diff --git a/sys/arm/arm/swtch.S b/sys/arm/arm/swtch.S index 4c422e86b517..4257557d1c5e 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 97b8b76cf79f..29a213fe1611 100644 --- a/sys/arm/arm/vm_machdep.c +++ b/sys/arm/arm/vm_machdep.c @@ -73,6 +73,12 @@ __FBSDID("$FreeBSD$"); #include +/* + * 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 a24eccce0225..09ba55f15cf2 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;