/** * \file * * * \brief ARM context switch * * * \author Stefano Fedrigo * \author Francesco Sacchi * \author Andrea Righi */ #include "cfg/cfg_proc.h" /* void asm_switch_context(void **new_sp [r0], void **save_sp [r1]) */ .globl asm_switch_context asm_switch_context: /* Save registers */ stmfd sp!, {r4 - r11, lr} /* Save old stack pointer */ str sp, [r1] /* Load new stack pointer */ ldr sp, [r0] /* Load new registers */ ldmfd sp!, {r4 - r11, pc} #if CONFIG_KERN_PREEMPT /* ARM interrupt mode with IRQ and FIQ disabled */ #define ARM_IRQ_MODE 0xD2 /* ARM supervisor mode with IRQ and FIQ disabled */ #define ARM_SVC_MODE 0xD3 .globl asm_irq_switch_context asm_irq_switch_context: /* Return if preemption is not needed */ bl proc_needPreempt cmp r0, #0 ldmeqfd sp!, {r0 - r3, ip, pc}^ /* Otherwise restore regs used by the ISR */ ldmfd sp!, {r0 - r3, ip, lr} /* Save current process context */ msr cpsr_c, #ARM_SVC_MODE stmfd sp!, {r0 - r3, ip, lr} /* Save lr_irq and spsr_irq in process stack */ msr cpsr_c, #ARM_IRQ_MODE mov r0, lr mrs r1, spsr msr cpsr_c, #ARM_SVC_MODE stmfd sp!, {r0, r1} /* Perform the context switch */ bl proc_preempt /* Restore lr_irq and spsr_irq from process stack */ ldmfd sp!, {r0, r1} msr cpsr_c, #ARM_IRQ_MODE mov lr, r0 msr spsr_cxsf, r1 /* Restore process regs */ msr cpsr_c, #ARM_SVC_MODE ldmfd sp!, {r0 - r3, ip, lr} /* Exit from ISR */ msr cpsr_c, #ARM_IRQ_MODE movs pc, lr #endif /* CONFIG_KERN_PREEMPT */