Files
rebbarb/gc_bba_test/source/netboot_stub.S
T
Roflin 4fd337fb24 Fix the netboot launcher: relocate the copier, reserve the staging region
The launcher committed in b438960 would have hung the console, and reviewing
it against Dennis's suggestion to test with Swiss's boot.dol is what surfaced
it -- Swiss is known-good, so a hang could only have been the launcher, but I
would not have been able to tell that from "the transfer is broken".

Two distinct defects, both from the same oversight -- a DOL's sections load
from 0x80003100 upward, which is exactly where this program is running:

1. The copier was an ordinary C function in .text, so it overwrote its OWN
   instructions partway through the copy.
2. The image was staged in a memalign'd buffer, which the destination sections
   can overwrite while it is still being read from.

Fixes:
  - netboot_stub.S: the copy/zero/cache-flush/jump sequence in position
    independent assembly, copied into reserved memory and executed THERE.  It
    has no globals, no literal pool, no TOC references and no calls, because
    any of those would read from the address it was LINKED at rather than the
    one it is RUNNING at.  It also does the dcbf/icbi pass the C version was
    doing through DCFlushRange -- without it the CPU executes stale icache
    lines at the entry point.
  - netboot_reserve(): carves the top of MEM1 and hands it to
    SYS_SetArena1Hi() so neither libogc nor malloc allocates there.  Called
    FIRST in main(), before the framebuffer.
  - netboot_launch(): verifies every text/data section AND bss against the
    reserved region and refuses (-3) if any would land on it, instead of
    corrupting the staged image or the copier mid-flight.  Also hands the new
    image a stack inside the reserved tail.

The app now tells you on screen to send Swiss's boot.dol first, and the README
explains why: the launcher and the transfer can each be broken independently
and a hang looks identical, so the first send should be an image whose success
is unmistakable.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
2026-10-09 11:13:32 +02:00

95 lines
2.2 KiB
ArmAsm

/* Relocatable DOL copier for netboot_launch().
*
* WHY THIS EXISTS IN ASSEMBLY, IN ITS OWN FILE:
* a DOL's sections load over the memory this program is running from (the
* standard load address is 0x80003100, right where our own .text sits), so a
* copier compiled as an ordinary C function would overwrite its own
* instructions partway through the copy and hang the console. This routine is
* copied into a reserved region at the top of MEM1 and executed THERE, so the
* image cannot touch it.
*
* It must therefore be strictly position independent: no globals, no literal
* pool, no TOC references, no calls. Only PC-relative branches and
* register-relative loads. Anything else silently reads from the address it
* was LINKED at rather than the one it is RUNNING at.
*
* r3 = descriptor, in the same reserved region:
* 0x00 entry point
* 0x04 stack pointer to hand the new image
* 0x08 section count
* 0x0C bss address
* 0x10 bss length
* 0x14 section count * (src, dst, len)
*/
.text
.globl nb_stub
.globl nb_stub_end
.align 2
nb_stub:
/* ---- copy every section ---- */
lwz 4, 8(3) /* nsec */
addi 5, 3, 0x14 /* -> first (src,dst,len) */
1: cmpwi 4, 0
beq 3f
lwz 6, 0(5) /* src */
lwz 7, 4(5) /* dst */
lwz 8, 8(5) /* len */
cmpwi 8, 0
beq 2f
mtctr 8
4: lbz 9, 0(6)
stb 9, 0(7)
addi 6, 6, 1
addi 7, 7, 1
bdnz 4b
2: addi 5, 5, 12
addi 4, 4, -1
b 1b
3: /* ---- zero BSS ---- */
lwz 7, 0xC(3)
lwz 8, 0x10(3)
cmpwi 8, 0
beq 6f
li 9, 0
mtctr 8
5: stb 9, 0(7)
addi 7, 7, 1
bdnz 5b
6: /* ---- make the copies visible to the instruction fetcher ----
* Flush each destination out of the data cache and invalidate the
* matching instruction-cache lines. Without this the CPU happily
* executes stale instructions from icache at the entry point. */
lwz 4, 8(3)
addi 5, 3, 0x14
7: cmpwi 4, 0
beq 9f
lwz 7, 4(5)
lwz 8, 8(5)
cmpwi 8, 0
beq 8f
addi 8, 8, 31 /* round up to whole 32-byte lines */
srwi 8, 8, 5
mtctr 8
10: dcbf 0, 7
icbi 0, 7
addi 7, 7, 32
bdnz 10b
8: addi 5, 5, 12
addi 4, 4, -1
b 7b
9: sync
isync
lwz 1, 4(3) /* stack for the new image */
lwz 9, 0(3) /* entry */
mtlr 9
li 3, 0
li 4, 0
li 5, 0
blr
nb_stub_end: