2013-12-23 32 views
1

我爲我的ARM Cortex-M3操作系統使用了exokernel模型。當一個任務想從UART讀取時,它會調用一個庫函數,如果沒有數據,它會進行SVC調用來阻塞任務(這會導致內核將該任務置於該IRQ的等待隊列中,並啓用IRQ )。當中斷髮生時,等待它的所有任務都被移動到可運行隊列,並且中斷再次被禁止。在IRQ後Cortext-M3上的任務切換崩潰

當我有一個固定的任務數組時,這個模型工作正常,但現在我已經移動到鏈表以允許更多類型的等待隊列(例如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,系統定時器和PendSV的分別是優先29,30和31。

故障是INVPC類型的使用故障,這意味着正在使用錯誤類型的EXC_RETURN值。我檢查過,每次都是0xfffffffd。

有什麼建議嗎?我應該在哪裏看?

+1

在http://www.keil.com/appnotes/files/apnt209.pdf中,它指出爲異常返回堆棧的PC值(您已標識爲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