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>