ARM v6 IRQ上下文切换

时间:2016-06-01 18:07:51

标签: c multithreading arm interrupt armv6

我正在尝试在定时器中断处理程序中编写上下文切换。目前,上下文切换能够在命令(协作)上的上下文之间切换。在中断处理程序中,我试图:

  1. 将当前程序计数器保存为旧线程需要继续执行的位置
  2. 切换到SVC模式以实际执行上下文切换
  3. 切换回IRQ模式并将链接寄存器从新线程更改为保存的PC
  4. 从IRQ处理程序返回到IRQ链接寄存器
  5. 我相信我可以正确地完成前两个,但我想知道:如何切换回中断模式,或者至少从中断处理程序修改SVC R13和R15?

    我正在使用ARM v6处理器;非常感谢你的帮助!

    编辑:这基本上就是我的开关:

    void interrupt_yield() {
        unsigned int old_mode; 
        __asm__("mrs %0, cpsr" : "=r" (old_mode));
        __asm__("msr cpsr_c, %0" : : "r" (MODE_SVC));
    
        PUSH_ALL; // Macro for push {r0-r12, lr} 
        __asm__("mov %0, sp" : "=r"(sp));
        manager->threads[manager->current_thread].sp = sp;
    
        unsigned nt = (manager->current_thread + 1) % manager->thread_counter;
        if (CURRENT_THREAD.status == ACTIVE) {
            CURRENT_THREAD.status = INACTIVE;
        }
        manager->current_thread = nt;
    
        CURRENT_THREAD.status = ACTIVE;
        SET_SP(CURRENT_THREAD.sp);
        POP_ALL;
    
        __asm__("msr cpsr, %0" : : "r" (old_mode));
    }
    
    
    void timer_vector() { // This is called by assembly in interrupt mode
        armtimer_clear_interrupt(); // clear timer interrupt
        interrupt_yield(); // Calls above function 
    }
    

    目标是更改IRQ链接寄存器以返回到新功能。但是,我似乎无法切换回中断模式。

    另外1次编辑:我从未真正切换IRQ链接寄存器;我意识到这一点,但我甚至没有切换回IRQ模式,所以这是一个后来修复的问题。

1 个答案:

答案 0 :(得分:1)

对于ARMv6,您需要更改模式以获取存储寄存器。您的示例代码已经包含许多必要的详细信息。

    #define MODE_IRQ 0x12
    #define MODE_SVC 0x13
    unsigned int mode;   /* original mode */

    /* target data... */
    unsigned int lr_irq;
    unsigned int sp_irq;
    unsigned int spsr;

    asm (" mrs %0, cpsr\n"    /* Save mode. */
         " msr cpsr_c,%4 \n"  /* to irq mode */
         " mov %1, lr\n"      /* Get lr_irq */
         " mov %2, sp\n"      /* Get sp_irq */
         " mrs %3, spsr\n"    /* Get spsr_irq */
         " msr cpsr, %0\n"    /* back to old mode */
         : "=&r" (mode), "=r"(lr_irq),
           "=r"(sp_irq), "=r"(spsr)
         : "I" (MODE_IRQ));

gcc会将lr_irq等分配给通用寄存器(非库存),您可以跨模式传输数据。具有虚拟化扩展的ARMv7具有避免此切换的指令。

您应该知道定时器中断可能在许多情况下发生。至少从IRQ模式检查 spsr 并进行一些调试(断言)验证它是用户模式可能是谨慎的。如果这永远不会触发,并且您认为IRQ只能在用户模式下发生,则可以删除“debug”。

另一种方法是在IRQ处理程序的汇编程序中执行此操作,并将它们传递给r0-r2中的interrupt_yield()例程。 ARM EABI将参数放在r0-r2中,因此中断产量需要参数。获得此数据后,无需返回IRQ模式。我强烈推荐这种方法用于生产代码。以上内容适用于原型设计。

相关:Explicitly accessing banked registers on ARM