From: arighi Date: Fri, 9 Apr 2010 15:30:46 +0000 (+0000) Subject: CM3: generic context switch implementation. X-Git-Tag: 2.5.0~497 X-Git-Url: https://codewiz.org/gitweb?a=commitdiff_plain;h=d9630fbb14997e3980bf0e4af4f0320a9bf69c12;p=bertos.git CM3: generic context switch implementation. git-svn-id: https://src.develer.com/svnoss/bertos/trunk@3411 38d2e660-2303-0410-9eaa-f027e97ec537 --- diff --git a/bertos/cpu/cortex-m3/hw/init_lm3s.c b/bertos/cpu/cortex-m3/hw/init_lm3s.c index d26f00b5..caac9d09 100644 --- a/bertos/cpu/cortex-m3/hw/init_lm3s.c +++ b/bertos/cpu/cortex-m3/hw/init_lm3s.c @@ -42,95 +42,15 @@ #include /* PAUSE */ #include /* IRQ_DISABLE */ #include -#include "drv/irq_lm3s.h" -#include "drv/clock_lm3s.h" -#include "io/lm3s.h" +#include +#include +#include +#include "switch_ctx_cm3.h" extern size_t __text_end, __data_start, __data_end, __bss_start, __bss_end; extern void __init2(void); -#if CONFIG_KERN_PREEMPT -/* - * Kernel preemption: implementation details. - * - * The kernel preemption is implemented using the PendSV IRQ. Inside the - * SysTick handler when a process needs to be interrupted (expires its time - * quantum or a high-priority process is awakend) a pending PendSV call is - * triggered. - * - * The PendSV handler is called immediately after the SysTick handler, using - * the architecture's tail-chaining functionality (an ISR call without the - * overhead of state saving and restoration between different IRQs). Inside the - * PendSV handler we perform the stack-switching between the old and new - * processes. - * - * Voluntary context switch is implemented as a soft-interrupt call (SVCall), - * so any process is always suspended and resumed from an interrupt context. - * - * NOTE: interrupts must be disabled or enabled when resuming a process context - * depending of the type of the previous suspension. If a process was suspended - * by a voluntary context switch IRQs must be disabled on resume (voluntary - * context switch always happen with IRQs disabled). Instead, if a process was - * suspended by the kernel preemption IRQs must be always re-enabled, because - * the PendSV handler resumes directly the process context. To keep track of - * this, we save the state of the IRQ priority in register r3 before performing - * the context switch. - * - * If CONFIG_KERN_PREEMPT is not enabled the cooperative implementation - * fallbacks to the default stack-switching mechanism, performed directly in - * thread-mode and implemented as a normal function call. - */ - -/* - * Voluntary context switch handler. - */ -static void NAKED svcall_handler(void) -{ - asm volatile ( - /* Save context */ - "mrs r3, basepri\n\t" - "mrs ip, psp\n\t" - "stmdb ip!, {r3-r11, lr}\n\t" - /* Stack switch */ - "str ip, [r1]\n\t" - "ldr ip, [r0]\n\t" - /* Restore context */ - "ldmia ip!, {r3-r11, lr}\n\t" - "msr psp, ip\n\t" - "msr basepri, r3\n\t" - "bx lr" : : : "memory"); -} - -/* - * Preemptible context switch handler. - */ -static void NAKED pendsv_handler(void) -{ - register cpu_stack_t *stack asm("ip"); - - asm volatile ( - "mrs r3, basepri\n\t" - "mov %0, %2\n\t" - "msr basepri, %0\n\t" - "mrs %0, psp\n\t" - "stmdb %0!, {r3-r11, lr}\n\t" - : "=r"(stack) - : "r"(stack), "i"(IRQ_PRIO_DISABLED) - : "r3", "memory"); - proc_current()->stack = stack; - proc_preempt(); - stack = proc_current()->stack; - asm volatile ( - "ldmia %0!, {r3-r11, lr}\n\t" - "msr psp, %0\n\t" - "msr basepri, r3\n\t" - "bx lr" - : "=r"(stack) : "r"(stack) - : "memory"); -} -#endif - /* Architecture's entry point */ void __init2(void) { diff --git a/bertos/cpu/cortex-m3/hw/switch_ctx_cm3.S b/bertos/cpu/cortex-m3/hw/switch_ctx_cm3.S deleted file mode 100644 index e464d613..00000000 --- a/bertos/cpu/cortex-m3/hw/switch_ctx_cm3.S +++ /dev/null @@ -1,58 +0,0 @@ -/** - * \file - * - * - * \brief Cortex-M3 context switch - * - * \author Andrea Righi - */ - -#include - -.syntax unified - -#if !CONFIG_KERN_PREEMPT -/* void asm_switch_context(void **new_sp [r0], void **save_sp [r1]) */ -.global asm_switch_context -.thumb_func -asm_switch_context: - mrs ip, psp - /* Save registers */ - stmdb ip!, {r4-r11, lr} - /* Save old stack pointer */ - str ip, [r1] - /* Load new stack pointer */ - ldr ip, [r0] - /* Load new registers */ - ldmia ip!, {r4-r11, lr} - msr psp, ip - bx lr -#endif /* CONFIG_KERN_PREEMPT */ diff --git a/bertos/cpu/cortex-m3/hw/switch_ctx_cm3.c b/bertos/cpu/cortex-m3/hw/switch_ctx_cm3.c new file mode 100644 index 00000000..7b36d902 --- /dev/null +++ b/bertos/cpu/cortex-m3/hw/switch_ctx_cm3.c @@ -0,0 +1,145 @@ +/** + * \file + * + * + * \brief Cortex-M3 context switch + * + * \author Andrea Righi + */ + +#include +#include /* CONFIG_KERN_PREEMPT */ +#include /* IRQ_PRIO_DISABLED */ +#include /* cpu_stack_t */ +#include /* asm_switch_context() prototype */ +#include /* proc_preempt() */ +#include "switch_ctx_cm3.h" + +#if CONFIG_KERN_PREEMPT +/* + * Kernel preemption: implementation details. + * + * The kernel preemption is implemented using the PendSV IRQ. Inside the + * SysTick handler when a process needs to be interrupted (expires its time + * quantum or a high-priority process is awakend) a pending PendSV call is + * triggered. + * + * The PendSV handler is called immediately after the SysTick handler, using + * the architecture's tail-chaining functionality (an ISR call without the + * overhead of state saving and restoration between different IRQs). Inside the + * PendSV handler we perform the stack-switching between the old and new + * processes. + * + * Voluntary context switch is implemented as a soft-interrupt call (SVCall), + * so any process is always suspended and resumed from an interrupt context. + * + * NOTE: interrupts must be disabled or enabled when resuming a process context + * depending of the type of the previous suspension. If a process was suspended + * by a voluntary context switch IRQs must be disabled on resume (voluntary + * context switch always happen with IRQs disabled). Instead, if a process was + * suspended by the kernel preemption IRQs must be always re-enabled, because + * the PendSV handler resumes directly the process context. To keep track of + * this, we save the state of the IRQ priority in register r3 before performing + * the context switch. + * + * If CONFIG_KERN_PREEMPT is not enabled the cooperative implementation + * fallbacks to the default stack-switching mechanism, performed directly in + * thread-mode and implemented as a normal function call. + */ + +/* + * Voluntary context switch handler. + */ +void NAKED svcall_handler(void) +{ + asm volatile ( + /* Save context */ + "mrs r3, basepri\n\t" + "mrs ip, psp\n\t" + "stmdb ip!, {r3-r11, lr}\n\t" + /* Stack switch */ + "str ip, [r1]\n\t" + "ldr ip, [r0]\n\t" + /* Restore context */ + "ldmia ip!, {r3-r11, lr}\n\t" + "msr psp, ip\n\t" + "msr basepri, r3\n\t" + "bx lr" : : : "memory"); +} + +/* + * Preemptible context switch handler. + */ +void NAKED pendsv_handler(void) +{ + register cpu_stack_t *stack asm("ip"); + + asm volatile ( + "mrs r3, basepri\n\t" + "mov %0, %2\n\t" + "msr basepri, %0\n\t" + "mrs %0, psp\n\t" + "stmdb %0!, {r3-r11, lr}\n\t" + : "=r"(stack) + : "r"(stack), "i"(IRQ_PRIO_DISABLED) + : "r3", "memory"); + proc_current()->stack = stack; + proc_preempt(); + stack = proc_current()->stack; + asm volatile ( + "ldmia %0!, {r3-r11, lr}\n\t" + "msr psp, %0\n\t" + "msr basepri, r3\n\t" + "bx lr" + : "=r"(stack) : "r"(stack) + : "memory"); +} +#else /* !CONFIG_KERN_PREEMPT */ +void NAKED asm_switch_context(cpu_stack_t **new_sp, cpu_stack_t **old_sp) +{ + register cpu_stack_t **_new_sp asm("r0") = new_sp; + register cpu_stack_t **_old_sp asm("r1") = old_sp; + + asm volatile ( + "mrs ip, psp\n\t" + /* Save registers */ + "stmdb ip!, {r4-r11, lr}\n\t" + /* Save old stack pointer */ + "str ip, [%1]\n\t" + /* Load new stack pointer */ + "ldr ip, [%0]\n\t" + /* Load new registers */ + "ldmia ip!, {r4-r11, lr}\n\t" + "msr psp, ip\n\t" + "bx lr" + : : "r"(_new_sp), "r"(_old_sp) : "ip", "memory"); +} +#endif /* CONFIG_KERN_PREEMPT */ diff --git a/examples/lm3s1968/lm3s1968.mk b/examples/lm3s1968/lm3s1968.mk index 42f40954..dbbea22b 100644 --- a/examples/lm3s1968/lm3s1968.mk +++ b/examples/lm3s1968/lm3s1968.mk @@ -46,11 +46,11 @@ lm3s1968_CSRC = \ bertos/cpu/cortex-m3/drv/clock_lm3s.c \ bertos/cpu/cortex-m3/drv/kdebug_lm3s.c \ bertos/cpu/cortex-m3/drv/ssi_lm3s.c \ + bertos/cpu/cortex-m3/hw/switch_ctx_cm3.c \ bertos/cpu/cortex-m3/hw/init_lm3s.c lm3s1968_CPPASRC = \ bertos/cpu/cortex-m3/hw/vectors_cm3.S \ - bertos/cpu/cortex-m3/hw/switch_ctx_cm3.S \ bertos/cpu/cortex-m3/hw/crt_cm3.S \ #