Date: Mon, 20 Oct 2014 01:50:00 -0700 From: Mark Millard <markmi@dsl-only.net> To: Nathan Whitehorn <nwhitehorn@freebsd.org> Cc: Justin Hibbits <chmeeedalf@gmail.com>, FreeBSD PowerPC ML <freebsd-ppc@freebsd.org> Subject: Re: My PowerMac G5's no longer crash at boot: PowerMac G5 specific ofwcall changes with justifying evidence [Darwin 32-bit ABI violation] Message-ID: <96B5F27E-E7CE-4962-906E-F8A9DD3F7DDE@dsl-only.net> In-Reply-To: <C2D6BBD9-3E03-464B-8398-5361DAAC4836@dsl-only.net> References: <76F704FD-BB74-4439-8318-DB4C167B420F@dsl-only.net> <543B3828.8070806@freebsd.org> <9D9B0372-8D8F-4153-85B5-40066206EF67@dsl-only.net> <379AA7FC-98C9-48B9-92BB-60E134817AF1@dsl-only.net> <C614025F-6455-4929-8468-462E76079274@dsl-only.net> <A2AB9066-259B-4B7D-BDDC-D03AE5827E13@dsl-only.net> <CAHSQbTCKi_MBhERh6d=kX2y-=%2B2OzqpGM%2BN=ZEShi-kX2r8NPQ@mail.gmail.com> <543D5ACD.20901@freebsd.org> <3D4A76B3-431A-4C94-8747-70369A8A1764@dsl-only.net> <0F85ACBD-F6D6-4ABA-B8FA-00C586A086DE@dsl-only.net> <EE3EC252-DC9E-4F95-977C-FAF9F364CA92@dsl-only.net> <49920E63-CB4A-429C-AB3A-984075AE183D@dsl-only.net> <0CEC8978-E208-4F57-8481-DD9C321EF673@dsl-only.net> <0EAE6493-FF6B-4F90-8C7B-F32A62DBD6B7@dsl-only.net> <C2D6BBD9-3E03-464B-8398-5361DAAC4836@dsl-only.net>
next in thread | previous in thread | raw e-mail | index | archive | help
I started to look into the powerpc/GENERIC (32 bit) PowerMac = requirements and what they imply for ofwcall since I intend on adding = the %r1 and %r3 validation code. But I discovered that the ofwcall64.S code is not really 32-bit Darwin = PowerPC ABI compliant. I am using Mac OS X Internals, A Systems Approach, by Amit Singh for = documentation of the Apple PowerPC 32 bit Darwin ABI. Technically it = documents just the Darwin/Mac OS X 32 bit PowerPC ABI. I'm not aware of = anything that explicitly says that openfirmware on PowerMac's is an = exact match. But I'd expect a match. (I also looked at The PowerPC = Compiler Writer's Guide, although it is not Apple specific.) The below is based on Internals book's material starting from the page = labeled 231 and using the diagram on the page labeled 232 and 235 = mostly. The page labeled 233 says: "A 32-bit Darwin ABI stack frame is 16-byte = aligned." I've choose to present a simple/non-optimized translation of what the = 32-bit Darwin PowerPC ABI would imply, translated into simple code that = conceptually might go in ofwcall. But Commented Code indicating the ABI = points. I must also note that the material is based strictly on the 32-bit = Darwin PowerPC ABI involved and what it allows/requires --and not on any = extra knowledge of what openfirmware really does that may make some = points irrelevant. And ofwcall's fake Darwin ABI frame is presented rather fully in its = details because openfirmware (the to-be-called routine) can use some of = that space. [Side note: it appears that any exceptions/interrupts that might use the = same stack must avoid a 224 (220?) byte "red zone" area above %r1 = because some leaf functions are allowed to use it without forming a = activation frame (well, 220 bytes but with 16-byte alignment pad making = it 224). AIX would have that be 220 --as far as I can tell because it = does not have the same 16-byte alignment rule.] .data .align 16 /* 32-bit Darwin PowerPC ABI requires 16-byte = (quad-word) stack frame alignment */. ofwstk: .space OFWSTKSZ /* Should keep to 16-byte multiples */ .align 4 /* back to normal */ ... mr %r18,%r1 lis %r1,(ofwstk+OFWSTKSZ-112)@ha=20 addi %r1,%r1,(ofwstk+OFWSTKSZ-112)@l /* Needs to produce a = 16-byte (quad-word) aligned %r1 value */ /* with room for the = following... */ /* These are not from the 32-bit Darwin PowerPC ABI: They are = after the fake ofwcall ABI frame. */ /* %r1+80 is also 16-byte aligned. */ std %r18,80+0(%r1) /* Save FreeBSD stack pointer */ std %r2,80+8(%r1) /* Save FreeBSD TOC */ std %r14,80+16(%r1) /* Save FreeBSD MSR */ /* Bytes at/after %r1+80+24 not used. The above are not from the = 32-bit Darwin ABI. */ /* The 32-bit Darwin PowerPC ABI ofwcall stack structure = follows: */ addi %r19,%r1,80 stw %r19,0(%r1) /* backchain (non-negative offsets from = there are junk here * relative to the 32-bit Darwin PowerPC = ABI but negative=20 * offsets from there can be okay if = small enough to be=20 * in ofwstk from %r1 to = ofwstk+OFWSTKSZ-112+79 inclusive) */ li %r19,0 stw %r19,4(%r1) /* space for openfirmware (the = to-be-called routine) to store CR */ stw %r19,8(%r1) /* space for openfirmware (the = to-be-called routine) to store LR */ stw %r19,12(%r1) /* Darwin linkage reserved space */ stw %r19,16(%r1) /* more Darwin linkage reserved space */ stw %r19,20(%r1) /* space for TOC (despite 32-bit Darwin = ABI not using TOC: it has the space) */ /* End of 24 byte linkage area */ /* Empty local stack area. If non-empty: 16-bit aligned? Prefix = padding shown in book that produces such alignment. */ /* Parameter area required because a function (openfirmware) is = called. Must be double word aligned. */ stw %r19,24(%r1) /* Parameter area with the only = argument's slot: space reserved despite register argument usage */ stw %r19,28(%r1) /* Parameter area is at least 8 words = and the space is reserved despite register argument usage */ stw %r19,32(%r1) /* Parameter area is at least 8 words = and the space is reserved despite register argument usage */ stw %r19,36(%r1) /* Parameter area is at least 8 words = and the space is reserved despite register argument usage */ stw %r19,40(%r1) /* Parameter area is at least 8 words = and the space is reserved despite register argument usage */ stw %r19,44(%r1) /* Parameter area is at least 8 words = and the space is reserved despite register argument usage */ stw %r19,48(%r1) /* Parameter area is at least 8 words = and the space is reserved despite register argument usage */ stw %r19,52(%r1) /* Parameter area is at least 8 words = and the space is reserved despite register argument usage */ /* NOTE: openfirmware (the to-be-called routine) is allowed to = use the above parameter area!=20 * This is true of the 32-bit Darwin PowerPC ABI despite = register argument passing! * Typical use is to temporarily free up a register. */ /* End of 32 byte parameter area */ stw %r19,56(%r1) /* padding to have 16 byte stack = alignment */ stw %r19,60(%r1) /* padding to have 16 byte stack = alignment */ /* End of 8-byte sized padding to cause 16-byte alignment */ /* GPR save area: 8-byte prefix padding to force = 16-byte-multiple for size(?) is shown in figures. */ stw %r19,64(%r1) /* padding to have 16 byte size for GPR = area */ stw %r19,68(%r1) /* padding to have 16 byte size for GRP = area */ stw %r19,72(%r1) /* %r30 always stored for GPR = save/restore (fake value here) */ stw %r19,76(%r1) /* %r31 always stored for GPR = save/restore (fake value here) */ /* End of 16-byte GRP save area */ /* Empty FPR save area but must be double word aligned */ /* +80 is again 16-byte aligned. The FreeBSD extras are not part = of the 32-bit Darwin ABI. */ Note: %r30 is used as the frame pointer register. %r31 as the PIC-offset = table register. Now compare that to the existing sort of code (but with the %r14, %r18, = and %r19 usage to match the above): .data .align 4 ofwstk: .space OFWSTKSZ ... mr %r18,%r1 lis %r1,(ofwstk+OFWSTKSZ-32)@ha addi %r1,%r1,(ofwstk+OFWSTKSZ-32)@l std %r18,8(%r1) /* Save FreeBSD stack pointer */ std %r2,16(%r1) /* Save FreeBSD TOC */ std %r14,24(%r1) /* Save FreeBSD MSR */ li %r19,0 stw %r19,4(%r1) stw %r19,0(%r1) So what I get from the comparison is that: std %r18,8(%r1) (FreeBSD stack pointer) is using space that openfirmware is allowed to put the LR in and also = some reserved space. std %r2,16(%r1) (FreeBSD TOC) is using reserved space and the TOC space from the Darwin ABI. std %r14,24(%r1) (FreeBSD MSR) is using the parameter space that openfirmware is allowed to put to = other uses. These risk openfirmware replacing part of the FreeBSD stack pointer and = the FreeBSD MSR. Also: stw %r19,4(%r1) stw %r19,0(%r1) only covers the backchain and space where openfirmware could put CR = values. It does not span where openfirmware could put LR values or the = parmeter area that openfirmware is allowed to use. As an example of the parameter area criteria and the size of the stack = frame from the book: the pages labeled 234-235 has f3() that calls g(); = (no arguments). For this it says... "f3 calls a function that takes no arguments. Nevertheless, this = introduces a parameter area on f3's stack. A parameter area is at least = 8 words (32 bytes) in size. f3's stack is 80 bytes." Of course openfirmware does take a 32-pointer as an argument but the 8 = words covers that and the stack frame size does not change compared to = the book's f3 example. And, of course, the three 64-bit values stored in ofwstk below all this = are in addition to the above. Quoting various statements about the "Parameter area" (for function f1 = calling f2): 0) "The Parameter area must be large enough to hold the largest = parameter list of all the functions that f1 calls." (Material about passing arguments in registers. Then...)=20 1) "However f1 must reserve space for all arguments of f2 in any case = --even if it is able to pass all arguments in registers. f2 is free to = use f1's parameter area for storing arguments if it wants to free up the = corresponding registers for other use. Thus, in a subroutine call, the = caller sets up a parameter area in its own stack portion, and the callee = can access the caller's parameter area for loading or storing = arguments." =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?96B5F27E-E7CE-4962-906E-F8A9DD3F7DDE>