Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 23 Feb 2015 03:05:57 -0800
From:      Mark Millard <markmi@dsl-only.net>
To:        FreeBSD PowerPC ML <freebsd-ppc@freebsd.org>, Nathan Whitehorn <nwhitehorn@freebsd.org>
Subject:   Darwin ABI and its use of stw r0, 8(%r1) using callers %r1 value vs. ofwcall's code
Message-ID:  <D479F4B6-7352-4A35-8C55-389291268CC4@dsl-only.net>

next in thread | raw e-mail | index | archive | help
The compiled BootX code for calling openfirmawre for its _Peer use (as =
one of many examples) does %r1 related code that looks like the =
following. This code is here just for illustrating the Darwin ABI usage =
as it suggests what APple's openfirmware might be expected (or at be =
least allowed) to do itself when it is called, much liek when _Peer is =
called.

_Peer:
mfspr   r0,lr
... /* no use of %r1 until... */
stw     r0,0x8(r1) /* Note the 8(%r1) usage on the so far unchanged %r1 =
*/
stwu    r1,-0x90(r1) /* Here %r1 is finally changed */
... /* no %r1 changes */
addi    r3,r1,0x38
... /* no %r1 changes */
mtspr   ctr,r9
or      r12,r9,r9 /* %r9 referencing the openfirmware address to jump to =
*/
bctrl
... /* Just for completness, not essential to my point... */
lwz     r0,0x48(r1) /* the success case's return value extraction */
addi    r1,r1,0x90
or      r3,r0,r0
lwz     r0,0x8(r1)
mtspr   lr,r0
blr

The position 8(%r1) in the stw is based on the caller's %r1 value in =
this standard Darwin ABI calling sequence.


The following code from ofwcall64.S (-r277335 but the usage is not new) =
has used that same 8(%r1) position relative to the final value that it =
gives %r1 just before calling into openfirmware:


        /* Get OF stack pointer */
        ld      %r7,TOC_REF(ofwstk)(%r2)
        addi    %r7,%r7,OFWSTKSZ-32
...
        mr      %r1,%r7
        std     %r5,8(%r1)      /* Save real stack pointer */
... /* no %r1 changes */
        /* Finally, branch to OF */
        mtctr   %r4
        bctrl

At this point OF would be allowed to store the lr to 8(%r1) before it =
changes or records %r1 if it followed just the Darwin ABI, just like the =
code above does. That would replace the "std %r5,8(%r1)" value that was =
assigned in ofwcall64.S.

This may partially explain the corrupted %r1 that I've sometimes =
observed when openfirmware returns. (But see later notes.)

The only reason that this works as well as it does is that (G5 Quad-Core =
PowerMac) openfirmware protects itself before potentially executing any =
normal Darwin ABI code, including special code that in part records %r1 =
as it came from the caller (x/i notation):

    or      r2,r0,r2,
    addis   r2,r0,-x49
    ori     r2,r2,0xf000 /* so %r2:=3D0xFFB7F000 */
    std     r1,r2,0x8,   /* %r1 saved to have a special, separate copy =
*/
    std     r0,r2,0x10,
    mfspr   r0,lr
    std     r0,r2,0x120,
    mfmsr   r1
    std     r1,r2,0x108,

(Side comment: It would not be good to call the entry point recursively =
in any form.)

Openfirmware also carefully saves the 64-bit lr value and the 64-bit =
msr. My guess is that it has its own transition between potential 64 bit =
code and the 32 bit environment going in and for returning (usually?). =
It may even use the msr value to change behavior for being called form =
32-bit vs. 64-bit contexts to some degree.

Unfortunately I can not tell (yet?) if openfirmware always restores/uses =
what it saved for returning or not. It may be that it sometimes does and =
sometimes does not. So far I've identified only the save side of things.

Should the PowerMac code have this Darwin ABI conflict and depend on =
Apple's openfirmware having an extra non-ABI layer that translates back =
and forth from/to 64-bit environments? If it is to depend on such, then =
why appear to have a full transition to a 32 bit context before calling =
into openfirmware? (There easily could be evidence that Im not familiar =
with.)

It is even possible that openfirmware is detecting that it was not =
called from a 64 bit context and so is doing things that are =
inappropriate in response.



A different point for the relocatable powerpc64 kernel is that =
openfirmware might not tolerate the instruction after

        /* Finally, branch to OF */
        mtctr   %r4
        bctrl

being outside the 32 bit addressing range unless openfirmware always has =
a clean transition back to 64-bit calling contexts.

This could be a reason to either have a 64-bit calling context if it is =
supported or to disallow such a large relocation on PowerMac G5's.


Yet a different point is the BootX code use of %r12 (which follows the =
Darwin ABI):

mtspr   ctr,r9
or      r12,r9,r9 /* %r9 referencing the openfirmware address to jump to =
*/
bctrl

Every indirect call to openfirmware sets %r12 to the called address even =
when it is not necessary to the local jump code to the called routine =
and so only the called code would potentially use the %r12 value.

The wording I have for the description of Darwin ABI's rule is =
consistent with the caller possibly caring for some reason:

"... wherein a routine that branches indirectly to another routine must =
store the target of the call in GPR12. No special purpose for a routine =
that has been called directly." (Mac OS X Internals, Amit Singh). The =
code generated for BootX certainly is following that %r12-use rule when =
it calls openfirmware.

So for PowerMac's it may be that %r12 should be used instead of %r4 in =
teh following code.


        /* read client interface handler */
        ld      %r4,TOC_REF(openfirmware_entry)(%r2)
        ld      %r4,0(%r4)
...
        /* Finally, branch to OF */
        mtctr   %r4
        bctrl


=3D=3D=3D
Mark Millard
markmi at dsl-only.net




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?D479F4B6-7352-4A35-8C55-389291268CC4>