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>
This commit is contained in:
@@ -29,6 +29,17 @@
|
||||
|
||||
#define NB_BLOCK_MAX 1024u /* payload bytes per frame */
|
||||
|
||||
/* Reserve the staging region at the top of MEM1. MUST be called early in
|
||||
* main(), before anything else allocates, and the pointer it returns is where
|
||||
* netboot_receive() should stage the image. Returns NULL if MEM1 is too
|
||||
* small (it never is on real hardware).
|
||||
*
|
||||
* The image CANNOT live in an ordinary malloc'd buffer: DOL sections load from
|
||||
* 0x80003100 upward and would overwrite it partway through the copy. This
|
||||
* carves the top of MEM1 and hands it to SYS_SetArena1Hi so libogc will not
|
||||
* allocate there either. */
|
||||
void *netboot_reserve(u32 *out_max);
|
||||
|
||||
/* Receive a .dol into `dst`. Returns its length, or <0 on error.
|
||||
* `status` (optional) is called with a human-readable progress line. */
|
||||
int netboot_receive(void *dst, u32 maxlen,
|
||||
|
||||
Reference in New Issue
Block a user