summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorandrew <andrew@FreeBSD.org>2013-03-06 06:19:56 +0000
committerandrew <andrew@FreeBSD.org>2013-03-06 06:19:56 +0000
commit1e16d8b6f0b524e7ca27ef6d5ceb4dedd8d1a061 (patch)
tree903980a964aad61cd9afba87e2f37f6d8ce5d880
parent684b694dcf968ef21f89f23aaba4ea102df252bc (diff)
downloadFreeBSD-src-1e16d8b6f0b524e7ca27ef6d5ceb4dedd8d1a061.zip
FreeBSD-src-1e16d8b6f0b524e7ca27ef6d5ceb4dedd8d1a061.tar.gz
Fix stack alignment in the kernel to be on an 8 byte boundary as required
by AAPCS.
-rw-r--r--sys/arm/arm/swtch.S5
-rw-r--r--sys/arm/arm/vm_machdep.c16
-rw-r--r--sys/arm/include/frame.h6
3 files changed, 24 insertions, 3 deletions
diff --git a/sys/arm/arm/swtch.S b/sys/arm/arm/swtch.S
index 4c422e8..4257557 100644
--- a/sys/arm/arm/swtch.S
+++ b/sys/arm/arm/swtch.S
@@ -211,10 +211,12 @@ ENTRY(cpu_throw)
GET_PCPU(r6)
str r7, [r6, #PC_CURPCB]
+ add sp, sp, #4;
ldmfd sp!, {r4-r7, pc}
ENTRY(cpu_switch)
stmfd sp!, {r4-r7, lr}
+ sub sp, sp, #4;
mov r6, r2 /* Save the mutex */
.Lswitch_resume:
@@ -488,6 +490,7 @@ ENTRY(cpu_switch)
* Pull the registers that got pushed when either savectx() or
* cpu_switch() was called and return.
*/
+ add sp, sp, #4;
ldmfd sp!, {r4-r7, pc}
#ifdef DIAGNOSTIC
.Lswitch_bogons:
@@ -501,6 +504,7 @@ ENTRY(cpu_switch)
#endif
ENTRY(savectx)
stmfd sp!, {r4-r7, lr}
+ sub sp, sp, #4
/*
* r0 = pcb
*/
@@ -528,6 +532,7 @@ ENTRY(savectx)
bl _C_LABEL(vfp_store)
1:
#endif /* ARM_VFP_SUPPORT */
+ add sp, sp, #4;
ldmfd sp!, {r4-r7, pc}
ENTRY(fork_trampoline)
diff --git a/sys/arm/arm/vm_machdep.c b/sys/arm/arm/vm_machdep.c
index 97b8b76..29a213f 100644
--- a/sys/arm/arm/vm_machdep.c
+++ b/sys/arm/arm/vm_machdep.c
@@ -73,6 +73,12 @@ __FBSDID("$FreeBSD$");
#include <machine/md_var.h>
+/*
+ * struct switchframe must be a multiple of 8 for correct stack alignment
+ */
+CTASSERT(sizeof(struct switchframe) == 24);
+CTASSERT(sizeof(struct trapframe) == 76);
+
#ifndef NSFBUFS
#define NSFBUFS (512 + maxusers * 16)
#endif
@@ -131,8 +137,8 @@ cpu_fork(register struct thread *td1, register struct proc *p2,
pcb2->un_32.pcb32_sp = td2->td_kstack +
USPACE_SVC_STACK_TOP - sizeof(*pcb2);
pmap_activate(td2);
- td2->td_frame = tf =
- (struct trapframe *)pcb2->un_32.pcb32_sp - 1;
+ td2->td_frame = tf = (struct trapframe *)STACKALIGN(
+ pcb2->un_32.pcb32_sp - sizeof(struct trapframe));
*tf = *td1->td_frame;
sf = (struct switchframe *)tf - 1;
sf->sf_r4 = (u_int)fork_return;
@@ -142,6 +148,8 @@ cpu_fork(register struct thread *td1, register struct proc *p2,
tf->tf_r0 = 0;
tf->tf_r1 = 0;
pcb2->un_32.pcb32_sp = (u_int)sf;
+ KASSERT((pcb2->un_32.pcb32_sp & 7) == 0,
+ ("cpu_fork: Incorrect stack alignment"));
/* Setup to release spin count in fork_exit(). */
td2->td_md.md_spinlock_count = 1;
@@ -345,6 +353,8 @@ cpu_set_upcall(struct thread *td, struct thread *td0)
tf->tf_r0 = 0;
td->td_pcb->un_32.pcb32_sp = (u_int)sf;
td->td_pcb->un_32.pcb32_und_sp = td->td_kstack + USPACE_UNDEF_STACK_TOP;
+ KASSERT((td->td_pcb->un_32.pcb32_sp & 7) == 0,
+ ("cpu_set_upcall: Incorrect stack alignment"));
/* Setup to release spin count in fork_exit(). */
td->td_md.md_spinlock_count = 1;
@@ -438,6 +448,8 @@ cpu_set_fork_handler(struct thread *td, void (*func)(void *), void *arg)
sf->sf_r4 = (u_int)func;
sf->sf_r5 = (u_int)arg;
td->td_pcb->un_32.pcb32_sp = (u_int)sf;
+ KASSERT((td->td_pcb->un_32.pcb32_sp & 7) == 0,
+ ("cpu_set_fork_handler: Incorrect stack alignment"));
}
/*
diff --git a/sys/arm/include/frame.h b/sys/arm/include/frame.h
index a24eccc..09ba55f 100644
--- a/sys/arm/include/frame.h
+++ b/sys/arm/include/frame.h
@@ -138,10 +138,14 @@ typedef struct irqframe {
} irqframe_t;
/*
- * Switch frame
+ * Switch frame.
+ *
+ * It is important this is a multiple of 8 bytes so the stack is correctly
+ * aligned when we create new threads.
*/
struct switchframe {
+ u_int pad; /* Used to pad the struct to a multiple of 8-bytes */
u_int sf_r4;
u_int sf_r5;
u_int sf_r6;
OpenPOWER on IntegriCloud