diff --git a/cpu/cortex-m3_common/thread_arch.c b/cpu/cortex-m3_common/thread_arch.c index 7b777c7f51..241e914344 100644 --- a/cpu/cortex-m3_common/thread_arch.c +++ b/cpu/cortex-m3_common/thread_arch.c @@ -59,25 +59,50 @@ char *thread_arch_stack_init(thread_task_func_t task_func, void *arg, void *stac uint32_t *stk; stk = (uint32_t *)((uintptr_t)stack_start + stack_size); - /* marker */ - stk--; - *stk = (uint32_t)STACK_MARKER; + /* adjust to 32 bit boundary by clearing the last two bits in the address */ + stk = (uint32_t *)(((uint32_t)stk) & ~((uint32_t)0x3)); - /* FIXME xPSR */ + /* Stack start marker */ stk--; - *stk = (uint32_t)0x01000200; + *stk = STACK_MARKER; - /* program counter */ - stk--; - *stk = (uint32_t)task_func; + /* Make sure the stack is double word aligned (8 bytes) */ + /* This is required in order to conform with Procedure Call Standard for the + * ARMĀ® Architecture (AAPCS) */ + /* http://infocenter.arm.com/help/topic/com.arm.doc.ihi0042e/IHI0042E_aapcs.pdf */ + if (((uint32_t) stk % 8) != 0) { + /* add a single word padding */ + --stk; + *stk = ~((uint32_t)STACK_MARKER); + } - /* link register, jumped to when thread exits */ + /* ****************************** */ + /* Automatically popped registers */ + /* ****************************** */ + + /* The following eight stacked registers are popped by the hardware upon + * return from exception. (bx instruction in context_restore) */ + + /* xPSR */ stk--; - *stk = (uint32_t)sched_task_exit; + /* Setting bit 9 (0x200) of xPSR will cause the initial stack pointer for + * the process to be aligned on a 32-bit, non-64-bit, boundary. Don't do that. */ + /* Default xPSR, only the Thumb mode-bit is set */ + *stk = 0x01000000; + + /* pc */ + stk--; + /* initial program counter */ + *stk = (uint32_t) task_func; + + /* lr */ + stk--; + /* link register, return address when a thread exits. */ + *stk = (uint32_t) sched_task_exit; /* r12 */ stk--; - *stk = (uint32_t) 0; + *stk = 0; /* r1 - r3 */ for (int i = 3; i >= 1; i--) { @@ -85,9 +110,19 @@ char *thread_arch_stack_init(thread_task_func_t task_func, void *arg, void *stac *stk = i; } - /* r0 -> thread function parameter */ + /* r0 */ stk--; - *stk = (unsigned int) arg; + /* thread function parameter */ + *stk = (uint32_t) arg; + + /* 8 hardware-handled registers in total */ + + /* ************************* */ + /* Manually popped registers */ + /* ************************* */ + + /* The following registers are not handled by hardware in return from + * exception, but manually by context_restore. */ /* r11 - r4 */ for (int i = 11; i >= 4; i--) { @@ -95,11 +130,20 @@ char *thread_arch_stack_init(thread_task_func_t task_func, void *arg, void *stac *stk = i; } - /* put LR to trigger return to thread stack pointer */ + /* exception return code */ stk--; - *stk = (uint32_t)EXCEPT_RET_TASK_MODE; + *stk = EXCEPT_RET_TASK_MODE; /* return to task-mode process stack pointer */ + + /* 9 manually handled registers in total. */ + + /* The returned stack pointer will be aligned on a 32 bit boundary not on a + * 64 bit boundary because of the odd number of registers above (8+9). + * This is not a problem since the initial stack pointer upon process entry + * _will_ be 64 bit aligned (because of the cleared bit 9 in the stacked + * xPSR and aligned stacking of the hardware-handled registers). */ return (char*) stk; + } void thread_arch_stack_print(void)