2013-12-23 5 views
1

Я использовал модель exokernel для своей ОС ARM Cortex-M3. Когда задача хочет прочитать из UART, она вызывает библиотечную функцию, которая, если нет данных, вызывает вызов SVC для блокировки задачи (что заставляет ядро ​​поставить задачу в очередь ожидания для этого IRQ и разрешить IRQ). Когда прерывание происходит, все ожидающие его задачи перемещаются в очередь выполнения, и прерывание снова отключается.Запуск задачи при сбое Cortext-M3 после IRQ

Эта модель работала нормально, когда у меня был фиксированный массив задач, но теперь я перешел на связанные списки, чтобы разрешить больше типов очереди ожидания (например, сообщения IPC). Что-то в изменении вызывает крушение. Вот вывод отладки:

Creating task 0 (idle task) 
task0 stack top is 2007cd20 
Starting SysTick @ 100Hz 
Becoming task 0 
Switching to task [email protected] with SP 2007c3e8 
GSM task starting 
Switching to task [email protected] with SP 2007c810 
Monitoring RFID reader 
Blocking task rfid on IRQ 7 
Switching to task [email protected] with SP 2007cc38 
Switching to task [email protected] with SP 2007ccd8 
Switching to task [email protected] with SP 2007c390 
Blocking task gsm on IRQ 8 
Switching to task [email protected] with SP 2007cc38 
Switching to task [email protected] with SP 2007ccd8 
Switching to task [email protected] with SP 2007cc38 
Starting GPS tracking 
Blocking task gps on IRQ 6 
Switching to task [email protected] with SP 2007ccd8 
[... repeats...] 
Switching to task [email protected] with SP 2007ccd8 
Unblocking tasks waiting on IRQ 8 
Switching to task [email protected] with SP 2007c3a0 
Switching to task [email protected] with SP 2007ccd8 
Switching to task [email protected] with SP 2007c3a0 
Fault: Usage fault 
    r0 = 2007c3a0 
    r1 = 10007fb8 
    r2 = 2007ccd8 
    r3 = 10007fb8 
    r12 = 00000008 
    lr = fffffffd 
    pc = 0070c858 
    psr = 00000003 
BFAR = e000ed38 
CFSR = 00040000 
DFSR = 00000000 
AFSR = 00000000 
SHCSR = 00070008 

Так что все нормально до прерывания. Фактический выход изменяется в зависимости от того, какой UART имеет данные сначала, но шаблон тот же: когда происходит прерывание, возникает ошибка, когда разблокированная задача переключается на во второй раз.

Вот соответствующие биты кода. Узел прокладка:

zeptos_pendsv_isr: 
    push {lr} 
    mrs r0, psp 
    stmfd r0!, {r4-r11} 
    bl zeptos_schedule 
    ldmfd r0!, {r4-r11} 
    msr psp, r0 
    pop {pc} 

И функции C:

static void pendsv(void) { 
    SCB->ICSR |= 1 << 28; 
} 

void *zeptos_schedule(void *sp) { 
    if (current_task) { 
     current_task->sp = sp; 
     DL_APPEND(runnable_tasks, current_task); 
    } 
    current_task = runnable_tasks; 
    DL_DELETE(runnable_tasks, current_task); 
    zeptos_printf("Switching to task %[email protected]%p with SP %p\n", current_task->name, current_task, current_task->sp); 
    return current_task->sp; 
} 

static void block(void *sp, uint8_t irq) { 
    zeptos_printf("Blocking task %s on IRQ %i\n", current_task->name, irq); 
    current_task->sp = sp; 
    DL_APPEND(irq_blocked_tasks[irq], current_task); 
    current_task = 0; 
    NVIC_EnableIRQ(irq); 
    pendsv(); 
} 

void __attribute__((interrupt)) zeptos_isr(void) { 
    int irq = (SCB->ICSR & 0xff) - 16; 
    zeptos_printf("Unblocking tasks waiting on IRQ %i\n", irq); 
    NVIC_DisableIRQ(irq); 
    // NVIC_ClearPendingIRQ(irq); 
    DL_CONCAT(runnable_tasks, irq_blocked_tasks[irq]); 
    irq_blocked_tasks[irq] = 0; 
    pendsv(); 
} 

void __attribute__((interrupt)) zeptos_svc_isr(void) { 
    __disable_irq(); 
    uint32_t *sp = (uint32_t *) __get_PSP(); 
    uint32_t pc = sp[6]; 
    uint8_t svc_type = *((uint8_t *) pc - 2); 
    switch (svc_type) { 
     case 0: 
      sleep(sp[0]); 
      break; 

     case 1: 
      block(sp, sp[0]); 
      break; 

     default: 
      zeptos_puts("Bad SVC type\n"); 
    } 
    __enable_irq(); 
} 

void Zeptos_BlockOnIrq(uint8_t irq) { 
    asm("svc 1"); 
} 

SVC, SysTick и PendSV являются приоритетными 29, 30 и 31 соответственно.

Неисправность - это ошибка использования типа INVPC, что означает, что используется неправильный тип значения EXC_RETURN. Я проверил, и это 0xfffffffd каждый раз.

Любые предложения? Где я должен искать?

+1

В http://www.keil.com/appnotes/files/apnt209.pdf указано, что значение ПК, сложенное для возврата исключения, которое вы идентифицировали как 0x0070c858, указывает на инструкцию о нарушении. Не могли бы вы указать, что обучение нам с комментарием в вашем C-коде? '// <- 0x0070c858' в конце строки. Я подозреваю, что вы неправильно возвращаетесь из исключения, когда ваш «стек процесса» каким-то образом повреждается. – nonsensickle

ответ

0

Я нашел проблему, наконец. Когда мой обработчик SVC вызывает block, чтобы поставить задачу в заблокированный список, стек этой задачи имеет только регистры, уложенные аппаратным обеспечением, а не {r4-r11}, которые планировщик ожидает там, когда он запускает его позже.

Быстрое исправление заключается в том, что для SVC ISR выполняется сборка, которая складывает и блокирует дополнительные регистры, а функция C zeptos_svc_isr возвращает указатель стека, как это делает zeptos_schedule. Он работает, но некоторые рефакторинг в порядке.

0

Как хранится состояние процессора задачи? Если я правильно помню, вам нужно также сохранить CPSR, когда вы переключаетесь. Вы, возможно, придется сказать, изменить его:

mrs r12, epsr 
stmfd r0!, { r4 - r11, r12 } 
... 
ldmfd r0!, { r4 - r11, r12 } 
msr r12, epsr 

EPSR будет содержать такие вещи, как состояние процессора флагов и любой IT блокировать государственную информацию.

+0

Аппарат устанавливает PSR и {r0-r3, lr, pc} на PSP, как только происходит прерывание. – Derecho