Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cortex-M: initial stack alignment #2976

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 57 additions & 13 deletions cpu/cortex-m3_common/thread_arch.c
Original file line number Diff line number Diff line change
Expand Up @@ -59,47 +59,91 @@ 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 */
/* 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 = (uint32_t)STACK_MARKER;
*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);
}

/* ****************************** */
/* Automatically popped registers */
/* ****************************** */

/* FIXME xPSR */
/* The following eight stacked registers are popped by the hardware upon
* return from exception. (bx instruction in context_restore) */

/* xPSR */
stk--;
*stk = (uint32_t)0x01000200;
/* 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;

/* program counter */
/* pc */
stk--;
*stk = (uint32_t)task_func;
/* initial program counter */
*stk = (uint32_t) task_func;

/* link register, jumped to when thread exits */
/* lr */
stk--;
*stk = (uint32_t)sched_task_exit;
/* 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--) {
stk--;
*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--) {
stk--;
*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)
Expand Down
63 changes: 53 additions & 10 deletions cpu/cortex-m4_common/thread_arch.c
Original file line number Diff line number Diff line change
Expand Up @@ -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):
* ------------------------------------------------------------------------------------------------------------------------------------
Expand All @@ -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--;
Expand All @@ -83,41 +96,71 @@ char *thread_arch_stack_init(thread_task_func_t task_func,
}
*/

/* FIXME xPSR */
/* ****************************** */
/* 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) 0x01000200;
/* 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;

/* program counter */
/* 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--) {
stk--;
*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;
}
Expand Down