summaryrefslogtreecommitdiffstats
path: root/sys/arm/include
diff options
context:
space:
mode:
authorandrew <andrew@FreeBSD.org>2013-08-05 19:06:28 +0000
committerandrew <andrew@FreeBSD.org>2013-08-05 19:06:28 +0000
commit1e070fe985d3b60b77ddd6155a70b5b2354ae123 (patch)
tree8dffe52db187e203919e583c9eb5259a31828b45 /sys/arm/include
parentb8fe5eca7f69369d0faabdfa7ab217dab06183d5 (diff)
downloadFreeBSD-src-1e070fe985d3b60b77ddd6155a70b5b2354ae123.zip
FreeBSD-src-1e070fe985d3b60b77ddd6155a70b5b2354ae123.tar.gz
When entering exception handlers we may not have an aligned stack. This is
because an exception may happen at any time. The stack alignment rules on ARM EABI state the only place the stack must be 8-byte aligned is on a function boundary. If an exception happens while a function is setting up or tearing down it's stack frame it may not be correctly aligned. There is also no requirement for it to be when the function is a leaf node. The fix is to align the stack after we have stored a backup of the old stack pointer, but before we have stored anything in the trapframe. Along with this we need to adjust the size of the trapframe by 4 bytes to ensure the stack below it is also correctly aligned.
Diffstat (limited to 'sys/arm/include')
-rw-r--r--sys/arm/include/asmacros.h13
-rw-r--r--sys/arm/include/frame.h5
2 files changed, 14 insertions, 4 deletions
diff --git a/sys/arm/include/asmacros.h b/sys/arm/include/asmacros.h
index 18dcef5..0c107a4 100644
--- a/sys/arm/include/asmacros.h
+++ b/sys/arm/include/asmacros.h
@@ -63,6 +63,7 @@
*/
#ifdef ARM_TP_ADDRESS
#define PUSHFRAME \
+ sub sp, sp, #4; /* Align the stack */ \
str lr, [sp, #-4]!; /* Push the return address */ \
sub sp, sp, #(4*17); /* Adjust the stack pointer */ \
stmia sp, {r0-r12}; /* Push the user mode registers */ \
@@ -78,6 +79,7 @@
str r1, [r0, #4];
#else
#define PUSHFRAME \
+ sub sp, sp, #4; /* Align the stack */ \
str lr, [sp, #-4]!; /* Push the return address */ \
sub sp, sp, #(4*17); /* Adjust the stack pointer */ \
stmia sp, {r0-r12}; /* Push the user mode registers */ \
@@ -100,7 +102,8 @@
ldmia sp, {r0-r14}^; /* Restore registers (usr mode) */ \
mov r0, r0; /* NOP for previous instruction */ \
add sp, sp, #(4*17); /* Adjust the stack pointer */ \
- ldr lr, [sp], #0x0004; /* Pull the return address */
+ ldr lr, [sp], #0x0004; /* Pull the return address */ \
+ add sp, sp, #4 /* Align the stack */
#else
#define PULLFRAME \
ldr r0, [sp], #0x0004; /* Get the SPSR from stack */ \
@@ -109,7 +112,8 @@
ldmia sp, {r0-r14}^; /* Restore registers (usr mode) */ \
mov r0, r0; /* NOP for previous instruction */ \
add sp, sp, #(4*17); /* Adjust the stack pointer */ \
- ldr lr, [sp], #0x0004; /* Pull the return address */
+ ldr lr, [sp], #0x0004; /* Pull the return address */ \
+ add sp, sp, #4 /* Align the stack */
#endif
/*
@@ -133,6 +137,8 @@
orr r2, r2, #(PSR_SVC32_MODE); \
msr cpsr_c, r2; /* Punch into SVC mode */ \
mov r2, sp; /* Save SVC sp */ \
+ bic sp, sp, #7; /* Align sp to an 8-byte addrress */ \
+ sub sp, sp, #4; /* Pad trapframe to keep alignment */ \
str r0, [sp, #-4]!; /* Push return address */ \
str lr, [sp, #-4]!; /* Push SVC lr */ \
str r2, [sp, #-4]!; /* Push SVC sp */ \
@@ -168,6 +174,8 @@
orr r2, r2, #(PSR_SVC32_MODE); \
msr cpsr_c, r2; /* Punch into SVC mode */ \
mov r2, sp; /* Save SVC sp */ \
+ bic sp, sp, #7; /* Align sp to an 8-byte addrress */ \
+ sub sp, sp, #4; /* Pad trapframe to keep alignment */ \
str r0, [sp, #-4]!; /* Push return address */ \
str lr, [sp, #-4]!; /* Push SVC lr */ \
str r2, [sp, #-4]!; /* Push SVC sp */ \
@@ -209,6 +217,7 @@
#endif
#if defined(__ARM_EABI__)
#define UNWINDSVCFRAME \
+ .pad #(4); /* Skip stack alignment */ \
.save {r13-r15}; /* Restore sp, lr, pc */ \
.pad #(2*4); /* Skip user sp and lr */ \
.save {r0-r12}; /* Restore r0-r12 */ \
diff --git a/sys/arm/include/frame.h b/sys/arm/include/frame.h
index 09ba55f..cd6a897 100644
--- a/sys/arm/include/frame.h
+++ b/sys/arm/include/frame.h
@@ -62,7 +62,7 @@
typedef struct trapframe {
register_t tf_spsr; /* Zero on arm26 */
register_t tf_r0;
- register_t tf_r1;
+ register_t tf_r1;
register_t tf_r2;
register_t tf_r3;
register_t tf_r4;
@@ -78,7 +78,8 @@ typedef struct trapframe {
register_t tf_usr_lr;
register_t tf_svc_sp; /* Not used on arm26 */
register_t tf_svc_lr; /* Not used on arm26 */
- register_t tf_pc;
+ register_t tf_pc;
+ register_t tf_pad;
} trapframe_t;
/* Register numbers */
OpenPOWER on IntegriCloud