diff options
author | andrew <andrew@FreeBSD.org> | 2013-03-06 06:19:56 +0000 |
---|---|---|
committer | andrew <andrew@FreeBSD.org> | 2013-03-06 06:19:56 +0000 |
commit | 1e16d8b6f0b524e7ca27ef6d5ceb4dedd8d1a061 (patch) | |
tree | 903980a964aad61cd9afba87e2f37f6d8ce5d880 | |
parent | 684b694dcf968ef21f89f23aaba4ea102df252bc (diff) | |
download | FreeBSD-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.S | 5 | ||||
-rw-r--r-- | sys/arm/arm/vm_machdep.c | 16 | ||||
-rw-r--r-- | sys/arm/include/frame.h | 6 |
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; |