operating-system - Cortext-M3 上的任务切换在 IRQ 后崩溃

标签 operating-system arm interrupt cortex-m task-switching

我为我的 ARM Cortex-M3 操作系统使用了外内核模型。当任务想要从 UART 读取数据时,它会调用一个库函数,如果没有数据,该函数会调用 SVC 来阻止该任务(这会导致内核将该任务放入该 IRQ 的等待队列中,并启用该 IRQ) )。当中断发生时,所有等待它的任务都被移至可运行队列,并再次禁用中断。

当我有固定的任务数组时,这个模型工作得很好,但现在我已经转移到链接列表以允许更多类型的等待队列(例如 IPC 消息)。更改中的某些内容导致崩溃。这是调试输出:

Creating task 0 (idle task)
task0 stack top is 2007cd20
Starting SysTick @ 100Hz
Becoming task 0
Switching to task gsm@2007c008 with SP 2007c3e8
GSM task starting
Switching to task rfid@2007c430 with SP 2007c810
Monitoring RFID reader
Blocking task rfid on IRQ 7
Switching to task gps@2007c858 with SP 2007cc38
Switching to task task0@2007cc80 with SP 2007ccd8
Switching to task gsm@2007c008 with SP 2007c390
Blocking task gsm on IRQ 8
Switching to task gps@2007c858 with SP 2007cc38
Switching to task task0@2007cc80 with SP 2007ccd8
Switching to task gps@2007c858 with SP 2007cc38
Starting GPS tracking
Blocking task gps on IRQ 6
Switching to task task0@2007cc80 with SP 2007ccd8
[... repeats...]
Switching to task task0@2007cc80 with SP 2007ccd8
Unblocking tasks waiting on IRQ 8
Switching to task gsm@2007c008 with SP 2007c3a0
Switching to task task0@2007cc80 with SP 2007ccd8
Switching to task gsm@2007c008 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 %s@%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。

有什么建议吗?我应该在哪里寻找?

最佳答案

如何保存任务的处理器状态? 如果我没记错的话,切换时还需要保存 CPSR。 您可能需要将其更改为:

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

EPSR 将包含处理器条件标志和任何 IT block 状态信息等内容。

关于operating-system - Cortext-M3 上的任务切换在 IRQ 后崩溃,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20741462/

相关文章:

linux-kernel - request_irq() 在内部做什么?

embedded - system() 返回错误值

c - 编译 ARM 演示项目时出现链接器错误

c++ - ComputeLibrary CLTensor 数据传输

c - 试图了解 asm 中断,特别是 16h func 01H

c - 如何在 32 位中引发浮点错误

c - 在 Linux 的事件循环中使用 select() 系统调用

linux - 如果我使用ubuntu + Windows,如何从未分配的分区增加ubuntu中主目录的磁盘大小?

android - 中国Android设备杀死后台服务

c - 操作系统设计竞争条件