On Sat, Apr 02, 2016 at 01:26:18PM -0700, Philip Guenther wrote:
> On Sat, Apr 2, 2016 at 12:44 PM, Philip Guenther <guent...@gmail.com> wrote:
> > On Sat, Apr 2, 2016 at 5:19 AM, Patrick Wildt <patr...@blueri.se> wrote:
> >> the Procedure Call Standard used in EABI requires the stack pointer to
> >> be 8-byte aligned by
> >>
> >>   * exception handlers, before calling AAPCS-conforming code.
> >>   * the OS, before giving control to an application.
> >>
> >> This diff makes sure our kernel interfaces adhere to that requirement.
> >>
> >> Can someone make sure this doesn't break armish/zaurus?
> >
> > The changes to cpu_switchto(), savectx(), and switchframe seem odd;
> > those are leaf functions, no?  When would their frame layouts result
> > in misaligned stacks for EABI-expecting code?
> 
> Ah, I now see where cpu_switchto() makes calls to C functions, so that
> part makes sense to me now.
> 
> 
> Philip Guenther
> 

Actually, it's a bit tricky.  savectx() actually does work with the SP,
even though it's not easily visible.  If we look in the !XSCALE case,
you can see it also stores r13, which is SP.  In the XSCALE case the
strd on r12 also stores r13.  This directly correlates with how
cpu_fork() and cpu_switchto() work.

What cpu_fork() does is create/fake two frames.  First a trapframe.
This trapframe is used to unwind using a PULLFRAME macro in
proc_trampoline().  The same macro, and the PUSHFRAME macro, is used on
kernel entry (e.g. interrupt).  It's reserved from a per-process kernel
stack pointer.  Then it sets up a switchframe.  This is used to unwind
out of cpu_switchto().  It's reserved directly after the trapframe.

        struct switchframe *sf;
        [..]
        pcb->pcb_un.un_32.pcb32_sp = (u_int)p2->p_addr + USPACE_SVC_STACK_TOP;
        p2->p_addr->u_pcb.pcb_tf = tf =
            (struct trapframe *)pcb->pcb_un.un_32.pcb32_sp - 1;
        [..]
        sf = (struct switchframe *)tf - 1;
        [..]
        sf->sf_pc = (u_int)proc_trampoline;
        pcb->pcb_un.un_32.pcb32_sp = (u_int)sf;

As we pad the trapframe and switchframe, pcb32_sp stays aligned.
This pcb32_sp is later on being used as a SP in cpu_switchto():

        /* Restore all the save registers */
        [..]
        ldmia   r7, {r8-r13}
        [..]

        /*
         * 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}

The start of cpu_switchto() saves the registers into a PCB struct,
exactly like savectx().

So this stuff essentially makes sure that the in-kernel stack is
correctly aligned, too.

Reply via email to