cortex-m3: 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 is the same implementation as for the Cortex-M4
This commit is contained in:
Joakim Gebart 2015-05-13 09:04:10 +02:00
parent eddd3177a5
commit 76a49bc3d2

View File

@ -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)