#ifndef NETBOOT_H #define NETBOOT_H #include #include /* Self-update over the BBA: receive a .dol via raw ethernet and launch it. * * Deliberately NOT built on an IP stack. Frames carry a private ethertype * and a 12-byte header, so there is no ARP, no IP, no checksums and no * libogc network driver competing with us for the EXI channel -- it reuses * exactly the two paths the test suite already proves on hardware: * bba_tx_bytes() for TX and the SPRAM ring at RRP for RX. * * The transfer is STOP-AND-WAIT (one block in flight, ACKed before the next). * That is not just simplicity: the gateware does not consume RRP, so * RXFrameAssembler can overwrite ring pages the GC has not read yet. One * block in flight means the ring never has more than one frame outstanding, * so the missing overflow protection cannot bite. Do not "optimise" this * into a sliding window without adding RBFI-style protection first. */ #define NB_ETHERTYPE 0x88B5u /* IEEE 802 local experimental ethertype 1 */ #define NB_MAGIC 0x47435550u /* "GCUP" */ #define NB_OP_DATA 0x01u /* host -> GC: one block */ #define NB_OP_ACK 0x02u /* GC -> host: block received */ #define NB_OP_DONE 0x03u /* host -> GC: transfer complete, launch */ #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, void (*status)(const char *msg)); /* Mount whichever SD interface is present (SD Gecko slot A or B, or SD2SP2) * and write `len` bytes to `path` (e.g. "/gc_bba_test.dol"), verifying the * result by reading it back. Returns 0 on success, <0 on error. * * NOTE the SD Gecko in memory-card slot A shares EXI channel 0 with the BBA * (which is channel 0, device 2). libogc arbitrates, but SD2SP2 -- on its own * channel -- avoids the question entirely. */ int netboot_sd_write(const char *path, const void *buf, u32 len, void (*status)(const char *msg)); /* Read `path` off the SD card into `dst` and launch it. Does not return on * success. Returns <0 if it cannot be read or is not a plausible DOL. * * This is how the update completes: we NEVER jump into the image we just * received, only into a known-good /boot.dol (Swiss). A broken test build * therefore costs nothing -- Swiss still comes up and can load whatever you * want, including the previous build. */ int netboot_boot_file(const char *path, void *dst, u32 maxlen, void (*status)(const char *msg)); /* Destination path the host asked for in its DONE frame (default * "/gc_bba_test.dol"). */ const char *netboot_dest_path(void); /* Launch a .dol image already in memory. Does not return on success. * Returns <0 if the image is not a plausible DOL. */ int netboot_launch(const void *dol); #endif