From 2eedb651c058bc4baaf2a9a75a2dfea5400f976c Mon Sep 17 00:00:00 2001 From: "NathanNeurotic (Ripto)" <109461996+NathanNeurotic@users.noreply.github.com> Date: Tue, 21 Jul 2026 12:03:45 -0700 Subject: [PATCH 1/2] perf(boot): drop four modules off the boot-critical path -- POPSLoader-shape lazy tier-0 (maintainer directive) Product of the POPSLoader gap analysis (wf_2662799e-a7d, both tracks source-verified). THE HEADLINE FINDING: the directed shape is ALREADY substantially ours -- config home is cwd-driven (configInit(gBootDir)), sysReset loads ZERO storage transports, and mass boots already resolve their backing device via USBMASS_IOCTL_GET_DRIVERNAME (bdmReadDeviceIdentity in the resolver scan) rather than assuming USB. Reading POPSLoader's source also corrected two assumptions: it IOP-RESETS at boot (Makefile RESET_IOP=1 -- its speed is not inherited mounts), and its "fast settings read" is a DODGE, not a solution: it reads settings from mc0:/POPSTARTER/.pldrs (always-up device) and embeds every other asset in the ELF -- it never solved cwd-settings-over-arbitrary-devices. Ours does. THE GENUINE TRANSFERABLE WIN (this commit): sysReset serialized four module DMAs onto the boot-critical path of EVERY flavor -- including the fast mc/mmce boots -- for modules nothing needs before the menu: libsd + audsrv (audio), isofs + genvmc (launch prep). Now: - libsd + audsrv load at the top of deferredAudioInit (their consumers' existing deferred seam; audioInit binds audsrv right below). - isofs + genvmc load via the new idempotent sysLoadLaunchModules(): from deferredInit on the IO worker for the GUI path (resident long before the menu is interactive -- never AT launch, per the Delta-4 no-module-loads-in-the-launch-sequence doctrine), and SYNCHRONOUSLY on the autolaunch fork, which skips deferredInit and needs both before its launch prep. NOT changed, deliberately (from the ranked candidate list): the untyped-mass ATA escalation stays (post-#250 its failure is retryable; residual cost is corner-case latency only); mmceInit stays synchronous (#152 THM/LNG starvation risk); menu-before-first-scan ordering stays (load-bearing for the #132 boot-step localizer; explicitly not to be stacked with the live HW triage). One candidate is flagged for a MAINTAINER UX DECISION in the PR: bdmLoadBlockDeviceModules loads every gEnable*'d transport at boot regardless of Manual/Auto -- gating Manual transports to tab entry would change what "Manual" means for tab visibility/hotplug. Builds clean (make opl.elf, exit 0). Co-Authored-By: Claude Fable 5 --- include/system.h | 3 +++ src/opl.c | 13 +++++++++++++ src/system.c | 43 +++++++++++++++++++++++++++++++++++-------- 3 files changed, 51 insertions(+), 8 deletions(-) diff --git a/include/system.h b/include/system.h index 1ad033e236..965a7eeeb7 100644 --- a/include/system.h +++ b/include/system.h @@ -17,6 +17,9 @@ int sysGetDiscID(char *discID); void sysInitDev9(void); void sysShutdownDev9(void); void sysReset(); +// Deferred halves of the old sysReset module set (lazy boot, 2026-07-21). Idempotent one-shots. +void sysLoadAudioModules(void); +void sysLoadLaunchModules(void); void sysExecExit(void); int sysLaunchDisc(void); // boot the physical PS2 disc in the drive; <0 (stays in OPL) on failure void sysPowerOff(void); diff --git a/src/opl.c b/src/opl.c index 31e3070867..48e62ef9e5 100644 --- a/src/opl.c +++ b/src/opl.c @@ -3000,6 +3000,12 @@ static void deferredInit(void) guiSetBootStatusSticky(_l(_STR_BOOT_BUILDING_MENU)); // boot-step localizer (IO thread) -- reaching // here means the device init chain cleared; see gui.c + // Launch-support modules (isofs + genvmc), moved OFF sysReset's boot-critical path (lazy boot, + // 2026-07-21). Loaded here on the IO worker: resident long before the menu becomes interactive, + // so no launch ever loads a module mid-sequence (Delta-4 doctrine). The autolaunch fork, which + // never reaches this handler, calls the same idempotent one-shot synchronously. + sysLoadLaunchModules(); + // inform GUI main init part is over struct gui_update_t *id = guiOpCreate(GUI_INIT_DONE); if (id) @@ -3049,6 +3055,9 @@ static void deferredAudioInit(void) int ret; guiSetBootStatusSticky(_l(_STR_BOOT_LOADING_SOUNDS)); // boot-step localizer (IO thread) -- see gui.c + // libsd + audsrv, moved OFF sysReset's boot-critical path (lazy boot, 2026-07-21): this handler + // is their consumers' natural seam -- audioInit binds audsrv right below. + sysLoadAudioModules(); audioInit(); ret = sfxInit(1); if (ret < 0) @@ -3341,6 +3350,10 @@ int main(int argc, char *argv[]) } if (argc >= 5) { + // The autolaunch legs skip deferredInit (which loads these for the GUI path), and their + // launch prep needs isofs (ISO probing/PS2Logo) + genvmc (per-game VMC validation) resident + // BEFORE the launch sequence starts -- never load modules inside it (Delta-4 doctrine). + sysLoadLaunchModules(); /* argv[0] boot path argv[1] game->startup argv[2] str to u32 game->start_sector diff --git a/src/system.c b/src/system.c index 3c0acade51..a47c8a122c 100644 --- a/src/system.c +++ b/src/system.c @@ -258,14 +258,13 @@ void sysReset() sysLoadModuleBuffer(&poweroff_irx, size_poweroff_irx, 0, NULL); LOG("[USBD]:\n"); sysLoadModuleBuffer(&usbd_irx, size_usbd_irx, 0, NULL); - LOG("[ISOFS]:\n"); - sysLoadModuleBuffer(&isofs_irx, size_isofs_irx, 0, NULL); - LOG("[GENVMC]:\n"); - sysLoadModuleBuffer(&genvmc_irx, size_genvmc_irx, 0, NULL); - LOG("[LIBSD]:\n"); - sysLoadModuleBuffer(&libsd_irx, size_libsd_irx, 0, NULL); - LOG("[AUDSRV]:\n"); - sysLoadModuleBuffer(&audsrv_irx, size_audsrv_irx, 0, NULL); + // isofs/genvmc/libsd/audsrv are NO LONGER loaded here (POPSLoader-shape lazy boot, maintainer + // directive 2026-07-21): they serialized four module DMAs onto the boot-critical path of EVERY + // flavor while nothing needs them before the menu. libsd+audsrv load in deferredAudioInit (their + // consumers' existing deferred seam); isofs+genvmc load via sysLoadLaunchModules() -- from + // deferredInit on the IO worker for the GUI path (resident long before any user launch, never AT + // launch per the Delta-4 no-module-loads-in-the-launch-sequence doctrine), and synchronously on + // the autolaunch fork which skips deferredInit entirely. #ifdef PADEMU int ds3pads = 1; // only one pad enabled @@ -287,6 +286,34 @@ void sysReset() poweroffSetCallback(&poweroffHandler, NULL); } +// Deferred halves of the old sysReset module set (see the comment there). Both are idempotent: +// sysLoadModuleBuffer dedupes an already-resident buffer, and the one-shot guards make repeat calls +// free. Audio pair = deferredAudioInit's first act; launch pair = deferredInit (IO worker, GUI path) +// or the autolaunch fork (synchronous -- it skips deferredInit). +void sysLoadAudioModules(void) +{ + static unsigned char loaded = 0; + if (loaded) + return; + LOG("[LIBSD]:\n"); + sysLoadModuleBuffer(&libsd_irx, size_libsd_irx, 0, NULL); + LOG("[AUDSRV]:\n"); + sysLoadModuleBuffer(&audsrv_irx, size_audsrv_irx, 0, NULL); + loaded = 1; +} + +void sysLoadLaunchModules(void) +{ + static unsigned char loaded = 0; + if (loaded) + return; + LOG("[ISOFS]:\n"); + sysLoadModuleBuffer(&isofs_irx, size_isofs_irx, 0, NULL); + LOG("[GENVMC]:\n"); + sysLoadModuleBuffer(&genvmc_irx, size_genvmc_irx, 0, NULL); + loaded = 1; +} + static void poweroffHandler(void *arg) { sysPowerOff(); From c775d2fd8034cfdea508818bac8a9bb3be7589bb Mon Sep 17 00:00:00 2001 From: "NathanNeurotic (Ripto)" <109461996+NathanNeurotic@users.noreply.github.com> Date: Tue, 21 Jul 2026 12:13:00 -0700 Subject: [PATCH 2/2] fix(boot): bot sweep of #252 -- both vetted and taken - The one-shot latches now set ONLY when every member load succeeds (CodeRabbit major -- real, and embarrassingly the exact latch-on-failure class the atad/mmce fixes just eradicated). - sysReset() clears both latches: after an IOP reboot nothing is resident, so the deferred loaders must reload on their next call (CodeRabbit minor -- real for any future in-process reset). Builds clean. Co-Authored-By: Claude Fable 5 --- src/system.c | 37 +++++++++++++++++++++++-------------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/src/system.c b/src/system.c index a47c8a122c..8c01e6a2c1 100644 --- a/src/system.c +++ b/src/system.c @@ -62,6 +62,9 @@ extern unsigned int size_eesync_irx; #define MAX_MODULES 64 static void *g_sysLoadedModBuffer[MAX_MODULES]; +// Deferred-loader latches (audio + launch-support one-shots below); cleared by sysReset. +static unsigned char sysAudioModsLoaded = 0; +static unsigned char sysLaunchModsLoaded = 0; static s32 sysLoadModuleLock = -1; #define ELF_MAGIC 0x464c457f @@ -240,6 +243,10 @@ void sysReset() // clears modules list memset(g_sysLoadedModBuffer, 0, sizeof(g_sysLoadedModBuffer)); + // ...and the deferred-loader latches: after an IOP reboot NOTHING is resident, so the audio and + // launch-support one-shots below must reload on their next call (CodeRabbit review of #252). + sysAudioModsLoaded = 0; + sysLaunchModsLoaded = 0; // load modules LOG("[IOMANX]:\n"); @@ -286,32 +293,34 @@ void sysReset() poweroffSetCallback(&poweroffHandler, NULL); } -// Deferred halves of the old sysReset module set (see the comment there). Both are idempotent: -// sysLoadModuleBuffer dedupes an already-resident buffer, and the one-shot guards make repeat calls -// free. Audio pair = deferredAudioInit's first act; launch pair = deferredInit (IO worker, GUI path) -// or the autolaunch fork (synchronous -- it skips deferredInit). +// Deferred halves of the old sysReset module set (see the comment there). Both are idempotent +// one-shots that latch ONLY on full success (a transient load failure stays retryable -- the exact +// latch-on-failure class the 2026-07 atad/mmce fixes eradicated; CodeRabbit review of #252), and +// sysReset() clears the latches so an in-process IOP reboot reloads everything. Audio pair = +// deferredAudioInit's first act; launch pair = deferredInit (IO worker, GUI path) or the autolaunch +// fork (synchronous -- it skips deferredInit). void sysLoadAudioModules(void) { - static unsigned char loaded = 0; - if (loaded) + if (sysAudioModsLoaded) return; LOG("[LIBSD]:\n"); - sysLoadModuleBuffer(&libsd_irx, size_libsd_irx, 0, NULL); + int r0 = sysLoadModuleBuffer(&libsd_irx, size_libsd_irx, 0, NULL); LOG("[AUDSRV]:\n"); - sysLoadModuleBuffer(&audsrv_irx, size_audsrv_irx, 0, NULL); - loaded = 1; + int r1 = sysLoadModuleBuffer(&audsrv_irx, size_audsrv_irx, 0, NULL); + if (r0 >= 0 && r1 >= 0) + sysAudioModsLoaded = 1; } void sysLoadLaunchModules(void) { - static unsigned char loaded = 0; - if (loaded) + if (sysLaunchModsLoaded) return; LOG("[ISOFS]:\n"); - sysLoadModuleBuffer(&isofs_irx, size_isofs_irx, 0, NULL); + int r0 = sysLoadModuleBuffer(&isofs_irx, size_isofs_irx, 0, NULL); LOG("[GENVMC]:\n"); - sysLoadModuleBuffer(&genvmc_irx, size_genvmc_irx, 0, NULL); - loaded = 1; + int r1 = sysLoadModuleBuffer(&genvmc_irx, size_genvmc_irx, 0, NULL); + if (r0 >= 0 && r1 >= 0) + sysLaunchModsLoaded = 1; } static void poweroffHandler(void *arg)