netboot: hold the screen on failure, dump the descriptor, shrink the block

Two separate problems, one of which was hiding the other.

1. The diagnostics were unreadable.  do_netboot() printed them and returned,
   and the caller's draw_main() redrew immediately and wiped the screen -- so
   two consecutive failures were reported only as "a short flash" with no
   detail, and the error code alone was not enough to act on.  nb_pause() now
   holds the screen until a button is pressed, on every failure path.

   This cost two blind round trips, each of which needs a hand copy of the
   .dol to the SD card.  Printing a diagnosis and then erasing it is worse
   than not printing one.

2. The default block was 1024 bytes, making ~1050-byte frames that span FIVE
   of the SPRAM ring's 15 pages.  The only multi-page frame ever proven on
   this hardware is the 342-byte DHCP broadcast from bring-up, which spans
   two.  Five-page frames are untested territory, and a transfer is the wrong
   place to discover a wrap bug.

   Default is now 256 bytes -> ~296-byte frame -> two pages, deliberately
   close to the proven case.  --block raises it once small blocks work; the GC
   still caps at NB_BLOCK_MAX = 1024.

ring_next() also keeps the four raw descriptor bytes and the page it read
them from, and the error path prints them.  When a length is rejected those
bytes ARE the diagnosis: 00 00 xx xx tells us the assembler wrote a
descriptor and the length is simply unexpected, whereas garbage tells us we
are reading the wrong page.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
2026-10-09 11:48:39 +02:00
parent 83a62d60a0
commit 77cd00a63c
3 changed files with 43 additions and 3 deletions
+11
View File
@@ -26,6 +26,10 @@
static u8 s_our_mac[6];
static u8 s_peer_mac[6];
/* Last descriptor ring_next() looked at, kept for the error path: when a
* length is rejected, the four raw bytes are the whole diagnosis. */
static u8 s_last_desc[4];
static u32 s_last_page;
static u16 rd16(const u8 *p) { return ((u16)p[0] << 8) | p[1]; }
static void wr16(u8 *p, u16 v) { p[0] = (u8)(v >> 8); p[1] = (u8)v; }
@@ -48,6 +52,8 @@ static int ring_next(u8 *buf, u32 cap)
addr = rpage << 8;
if (bba_stream((u16)addr, hdr, 4) < 0) return -1;
memcpy(s_last_desc, hdr, 4);
s_last_page = rpage;
dlen = ((u32)hdr[2] << 8) | hdr[3];
if (dlen <= 4 || dlen > 1518 + 4) return -3; /* descriptor implausible */
flen = dlen - 4;
@@ -186,6 +192,11 @@ int netboot_receive(void *dst, u32 maxlen, void (*status)(const char *msg))
n == -2 ? "RRP outside pages 1-15" :
"descriptor length implausible");
status(line);
snprintf(line, sizeof(line),
" page %u descriptor = %02X %02X %02X %02X",
(unsigned)s_last_page, s_last_desc[0],
s_last_desc[1], s_last_desc[2], s_last_desc[3]);
status(line);
}
return -2;
}