mirror of
https://github.com/Druthulu/BFM-decomp
synced 2026-09-28 06:49:47 -04:00
bd5e21b366
- RE'd the full file-loader/overlay subsystem in Ghidra via MCP: CdReadRequest -> CdReadStateMachine (hand-rolled CdControl SeekL/ReadN reader, NOT PsyQ CdRead); LIST.CD RAM cache cdFileLocTable + ResourceGetCdLoc/resourceIdMap lookup; LZSS staging buffer 0x80079A70; loadDestPtrTable; ~50 symbols named (T1-T5,T8) - T6b MILESTONE: resident blob @0x800CEDF8 + location overlay @0x80128158 proven byte-identical (sha1-equal contiguous prefixes) vs live PCSX-Redux RAM; blobs imported into Ghidra (ImportOverlay.java); overlay-map table -> memory-map.md §4.3 - PCSX-Redux runtime oracle: Windows-native build, WSL reads RAM via the web API at 172.17.208.1:8081; ledger #4 resolved - live-verified player/time state: gold(/10) HP BP day hour tiredness boss-HP; save-header template (Q#5) + debug-menu dispatch (Q#9: DEBUG.BIN path is dead) - overlay map: 13 area-states across SC01/02/03, 2 duplicate pairs, location x chapter keying, free-roam vs menu-hub granularity - resolves Open Q#1/#3/#4/#5/#6/#8/#9/#12; corrects SLUS-90029 (FF8 demo, not BFM) - 2 US prototypes acquired + CRC-verified (Aug-31 1369DE07, Sep-8 5C24728E) - rules R9 (verify persistence), R10 (>=3-datapoint live verification), R11 (runtime oracle Windows-native, bridged to WSL) - bumps project version 1.2.0 -> 1.3.0
160 lines
14 KiB
Markdown
160 lines
14 KiB
Markdown
# PhaseEnd — Phase 3: File-loader & overlay-map RE (+ PCSX-Redux harness)
|
||
**Date:** 2026-06-14 · **Project Version:** 1.3.0 · **Phase Status:** Complete
|
||
|
||
## Build Log
|
||
|
||
**Files created/changed and complete — do not recreate:**
|
||
- `tools/ghidra_mcp_start.sh` / `ghidra_mcp_stop.sh` / `ghidra_mcp_verify.sh` — oracle lifecycle: start
|
||
detached headless MCP server / clean save+stop (the ONLY way headless MCP writes persist) / read-only
|
||
R9 verify. Used every RE session.
|
||
- `tools/ghidra_scripts/BfmMcpServer.java` — headless MCP server + commit-on-clean-shutdown; run by `start.sh`.
|
||
- `tools/ghidra_scripts/GetSymbolAt.java` — read-only symbol probe consumed by `verify.sh` (R9).
|
||
- `tools/ghidra_scripts/ImportOverlay.java` — headless: loads the proven resident blob (→0x800CEDF8) +
|
||
one location overlay (→0x80128158) into the program (`RAM` block, convertToInitialized+setBytes);
|
||
idempotent. (T7)
|
||
- `tools/ghidra_scripts/VerifyOverlay.java` — read-only R9 check that the imported blob bytes persisted. (T7)
|
||
- `tools/ghidra_scripts/ExportSymbols.java` + **`config/symbols.us.txt`** — headless export of all 967
|
||
USER_DEFINED symbols (PsyQ-signature names + manual RE) to committed text — the durable, diffable,
|
||
re-importable record of the RE work (the `.rep` is gitignored); Phase-5 splat input. (phase-close)
|
||
- **`dumps/INDEX.md`** + `dumps/*.bin` — the 28-dump live RAM corpus, **committed** (H1 relaxed while
|
||
private; static, not regenerable, off-machine backup); INDEX maps each dump → state. (phase-close)
|
||
- `.gitignore` — added `/tools/pcsx-redux/` (AppImage), `/.run/` (runtime scratch); dumps committed.
|
||
- `.claude/settings.local.json` — SessionStart hook that auto-starts the oracle. (T0)
|
||
- **`/tmp` → project-local migration:** `ghidra_mcp_start.sh`/`stop.sh` + `BfmMcpServer.java` now use
|
||
`~/bfm-decomp/.run/{ghidra-mcp.log,mcp-stop.req}` (no `/tmp`); full start/stop/save/R9 cycle re-certified. (R12)
|
||
- `docs/memory-map.md` — **the phase's main written deliverable.** Added: the T1 "imported into Ghidra"
|
||
block; the T2 (CdRead chain) / T3 (LIST.CD cache+lookup) / T4 (LZSS staging) / T5 (US load addresses) /
|
||
T6b (MILESTONE proof) blocks; **§4.3 overlay-map table (13 area-states + the loader model)**; §3.4
|
||
player-state promoted to `verified` (gold/HP/BP/day/hour/tiredness-raw) + refutations; §2.3
|
||
`saveHeaderTemplate`; §5 debug-menu dispatch; Open Questions **#1,#3,#4,#5,#6,#8,#9,#12 resolved**;
|
||
SLUS-90029 corrected (FF8 demo, not BFM).
|
||
- `docs/SETUP.md` — §3 PCSX-Redux as-built (Windows-native + WSL web-API bridge); ledger #4 RESOLVED
|
||
(web server :8081, dump URL).
|
||
- `phase-ends/CURRENT_PHASE.md` — **absorbed into this file and deleted** (P8).
|
||
- `phase-ends/PhaseEnd_Phase3.md` — this file.
|
||
|
||
**Local artifacts (gitignored / outside repo — present on this machine, do NOT recreate; a fresh clone redoes them):**
|
||
- `~/bfm-decomp/ghidra/bfm.{gpr,rep}` — the saved Ghidra project. `SLUS_007.26` now carries the T1 seeds
|
||
**plus ~50 Phase-3 symbols**: loader cluster (`LoaderInitFileTable`, `CdReadRequest`,
|
||
`CdReadStateMachine`, `CdReadSectorReadyCB`, `CdQueueBusy`, `cdReq_*` control block), resource loader
|
||
(`ResourceLoadStateMachine`, `ResourceGetCdLoc`, `resourceIdMap`, `resLoad_*`), `cdFileLocTable`,
|
||
`listCdBuffer`, `lzss_sectorStagingBuf`, `StreamLoadStateMachine`, `loadDestPtrTable`,
|
||
`GameModeDispatch`+`gameModeHandlerTable`, `DebugMenuHandler`, `SaveLoadRoutine`, `saveHeaderTemplate`,
|
||
`debugBinPresent`, player-state fields — **plus 2 imported memory blocks** (resident blob @0x800CEDF8,
|
||
tut_forest overlay @0x80128158). R9-verified; DB saved (clean shutdown).
|
||
- `tools/pcsx-redux/PCSX-Redux-HEAD-x86_64.AppImage` — Linux AppImage (downloaded; **NOT used** — WSLg
|
||
display + WSL controller failed; the Windows-native build is the actual oracle). Gitignored.
|
||
- `disks/` — 2 CRC-verified US prototypes (**Aug-31-1998 "Musashi Demo" 1369DE07**, **Sep-8-1998 "Musashi
|
||
Master" 5C24728E**) + a "Squaresoft on PlayStation Vol.2 (FF8 Demo)" disc. Gitignored.
|
||
|
||
**Tools/packages installed:**
|
||
- **PCSX-Redux** (runtime oracle). The Linux AppImage was fetched to `tools/pcsx-redux/` but is unused;
|
||
the **Windows-native build** (`distrib.app/.../dev-win-x64`) is what runs — web server on :8081, reached
|
||
from WSL at **172.17.208.1:8081** (NAT gateway). Ships OpenBIOS (no BIOS dump needed).
|
||
- **usbipd-win** (Windows, installed by Drew) — attempted DualSense→WSL passthrough; abandoned (WSL2 kernel
|
||
has no `CONFIG_HID_PLAYSTATION`/`joydev`) in favour of the Windows-native emulator.
|
||
|
||
**Verification results (literal):**
|
||
- **MILESTONE byte-proof (live PCSX-Redux RAM):** resident `MAIN.CD/FILE_010/1.1` @0x800CEDF8 = **18,788-byte
|
||
contiguous exact prefix, sha1 `dbc55765593d3c157965a22af5808990714dbae9`** (RAM slice == extracted, EQUAL);
|
||
overlay `SC01/FILE_077/0.4.dec` @0x80128158 = **389,400-byte contiguous exact prefix, sha1
|
||
`8e40afab29200f00752573bfc28f9a8676000f85`** EQUAL. EXE resident: RAM[0x10000:] == extracted
|
||
`SLUS_007.26`[0x800:] (8192/8192).
|
||
- **R9 persistence verifies — all PASS:** T1 (`CdPathTable`, db.5); checkpoint#1 (`StreamLoadStateMachine`);
|
||
#2 (`loadDestPtrTable`); T7 (`VerifyOverlay` — both blobs init=true, bytes correct); #3 (`DebugMenuHandler`).
|
||
- PCSX-Redux web API `GET :8081/api/v1/cpu/ram/raw` → exactly **2,097,152 B**.
|
||
- **Overlay map:** 13 area-states identified by RAM-vs-extracted byte-match across **SC01/SC02/SC03**;
|
||
2 duplicate-overlay pairs (`SC02/000≡003`, `SC01/005≡006`).
|
||
- **Player/time state live-verified** (multi-datapoint / controlled diff): `gold` 0x80078E8C (÷10),
|
||
`hp_max/cur` 0x80078EB2/EB4, `bp_max/cur` 0x80078EB6/EB8, `dayCounter` 0x80078EAC, `hour` 0x80078EB1,
|
||
`tiredness_raw` 0x80078EA4, `bossHp_SteamKnight` 0x801E4398. **Four 2-datapoint false positives caught
|
||
and refuted** (clock 0x8007CE82, two tiredness guesses, a dow byte) → see R10.
|
||
- `git status`: only docs + tooling/scripts tracked; all ROM-derived (`ghidra/`, `disks/`, extracted bulk,
|
||
the PCSX AppImage) gitignored.
|
||
|
||
**Milestone achieved:** `docs/memory-map.md §4.3` holds a loader/overlay table where the resident blob
|
||
(0x800CEDF8) and a location overlay (0x80128158) have US load addresses **proven byte-identical** (sha1-equal
|
||
contiguous prefixes) against a **live PCSX-Redux RAM dump** — the project's central "what loads where"
|
||
unknown, resolved.
|
||
|
||
**Next:** **Phase 4 = PROTOTYPE RESEARCH SPIKE** (Drew's directive — supersedes the roadmap's "build
|
||
toolchain" as the *next* phase; toolchain follows). Start with a symbol/debug-info hunt in the Aug-31
|
||
"Musashi Demo". See "Notes for Future Phases" below for the full brief.
|
||
|
||
## Deviations
|
||
|
||
| Item | Plan | Actual | Reason |
|
||
|---|---|---|---|
|
||
| Runtime-oracle location | PCSX-Redux under WSLg (all-in-WSL) | **Windows-native** PCSX-Redux; WSL fetches RAM via 172.17.208.1:8081 | WSLg wouldn't paint the window; WSL2 kernel can't do the DualSense. Hybrid bridged by the web API (→ R11) |
|
||
| Overlay-mapping scope | ≥1 overlay (milestone) | 13 area-states across SC01/02/03 + full loader model | Drew-driven live tour; high value for Gen2 overlay configs |
|
||
| Player-state RE | not in plan | gold/HP/BP/day/hour/tiredness/boss-HP verified; save-header found | Opportunistic live triangulation (Drew fed ground truth) |
|
||
| Prototypes | parking lot | 2 US protos acquired + CRC-verified; FF8 demo disc | Drew acquired them; seed the Phase-4 spike |
|
||
| Next phase | Phase 4 = build toolchain (roadmap) | Phase 4 = prototype research spike | Drew's directive — assess proto value before matching |
|
||
| T6b proof form | "sha1 of dump slice == sha1 of extracted blob" (whole blob) | sha1-equal large **contiguous prefix** (runtime data diverges past the code) | Runtime writes mutate the blob's data after load; the code prefix is byte-identical at the exact vaddr — conclusive for the load address (P9) |
|
||
| `.DA`/proto context | — | SLUS-90029 corrected to FF8 demo (not a BFM demo); no playable US BFM demo exists | Drew correction + web research |
|
||
|
||
## Commit Message
|
||
```
|
||
feat(phase-3): file-loader & overlay-map RE + PCSX-Redux runtime oracle
|
||
|
||
- RE'd the full file-loader/overlay subsystem in Ghidra via MCP: CdReadRequest ->
|
||
CdReadStateMachine (hand-rolled CdControl SeekL/ReadN reader, NOT PsyQ CdRead);
|
||
LIST.CD RAM cache cdFileLocTable + ResourceGetCdLoc/resourceIdMap lookup; LZSS
|
||
staging buffer 0x80079A70; loadDestPtrTable; ~50 symbols named (T1-T5,T8)
|
||
- T6b MILESTONE: resident blob @0x800CEDF8 + location overlay @0x80128158 proven
|
||
byte-identical (sha1-equal contiguous prefixes) vs live PCSX-Redux RAM; blobs
|
||
imported into Ghidra (ImportOverlay.java); overlay-map table -> memory-map.md §4.3
|
||
- PCSX-Redux runtime oracle: Windows-native build, WSL reads RAM via the web API
|
||
at 172.17.208.1:8081; ledger #4 resolved
|
||
- live-verified player/time state: gold(/10) HP BP day hour tiredness boss-HP;
|
||
save-header template (Q#5) + debug-menu dispatch (Q#9: DEBUG.BIN path is dead)
|
||
- overlay map: 13 area-states across SC01/02/03, 2 duplicate pairs, location x
|
||
chapter keying, free-roam vs menu-hub granularity
|
||
- resolves Open Q#1/#3/#4/#5/#6/#8/#9/#12; corrects SLUS-90029 (FF8 demo, not BFM)
|
||
- 2 US prototypes acquired + CRC-verified (Aug-31 1369DE07, Sep-8 5C24728E)
|
||
- rules R9 (verify persistence), R10 (>=3-datapoint live verification),
|
||
R11 (runtime oracle Windows-native, bridged to WSL)
|
||
- bumps project version 1.2.0 -> 1.3.0
|
||
```
|
||
|
||
## Rules Added This Phase
|
||
|
||
| Rule | Reason |
|
||
|---|---|
|
||
| **R9 — Verify Ghidra persistence after every save-shutdown.** Read-only re-open (`tools/ghidra_mcp_verify.sh <addr> <name>`) and confirm a recent edit survived — never trust "Save succeeded" alone. Mandatory at phase end; recommended at each checkpoint. | Headless MCP writes persist only on clean shutdown; the live server holds an open transaction. Catches a lost save before it strands work. (Candidate since this phase; formalized.) |
|
||
| **R10 — Multi-datapoint live-RAM verification.** A RAM-address finding from PCSX-Redux is `verified` only with **≥3 consistent datapoints** OR a **controlled before/after diff** (e.g. paused snapshots, sleep reset). Two-datapoint matches stay `candidate` (coincidence-prone). | Four 2-datapoint false positives this phase (clock 0x8007CE82, two tiredness guesses, a day-of-week byte) were each disproven by a 3rd datapoint. Aligns G1/P9 (bytes are truth). |
|
||
| **R11 — Runtime oracle is Windows-native, bridged to WSL via the web API** (`http://172.17.208.1:8081`). Build, Ghidra, splat, asm-differ, analysis all stay in WSL (R2/H2 unchanged for those); only the emulator GUI + controller live on Windows — the explicit all-in-WSL exception. | WSLg can't render PCSX-Redux and the WSL2 kernel can't expose a DualSense; the web API is a clean, low-friction WSL↔Windows boundary that preserves the rest of the architecture. |
|
||
| **R12 — No `/tmp`; project-local data only.** All project data — including transient runtime scratch (logs, sentinels, temp outputs) — lives under `~/bfm-decomp` (runtime scratch → `.run/`, gitignored). Never `/tmp`. | Drew directive 2026-06-14: `/tmp` is volatile (28 non-regenerable RAM dumps nearly lost on a reboot). Keeps the clone self-contained and durable. |
|
||
|
||
## PhaseEnd Changelog
|
||
**v1.2.0 → v1.3.0** — Phase 3 complete. The file-loader/overlay subsystem is fully reverse-engineered in
|
||
Ghidra and the central "what loads where" unknown is **byte-proven against live hardware behavior**: the
|
||
resident blob (0x800CEDF8) and location overlays (0x80128158) load position-locked and verbatim; the loader
|
||
is a hand-rolled `CdControl` async reader (not PsyQ `CdRead`) driven by `cdFileLocTable` (the parsed LIST.CD
|
||
TOC) + a two-level resource-ID map. A live overlay map of 13 area-states across SC01/SC02/SC03 was captured
|
||
(duplicate overlays, location×chapter keying, free-roam-vs-menu-hub granularity). PCSX-Redux stood up as the
|
||
runtime oracle (Windows-native, WSL web-API bridge). Bonus live-verified the player/time state block
|
||
(gold÷10, HP/BP, day, hour, tiredness) and the save-header (Q#5) + debug-menu dispatch (Q#9: DEBUG.BIN dead).
|
||
Open Questions #1/#3/#4/#5/#6/#8/#9/#12 resolved. Three rules added (R9 persistence, R10 multi-datapoint
|
||
verification, R11 Windows-native oracle). Two US prototypes acquired + CRC-verified, seeding the Phase-4 spike.
|
||
|
||
## Notes for Future Phases — Phase 4 RESEARCH SPIKE brief (Drew's directive)
|
||
|
||
Analyze the two CRC-verified US prototypes (`disks/`) **before** the build/matching phases:
|
||
1. **Debug info?** Hunt the Aug-31 "Musashi Demo" + Sep-8 "Musashi Master" for `.SYM`/symbol tables, debug
|
||
strings, assertion/source-path text, less-stripped data. (Hidden Palace said "no symbols" — UNVERIFIED.)
|
||
2. **Is the demo easier to decomp, and does it help the full game?** Assess optimization level vs retail.
|
||
**Caveat:** demo ≠ retail bytes → demo *matches don't transfer* to SLUS-00726; value is **labels + a
|
||
readable reference + shared tables**, not matched bytes.
|
||
3. **Free-label lead (already identified):** the Aug-31 demo's title scene/area-select very likely shares
|
||
code/tables with the retail debug menu mapped in T8 — `GameModeDispatch` (0x80010B40),
|
||
`gameModeHandlerTable` (0x800629F4), `DebugMenuHandler` (0x80011144). Binary-diff to lift labels in.
|
||
4. **Deliverable:** a go/no-go on whether the protos accelerate Gen1 matching, plus any labels imported.
|
||
This is a **roadmap insertion** before Phase 4 (build toolchain), which then follows. Also outstanding for
|
||
later: the save-data block format (trace `SaveLoadRoutine` 0x8002B154, Q#5); the exact tiredness-% / minute /
|
||
day-vs-dow encoding; importing more overlays as Ghidra overlay address spaces (Gen2).
|
||
|
||
## 🛑 Stop Here
|
||
PhaseEnd written; `CURRENT_PHASE.md` absorbed. **Drew commits AND pushes** this PhaseEnd (R6/R8). Start a
|
||
fresh session for the next phase. Keep this file forever.
|