BeRTOS
|
00001 00038 #include <cfg/compiler.h> 00039 #include <cfg/cfg_proc.h> /* CONFIG_KERN_PREEMPT */ 00040 #include <cpu/irq.h> /* IRQ_PRIO_DISABLED */ 00041 #include <cpu/types.h> /* cpu_stack_t */ 00042 #include <kern/proc_p.h> /* asm_switch_context() prototype */ 00043 #include <kern/proc.h> /* proc_preempt() */ 00044 #include "switch_ctx_cm3.h" 00045 00046 #if CONFIG_KERN_PREEMPT 00047 /* 00048 * Kernel preemption: implementation details. 00049 * 00050 * The kernel preemption is implemented using the PendSV IRQ. Inside the 00051 * SysTick handler when a process needs to be interrupted (expires its time 00052 * quantum or a high-priority process is awakend) a pending PendSV call is 00053 * triggered. 00054 * 00055 * The PendSV handler is called immediately after the SysTick handler, using 00056 * the architecture's tail-chaining functionality (an ISR call without the 00057 * overhead of state saving and restoration between different IRQs). Inside the 00058 * PendSV handler we perform the stack-switching between the old and new 00059 * processes. 00060 * 00061 * Voluntary context switch is implemented as a soft-interrupt call (SVCall), 00062 * so any process is always suspended and resumed from an interrupt context. 00063 * 00064 * NOTE: interrupts must be disabled or enabled when resuming a process context 00065 * depending of the type of the previous suspension. If a process was suspended 00066 * by a voluntary context switch IRQs must be disabled on resume (voluntary 00067 * context switch always happen with IRQs disabled). Instead, if a process was 00068 * suspended by the kernel preemption IRQs must be always re-enabled, because 00069 * the PendSV handler resumes directly the process context. To keep track of 00070 * this, we save the state of the IRQ priority in register r3 before performing 00071 * the context switch. 00072 * 00073 * If CONFIG_KERN_PREEMPT is not enabled the cooperative implementation 00074 * fallbacks to the default stack-switching mechanism, performed directly in 00075 * thread-mode and implemented as a normal function call. 00076 */ 00077 00078 /* 00079 * Voluntary context switch handler. 00080 */ 00081 void NAKED svcall_handler(void) 00082 { 00083 asm volatile ( 00084 /* Save context */ 00085 "mrs r3, basepri\n\t" 00086 "mrs ip, psp\n\t" 00087 "stmdb ip!, {r3-r11, lr}\n\t" 00088 /* Stack switch */ 00089 "str ip, [r1]\n\t" 00090 "ldr ip, [r0]\n\t" 00091 /* Restore context */ 00092 "ldmia ip!, {r3-r11, lr}\n\t" 00093 "msr psp, ip\n\t" 00094 "msr basepri, r3\n\t" 00095 "bx lr" : : : "memory"); 00096 } 00097 00098 /* 00099 * Preemptible context switch handler. 00100 */ 00101 void NAKED pendsv_handler(void) 00102 { 00103 register cpu_stack_t *stack asm("ip"); 00104 00105 asm volatile ( 00106 "mrs r3, basepri\n\t" 00107 "mov %0, %2\n\t" 00108 "msr basepri, %0\n\t" 00109 "mrs %0, psp\n\t" 00110 "stmdb %0!, {r3-r11, lr}\n\t" 00111 : "=r"(stack) 00112 : "r"(stack), "i"(IRQ_PRIO_DISABLED) 00113 : "r3", "memory"); 00114 proc_current()->stack = stack; 00115 proc_preempt(); 00116 stack = proc_current()->stack; 00117 asm volatile ( 00118 "ldmia %0!, {r3-r11, lr}\n\t" 00119 "msr psp, %0\n\t" 00120 "msr basepri, r3\n\t" 00121 "bx lr" 00122 : "=r"(stack) : "r"(stack) 00123 : "memory"); 00124 } 00125 #else /* !CONFIG_KERN_PREEMPT */ 00126 #ifdef __IAR_SYSTEMS_ICC__ 00127 #else /* __IAR_SYSTEMS_ICC__ */ 00128 void NAKED asm_switch_context(cpu_stack_t **new_sp, cpu_stack_t **old_sp) 00129 { 00130 register cpu_stack_t **_new_sp asm("r0") = new_sp; 00131 register cpu_stack_t **_old_sp asm("r1") = old_sp; 00132 00133 asm volatile ( 00134 "mrs ip, psp\n\t" 00135 /* Save registers */ 00136 "stmdb ip!, {r4-r11, lr}\n\t" 00137 /* Save old stack pointer */ 00138 "str ip, [%1]\n\t" 00139 /* Load new stack pointer */ 00140 "ldr ip, [%0]\n\t" 00141 /* Load new registers */ 00142 "ldmia ip!, {r4-r11, lr}\n\t" 00143 "msr psp, ip\n\t" 00144 "bx lr" 00145 : : "r"(_new_sp), "r"(_old_sp) : "ip", "memory"); 00146 } 00147 #endif /* __IAR_SYSTEMS_ICC__ */ 00148 #endif /* CONFIG_KERN_PREEMPT */