1
0
mirror of https://github.com/RIOT-OS/RIOT.git synced 2025-01-18 12:52:44 +01:00

cortex-m4: Align initial stack pointer to 64 bits

AAPCS requires stack pointers to be aligned on a double word boundary.

In addition, Clang-3.6 assumes the stack pointer is always aligned to
a 8 byte boundary upon function entry, at least in armv7-m, causing
hard-to-find errors in the compiled code.
This commit is contained in:
Joakim Gebart 2015-05-13 09:04:10 +02:00
parent 21dc560a19
commit eddd3177a5

View File

@ -44,7 +44,7 @@
/**
* Cortex-M knows stacks and handles register backups, so use different stack frame layout
*
* TODO: How to handle different Cortex-Ms? Code is so far valid for M3 and M4 without FPU
* \todo Cortex-M thread_arch_stack_init: How to handle different Cortex-Ms? Code is so far valid for M3 and M4 without FPU
*
* Layout with storage of floating point registers (applicable for Cortex-M4):
* ------------------------------------------------------------------------------------------------------------------------------------
@ -65,10 +65,23 @@ char *thread_arch_stack_init(thread_task_func_t task_func,
uint32_t *stk;
stk = (uint32_t *)((uintptr_t)stack_start + stack_size);
/* marker */
/* adjust to 32 bit boundary by clearing the last two bits in the address */
stk = (uint32_t *)(((uint32_t)stk) & ~((uint32_t)0x3));
/* Stack start marker */
stk--;
*stk = STACK_MARKER;
/* 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);
}
/* TODO: fix FPU handling for Cortex-M4 */
/*
stk--;
@ -83,21 +96,33 @@ char *thread_arch_stack_init(thread_task_func_t task_func,
}
*/
/* FIXME xPSR */
stk--;
*stk = (uint32_t) 0x01000200;
/* ****************************** */
/* Automatically popped registers */
/* ****************************** */
/* program counter */
/* The following eight stacked registers are popped by the hardware upon
* return from exception. (bx instruction in context_restore) */
/* xPSR */
stk--;
/* 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;
/* link register, jumped to when thread exits */
/* 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--) {
@ -105,19 +130,37 @@ char *thread_arch_stack_init(thread_task_func_t task_func,
*stk = i;
}
/* r0 -> thread function parameter */
/* r0 */
stk--;
/* 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--) {
stk--;
*stk = i;
}
/* lr means exception return code */
/* exception return code */
stk--;
*stk = EXCEPT_RET_TASK_MODE; /* return to task-mode main stack pointer */
*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;
}