# POPSLoader High-Level Code Audit

**Audited branch:** `BETA-12-PLAY`
**Audit date:** 2026-05-23
**Auditor:** Antigravity (AI)
**Scope:** Read-only survey of checked-out source. No source changes made.

---

## 1. Repository Structure

```
POPSLoader/
├── asm/                  # Embedded C assets (PNG, Lua, IRP, ICN, etc.) as C arrays
├── bin/
│   ├── POPSLDR/          # Runtime Lua scripts + static data (POPSTARTER.ELF, PATCH_5.BIN, icons, IRX variants)
│   └── POPSLOADER.ELF    # Pre-built ELF (not tracked by Git; produced by `make all`)
├── src/
│   ├── elf_loader/       # BRAM child loader library
│   │   ├── loader.c      # Generated C blob of the child loader ELF (tracked; regenerated by `make elfloader`)
│   │   ├── libcustom-elf-loader.a
│   │   └── src/
│   │       ├── elf.c     # Main ELF-handoff backend
│   │       └── loader/src/loader.c  # Child loader main()
│   ├── main.cpp          # EE boot entry point; loads IRX stack, then runs boot.lua
│   ├── luasystem.cpp     # System.* Lua binding layer (file I/O, ELF load, BDM, HDD, MMCE, …)
│   ├── luaHDD.cpp        # HDD.* Lua binding layer
│   ├── luaplayer.cpp     # Lua VM bootstrap
│   ├── luagraphics.cpp   # Graphics.* binding
│   ├── luacontrols.cpp   # pad/controller bindings
│   ├── embed_assets.cpp  # Asset registration / boot.lua injection
│   ├── graphics.cpp      # gsKit wrapper
│   └── …                 # render, sound, atlas, fntsys, md5, etc.
├── etc/boot.lua          # First Lua executed; initializes fonts, requires system
├── iop/embed/            # Pre-built IRX modules for BDM, FATFS, MMCE, MX4SIO
├── modules/              # ds34usb / ds34bt EE-side libraries
├── Makefile              # Primary build + asset-embedding pipeline
├── .github/workflows/
│   ├── compilation.yml   # Build/package CI (source of truth for release artifacts)
│   └── opencode.yml      # Comment-triggered AI-assistance automation (NOT a build gate)
└── docs/                 # (this file's home)
```

**Languages:** C++ (main EE runtime), C (elf.c, loader.c, asset stubs), Lua (system.lua, ui.lua, images.lua, pops_profiles.lua).

---

## 2. Boot / Execution Flow

```
Power-on / OSDSYS hands off POPSLOADER.ELF
  └─► main.cpp: _ps2sdk_memory_init()   — optional IOP reset (RESET_IOP=1 default)
       └─► main():
            ├─ SBV patches (enable_lmb, disable_prefix_check, fileio)
            ├─ IRX load sequence:
            │   iomanX → fileXio → sio2man → mmceman → mcman → mcserv
            │   padman → libsd → usbd → ds34usb → ds34bt → audsrv
            ├─ initMC()  — MC RPC + initial sync
            ├─ initGraphics()  — gsKit setup
            ├─ pad_init()
            ├─ chdir(boot_path)
            └─ loop: runScript("boot.lua")
                 └─► etc/boot.lua:  font init → require("system")
                      └─► bin/POPSLDR/system.lua:
                           ├─ Settings load  (.pldrs on mc0:/POPSTARTER/ or sidecar)
                           ├─ PLDR.AutoInitStartupBackends()
                           └─ require("ui")  → drives all user interaction
```

**Key observation:** The IOP reset at `_ps2sdk_memory_init()` happens before any IRX is loaded. Any subsequent ELF handoff that needs a clean IOP must either re-issue a full IOP reset (via `SifIopReset`) or avoid SIF state contamination when calling `ExecPS2`.

---

## 3. Subsystem Inventory

### 3.1 `main.cpp` — EE Bootstrap
- Boots IOP modules in a fixed sequence.
- `LoadIrxChecked()` returns bool and logs errors via DPRINTF; IRX failures are non-fatal but noted.
- `NormalizeDirPath()` handles `host:`, single-colon, and drive-letter paths.
- `setLuaBootPath()` extracts directory from `argv[0]` using `/`, `\`, or `:` as delimiters.
- Boot timestamp helper (`BootStamp`) is DPRINTF-gated; invisible in non-debug builds.
- `_ps2sdk_memory_init()` is a ps2sdk weak-function override; controlled by `RESET_IOP` Makefile flag.

**No functional issues observed at this scope.** The optional `DumpLoadedModules()` function exists only in DEBUG builds and is safe.

---

### 3.2 `src/elf_loader/src/elf.c` — ELF Handoff Backends

Four public launch entry points:

| Function | Route |
|---|---|
| `LoadELFFromFile(path, argc, argv)` | Non-reboot direct `LoadExecPS2` |
| `LoadELFFromFileExecPS2(path, argc, argv)` | Non-reboot `SifLoadElf` → `ExecPS2` |
| `LoadELFFromFileExecPS2RebootIOP(path, argc, argv)` | IOP reboot then `ExecPS2`, or → embedded loader for HDD paths |
| `LoadELFFromFileExecPS2RebootIOPWithPartition(path, partition, argc, argv)` | Partition-aware version; routes HDD-backed paths through `ExecuteHddBackedViaEmbeddedLoader` |

**Embedded loader route (`ExecuteViaEmbeddedLoader`):**
1. Validates ELF magic of the in-memory BRAM loader blob.
2. `wipe_bramMem()` zeros `0x00084000–0x00100000`.
3. Writes `EmbeddedLoaderMetadata` at `0x00083C00` (magic `POPL`, version `1`, `partition_context`, `load_path`, `valid=1`).
4. Copies loader ELF PT_LOAD segments to their linked BRAM addresses.
5. `SifExitIopHeap / SifExitRpc / SifExitCmd`, `FlushCache(0/2)`, then `ExecPS2` into the loader's entry point.

**`LoadELFFromFileWithPartition` route:**
- If `partition != NULL`, routes directly to `ExecuteViaEmbeddedLoader(partition, resolved_path, argc, argv)`.
- Otherwise: resolves path, opens/closes to verify existence, builds `launch_argv`, calls `LoadExecPS2`.

**Findings:**

> [!NOTE]
> `elf.c.orig` is present in `src/elf_loader/src/` (36 KB vs. 18 KB for current `elf.c`). This leftover file is not part of the build but may confuse future AI agents or developers. It should be removed unless it serves a reference purpose.

> [!NOTE]
> `LoadELFFromFileWithPartition` calls `wipe_bramMem()` unconditionally before the non-partition direct-`LoadExecPS2` path. This wipes BRAM even when the BRAM embedded loader is not going to be used. This is consistent with the original design intent (clearing any previous loader state), but is a latent issue if any caller relies on BRAM contents surviving across a non-BRAM launch attempt.

> [!NOTE]
> The `can_open_exec_path()` function uses a raw `open()` / `close()` round-trip to verify file existence. This is a side-effect probe (opens file, consumes a file descriptor temporarily). This is fine for ps2sdk environments but worth noting if future fd-leak sensitivity arises.

> [!CAUTION]
> `loader_elf[]` is declared `extern unsigned char` with no size declaration. If the linker ever fails to include the embedded loader object, this will silently resolve to an arbitrary address, and the ELF magic check (`ELF_MAGIC`) is the only runtime guard. CI checking that `src/elf_loader/loader.c` was regenerated is the correct mitigation; it must remain enforced.

---

### 3.3 `src/elf_loader/src/loader/src/loader.c` — BRAM Child Loader

Entry `main(int argc, char *argv[])`:
1. Reads `EmbeddedLoaderMetadata` from `0x00083C00`.
2. If `argc == 0`: calls `build_default_target_arg0()` to synthesize `argv[0]` from `partition_context` + `load_path`.
3. Otherwise: copies caller `argv[]` into `target_arg_storage`.
4. `SifInitRpc(0)`, `wipeUserMem()` (clears `0x00100000 – GetMemorySize()`), `FlushCache(0)`.
5. Selects load path:
   - **fileXio direct load** (`should_use_filexio_direct_load()`): used for `pfs:` / `hdd:` paths *without* HDD partition context. Calls `fileXioInit()` then `load_elf_via_filexio()`.
   - **SifLoadElf**: used for everything else (including HDD partition-context paths and generic `mc:`/`mass:` paths).
6. On success (`elfdata.epc != 0`):
   - `loaded_via_filexio` → `FlushCache(0/2)` → `ExecPS2`.
   - `is_hdd_partition_context` → dynamic PFS unmount, `SifExitRpc/Cmd`, `FlushCache(0)` → `ExecPS2`.
   - Generic non-HDD path → `SifExitRpc` (no `SifExitCmd`), `FlushCache(0/2)` → `ExecPS2`.

**Findings:**

> [!NOTE]
> `build_default_target_arg0()` uses `snprintf` and `strncat`. Earlier docs claimed the child loader was avoiding `printf`/`snprintf` to reduce binary size and runtime dependency risk. The current source contradicts that claim. This is documented in `HDD_POPSTARTER_HANDOFF.md` finding 6 and is a source/doc drift risk.

> [!NOTE]
> Debug color macros (`SET_GS_BGCOLOUR`) are compiled out unless `LOADER_ENABLE_DEBUG_COLORS` is defined. These are correct to leave in place but must not be enabled in release builds. They are not enabled by default in the current Makefile.

> [!IMPORTANT]
> The child loader's `target_arg_storage` is `1024` bytes and `target_argv` is `char *[33]`. The outer `LoadELFFromFileWithPartition` / `ExecuteViaEmbeddedLoader` limit is also 32 args. These sizes are consistent but the child loader has no defense against a caller that passes `argc > 32` (the check is `if (target_argc > 32) return -E2BIG`), which is correct. However, `target_arg_storage` overflows are only checked per-arg, not as a total-size guard before copying. If an individual argument is very long, `target_arg_offset + arg_len > sizeof(target_arg_storage)` would trigger, but the error handling just returns `-E2BIG` with no notification. This is the correct PS2 behavior; nothing observable will happen after `ExecPS2` fails to run anyway.

> [!CAUTION]
> The BRAM child loader is a separate ELF that must be rebuilt and regenerated (`src/elf_loader/loader.c` via `bin2c`) any time `loader.c` changes. CI enforces this. Do NOT edit `loader.c` without running `make elfloader` and committing the regenerated `src/elf_loader/loader.c` blob. Failing to do so will cause a CI build failure and a stale-loader-on-hardware risk.

---

### 3.4 `src/luasystem.cpp` — Lua → C Binding Layer

Key `System.*` bindings relevant to launch:

| Lua Binding | C Function | Route |
|---|---|---|
| `System.loadELF(path, reboot_iop, [selector])` | `lua_loadELF` | `LoadELFFromFile` or `LoadELFFromFileExecPS2RebootIOP` |
| `System.loadELFWithPartition(path, reboot_iop, partition_context, args...)` | `lua_loadELFWithPartition` | `LoadELFFromFileExecPS2RebootIOPWithPartition` |
| `System.loadELFRebootIOP(path, [argv0])` | `lua_loadELFRebootIOP` | `LoadELFFromFileExecPS2RebootIOP` |
| `System.exitToBrowser()` | `lua_exitToBrowser` | `Exit(0)` |
| `System.setExecKeepPfsMask(mask)` | `lua_setExecKeepPfsMask` | `SetExecKeepPfsMask` |

**Findings:**

> [!NOTE]
> `lua_loadELF` without a `selector` argument calls `LoadELFFromFile(path, 0, NULL)` (non-reboot) or `LoadELFFromFileExecPS2RebootIOP(path, 0, NULL)` (reboot). The child-loader or `LoadExecPS2` then synthesizes `argv[0]` internally. This is the correct path for `BOOT.ELF` (mc0:/BOOT/BOOT.ELF, no selector needed).

> [!NOTE]
> `lua_loadELFWithPartition` validates that `partition_context` matches the `hdd?:PART:` pattern via `is_partition_context_arg()`. This guards against trivially wrong calls. It also enforces `reboot_iop != 0`, which is correct since partition-aware launches must go through the embedded loader path.

> [!NOTE]
> After any launch call, `ClearExecKeepPfsMask()` is called regardless of whether the launch succeeded. This prevents stale PFS keep-masks from persisting if `LoadELFFromFile` or a launch backend returns (which only happens on failure).

---

### 3.5 `bin/POPSLDR/system.lua` — Lua Orchestration Layer

**Responsible for:**
- Settings load/save/apply (`LoadSettings`, `EncodeSettings`, `CommitSettingsChanges`).
- Backend detection and lazy-init (`EnsureHddRuntimeReadyForExec`, `LoadHDDModules`, `BuildUsbIdentityDeferred`).
- Startup auto-init (`AutoInitStartupBackends`, `CollectStartupBackendTargets`).
- HDD partition mount tracking (`MountHddPartitionTracked`, `UMountHddPartitionTracked`, `PLDR.HDD.MOUNT_TRACKER`).
- POPStarter game launch (`RunPOPStarterGame`, `LaunchEngine`, `ResolvePopstarterPath`, `BuildPartitionScopedExecInfo`).
- External handoff prep (`PrepareForExternalELFLaunch`, `PrepareForColdExternalELFLaunch`).
- Game list construction and sorting.

**Findings:**

> [!IMPORTANT]
> `PrepareForColdExternalELFLaunch()` clears the exec keep mask to 0 and unmounts **all** tracked HDD partition slots. This is the correct behavior for BOOT.ELF exit after HDD has been initialized — it ensures no HDD state leaks into the wLaunchELF environment. The current `LaunchBootElf` in `ui.lua` calls this path when `hdd_loaded == true`. This is the right conditional.

> [!NOTE]
> `PrepareForExternalELFLaunch()` calls `System.setExecKeepPfsMask()` with a mask derived from slots that should be preserved during handoff. The keep-mask is consumed in `elf.c`'s `unmount_pfs_slots_for_exec()` before the final `ExecPS2`. This flow is structurally correct.

> [!NOTE]
> `CommitSettingsChanges()` normalizes `popstarter_mode` between `CUSTOM` and `PROFILE_DEFAULT`. When mode is profile-default, `EncodeSettings()` writes an empty `POPSTARTER_PATH`. This intentionally relies on the selected profile path at next load-time. This is the documented behavior (see `STATE.md`, `DECISIONS.md`) and is source-confirmed. Hardware verification of the full save/load round-trip has not been recorded.

> [!CAUTION]
> `AutoInitStartupBackends()` initializes HDD via `PLDR.LoadHDDModules()` but intentionally does **not** build the game list or scan POPS partitions. This split was necessary to avoid large-library boot-time scans. If the HDD backend init fails silently (e.g., module load error not surfaced to Lua), auto-init will appear to have run without actually establishing HDD readiness. `PLDR.LoadHDDModules()` return values should be checked in callers where a failure would leave the HDD page non-functional.

---

### 3.6 `bin/POPSLDR/ui.lua` — UI Orchestration Layer

**Responsible for:**
- Scene management and transition (`UI.Scene.Set`, `UI.Scene.Push/Pop`).
- Notification toast system (`UI.Notify`, `UI.DrawNotifications`).
- Modal dialog system (`UI.Modal.*`).
- Exit modal and BOOT.ELF launch (`UI.Modal.ConfirmExit`, `UI.Modal.LaunchBootElf`).
- Settings page (OPL-style focused-list layout; D-pad-driven).
- Loading/progress screen and backdrop (`UI.SavingActive`, `UI.CCOL.LOADING_BACKDROP`).
- Cover preview behavior.
- Keyboard/path editor.

**Findings:**

> [!NOTE]
> `LaunchBootElf()` (line 1305) resolves the ELF path via `ResolveFirstExistingElf({"mc0:/BOOT/BOOT.ELF", "mc1:/BOOT/BOOT.ELF"})`. If neither path exists, it shows an error notification and returns cleanly. This guard is correct.

> [!NOTE]
> `LaunchBootElf()` always calls `System.loadELF(elf_path, 0)` (non-reboot variant, `reboot_iop=0`). The variable `reboot_iop` is computed and set to `1` when `hdd_loaded` is true, but **it is never passed to `System.loadELF`**. The call at line 1326 always passes `0` regardless of `reboot_iop`. This means the HDD-conditional reboot logic currently has no effect. This is a latent correctness issue but may not be the cause of current failures since the reboot path itself has also failed in hardware testing.

> [!CAUTION]
> `LaunchBootElf()` computes `reboot_iop` but always passes `0` to `System.loadELF`. If the intent is to conditionally use the reboot IOP path when HDD is loaded, the call should be:
> ```lua
> local rc = System.loadELF(elf_path, reboot_iop)
> ```
> This is a source defect. Whether fixing it helps hardware depends on whether the reboot-IOP route itself works for BOOT.ELF — which is currently `Unknown (verify on hardware)`.

> [!NOTE]
> The backup files `ui.lua.backup-before-notif-audit-20260523-053651` and `ui.lua.backup-before-wraptext-repair-20260523-053913` are untracked in the working tree. These are not part of the build and should be removed or gitignored to avoid confusion.

> [!NOTE]
> `uibeforeclauddesign.lua` is also untracked. This is a pre-redesign backup. It is not part of the build and should be removed or gitignored.

---

### 3.7 `src/main.cpp` — Notable Patterns

- `ARGV0` is stored as a global `char *`. It points into the original `argv[]` array passed to `main()`. This is safe as long as the ps2sdk runtime does not free `argv` (it does not, on PS2 EE).
- `setLuaBootPath` and `setAppDirFromPath` are separate functions; both call `NormalizeDirPath`. Boot path and app dir can differ when argv[0] does not include a directory (e.g., bare filename).

---

### 3.8 CI Pipeline (`compilation.yml`)

**Not read in full during this audit pass, but cross-referenced from docs:**
- Compiles in `ps2dev/ps2dev:latest` container.
- Checks that `src/elf_loader/loader.c` matches the regenerated child loader.
- Checks for embedded runtime markers in the final ELF.
- Packages `PS1_POPSLOADER/*` + `POPS/PATCH_5.BIN` + `PS1_POPSLOADER/BUILD_INFO.txt`.
- `opencode.yml` is a separate comment-triggered AI workflow; it is NOT a build gate.

---

## 4. Cross-Cutting Concerns

### 4.1 PFS Slot Tracking
- Slots 0–3 are tracked via `PLDR.HDD.MOUNT_TRACKER` in Lua.
- Pre-exec, `PrepareForExternalELFLaunch()` unmounts non-keep slots via `UMountHddPartitionTracked()` and sets `System.setExecKeepPfsMask()`.
- C-side `unmount_pfs_slots_for_exec()` then unmounts any remaining non-keep slots before the final `ExecPS2`.
- This two-layer unmount is belt-and-suspenders: Lua side should ideally have already done the work, but C side catches any mismatch.

### 4.2 Embedded Asset Pipeline
- `asm/asset_*.c` files are auto-generated by `bin2c` during `make`.
- Lua scripts (`system.lua`, `ui.lua`, `images.lua`, `pops_profiles.lua`) are embedded as C arrays and loaded from memory; no loose-file Lua loading at runtime.
- `src/embed_assets.cpp` registers assets and provides the `boot.lua` injected source string.

### 4.3 BOOT.ELF Exit — Current State

The following is the **full known failure history** for BOOT.ELF exit, consolidated from repository docs:

| Candidate | Route | Hardware Result |
|---|---|---|
| `System.loadELF(elf_path, reboot_iop, elf_path)` | Original — LoadExecPS2 | Black screen / hang |
| `System.loadELF(elf_path, 0)` | Non-reboot LoadExecPS2 | Black screen / hang |
| Candidate C: SifExitRpc/Cmd + FlushCache before LoadExecPS2 | LoadExecPS2 with extra teardown | Black screen / hang. Reverted. |
| `ExecuteViaEmbeddedLoader("", resolved_path, 0, NULL)` for exact mc0/mc1 paths | BRAM embedded loader | Black screen / hang |
| Current source: `System.loadELF(elf_path, 0)` always | Non-reboot, `reboot_iop` computed but not passed | **Source defect confirmed (reboot_iop always 0)** |

**Root hypothesis not yet ruled out:** wLaunchELF (`BOOT.ELF`) requires a clean IOP module environment (specifically: only rom0:SIO2MAN + rom0:MCMAN + rom0:MCSERV, no BDM/USB/ds34/audsrv residue). The full IOP reboot path (`LoadELFFromFileExecPS2RebootIOPWithPartition` non-HDD branch) is the only candidate that issues `SifIopReset` + reloads stock MC modules before `ExecPS2`. This path has **never been tested in isolation for BOOT.ELF** on current source.

---

## 5. Stale / Leftover Files

| File | Risk | Recommendation |
|---|---|---|
| `src/elf_loader/src/elf.c.orig` | May confuse future AI agents; not in build | Remove or gitignore |
| `bin/POPSLDR/ui.lua.backup-before-notif-audit-20260523-053651` | Untracked; not in build | Remove |
| `bin/POPSLDR/ui.lua.backup-before-wraptext-repair-20260523-053913` | Untracked; not in build | Remove |
| `bin/POPSLDR/uibeforeclauddesign.lua` | Untracked; not in build; pre-redesign backup | Remove |

---

## 6. Documentation / Source Sync Gaps

| Doc | Claim | Source Reality |
|---|---|---|
| Earlier docs (pre-audit) | Child loader avoids `snprintf`/`strncat` | `loader.c` uses both in `build_default_target_arg0()` and `read_embedded_loader_metadata()` |
| `STATE.md` | BOOT.ELF exit uses `reboot_iop = 1` when HDD loaded | Source computes `reboot_iop` but passes `0` to `System.loadELF`; `reboot_iop` is never used |
| `ARCHITECTURE.md` line 119 | `BOOT.ELF` after HDD runtime initialization is a connected concern labeled `U-10` | Correct; consistent |
| `DECISIONS.md` 2026-03-06 | Settings persist as a transaction | Source-confirmed correct |
| `DECISIONS.md` 2026-05-22 | B2 dynamic PFS unmount fix in loader.c | Source-confirmed present in `loader/src/loader.c` (is_hdd_partition_context branch) |

---

## 7. Recommended Next Steps (Not Prescriptive)

The following are **observations only**. All changes require user approval before implementation.

1. **Fix the `reboot_iop` dead-code bug in `LaunchBootElf()`.**
   `reboot_iop` is computed but never used. The call `System.loadELF(elf_path, 0)` should be `System.loadELF(elf_path, reboot_iop)` if the conditional-reboot intent is real. This is a one-character diff and a clear source defect. Whether it helps on hardware is `Unknown (verify on hardware)`.

2. **Remove stale backup/leftover files** from the working tree to reduce confusion for future agents and developers.

3. **Remove `src/elf_loader/src/elf.c.orig`** or move it to a `docs/` or `artifacts/` reference location.

4. **Hardware retest sequence** (per `HDD_POPSTARTER_HANDOFF.md` recommended order):
   - D-15 first (USB POPSTARTER + HDD game) to confirm no regression.
   - D-10 normal X (HDD POPSTARTER + HDD game).
   - U-10 (BOOT.ELF after HDD page init) as separate result.

5. **Record all results in `QA_REGRESSION_MATRIX.md`.**

---

## 8. Audit Scope and Limitations

- This is a **source-only** audit. No hardware execution was performed.
- Lua code was inspected by grep and targeted view; not all 4800+ lines of `system.lua` or 3587+ lines of `ui.lua` were read.
- The full `QA_REGRESSION_MATRIX.md` (40 KB) was not read line-by-line; hardware claims are taken from `STATE.md` and `HDD_POPSTARTER_HANDOFF.md` which summarize it.
- IRX modules in `iop/embed/` and `bin/POPSLDR/` were not disassembled; they are treated as opaque blobs.
- The embedded loader blob `src/elf_loader/loader.c` (6.4 MB generated C array) was not inspected; the compiled source `loader/src/loader.c` was read in full.

---

*Audit-only pass. No source files were modified.*
