From 2c4bbdc600f3b8bfd7e9b13867dff8db9443acbe Mon Sep 17 00:00:00 2001 From: ReaperOfVeriod Date: Mon, 12 Oct 2026 04:32:07 +0200 Subject: [PATCH] Use PCSX2 RAM to recover the chunk loader's transformation This is what RAM was needed for: nothing about the loader's transformation is recoverable from the disc. Anchor: a 32-byte probe from inside a chunk record in level 0's core_data, searched in the level-0 savestate. It hits at 0x18538a8 and the record's first bytes at 0x185387e -- exactly chunk_base + record_offset, no rescaling. So the chunk payload is copied VERBATIM; unlike collision and the shrub packet tables it is not expanded or repacked. Result 1: the offset table is rewritten to absolute EE addresses. disc: f000057c f00006b0 f00007e4 f0000914 RAM: 0xf185387c 0xf18539b0 0xf1853ae4 0xf1853c14 The 0xf0000000|low24 tag becomes 0xf1850000|low24 -- tag replaced by the chunk's load base, low 24 bits untouched. Consecutive deltas agree exactly (0x134, 0x134, 0x130), which is why the disc-side stride is approximate rather than constant. Result 2: every record gains a constant 2-byte prefix 02 00, and the rewritten table points at THAT rather than at the record data. Walking all 90 records from the RAM dump: prefix 02 00 on 90 of 90; the disc's index bytes preserved unchanged at +2/+3 on 90 of 90. Result 3, the useful one: the byte at +2 takes exactly 0, 16, 32, ... 240 -- the 16 values index_rule predicts for step = 16, phase = 0. The mixed-radix record index derived from the disc is corroborated on the running game's own copy of the chunk. That is a disc-derived claim validated against the game, which is the strongest form of check available here. On disc a chunk is [16-byte header][10 zero bytes][tagged offset table][records]. In RAM it is [16-byte header][10 zero bytes][absolute-pointer table][records each prefixed with 02 00]. The 02 00 is unexplained -- possibly a record type or an alignment the loader needs -- but it is constant, so like the two index bytes it carries no per-record information. --- docs/formats/core-data-regions.md | 24 ++++++++++++++ docs/plan/pcsx2-verification.md | 52 +++++++++++++++++++++++++++++++ 2 files changed, 76 insertions(+) diff --git a/docs/formats/core-data-regions.md b/docs/formats/core-data-regions.md index 0534c55..f766e30 100644 --- a/docs/formats/core-data-regions.md +++ b/docs/formats/core-data-regions.md @@ -1427,3 +1427,27 @@ So 9.4%, and no chunk is a template. Six records looked like a majority because that chunk's tail happens to carry shared constants -- the per-type figures range from 9.4% overall to 55.6% on one type. A pooled figure over all types would have hidden that spread again, so it is reported per type as well. + +## What the loader does to a chunk (from RAM) + +Verified against PCSX2 level-0 RAM; method and full dump in +`plan/pcsx2-verification.md`. + +The chunk payload is copied **verbatim** -- a probe from inside a record hits at +`chunk_base + record_offset` with no rescaling. Two things change around it: + +1. **The offset table is rewritten to absolute EE addresses.** Disc offsets + `0xf000057c, 0xf00006b0, 0xf00007e4, 0xf0000914` become + `0xf185387c, 0xf18539b0, 0xf1853ae4, 0xf1853c14` in RAM. The + `0xf0000000 | low24` tag becomes `0xf1850000 | low24` -- tag replaced by the + load base, low 24 bits untouched. + +2. **Every record gains a constant 2-byte prefix `02 00`,** and the rewritten + table points at *that* rather than at the record data. Measured on all + **90 of 90** records: prefix `02 00` on every one, and the disc's index bytes + preserved unchanged at `+2`/`+3` on every one. + +The third result is the useful one: the byte at `+2` takes exactly +`0, 16, 32, ... 240` -- the 16 values `index_rule` predicts for `step = 16, +phase = 0`. The mixed-radix record index, derived from the disc, is corroborated +on the running game's own copy. diff --git a/docs/plan/pcsx2-verification.md b/docs/plan/pcsx2-verification.md index 26a3416..05fbea8 100644 --- a/docs/plan/pcsx2-verification.md +++ b/docs/plan/pcsx2-verification.md @@ -726,3 +726,55 @@ coincidence inside a short run. **The collision lead in this file is disproved, not merely unproven.** Recorded here so it is not picked up again. Level 1's grid is 384 cells and nothing found so far counts to it. + +## The chunk container: what the loader does to it + +This is what RAM was needed for. Nothing about the loader's transformation is +recoverable from the disc. + +**Anchor.** A 32-byte probe from inside a chunk record in level 0's `core_data` +was searched in the level-0 savestate. It hits at `0x18538a8`, and the record's +first bytes hit at `0x185387e` -- exactly `chunk_base + record_offset`, with no +rescaling. So the chunk payload is copied **verbatim**; it is not expanded or +repacked the way the collision payload and the shrub packet tables are. + +**Result 1 -- the offset table is rewritten to absolute EE addresses.** +Disc, at chunk `0x100b302`: + + offsets[0..3] = f000057c f00006b0 f00007e4 f0000914 + +RAM, in a table at `0x185331c`: + + 0xf185387c 0xf18539b0 0xf1853ae4 0xf1853c14 + +The tagged form `0xf0000000 | low24` becomes `0xf1850000 | low24`: the tag is +replaced by the chunk's load base and the low 24 bits are untouched. The +consecutive deltas agree exactly (`0x134, 0x134, 0x130`, which is why the +disc-side `stride` is approximate rather than constant). + +**Result 2 -- every record gains a constant 2-byte prefix, and the table points +at the prefix.** RAM at each record: + + 0x185387c 02 00 00 00 38 d3 4c 38 ... + 0x18539b0 02 00 10 00 2f bb 4c 38 ... + 0x1853ae4 02 00 20 00 20 8f 4c 38 ... + 0x1853c14 02 00 30 00 14 6f 4c 38 ... + +Walked all **90** records of the chunk from the RAM dump: + + 2-byte prefix : 02 00 on 90 of 90 + disc index bytes preserved at +2/+3 : 90 of 90 + byte at +2, distinct values : 0, 16, 32, ... 240 (16 values) + +**Result 3 -- the disc-side index finding is confirmed against live data.** The +bytes at `+2` take exactly the 16 values `ResolvedChunk::index_rule` predicts for +`step = 16, phase = 0`, stepping 0x00, 0x10, 0x20, ... That is the mixed-radix +record index, measured on 2,430 records from the disc and now corroborated on the +running game's own copy of one chunk. + +**What this means for the format.** On disc, a chunk is +`[16-byte header][10 zero bytes][tagged offset table][records]`. In RAM it is +`[16-byte header][10 zero bytes][absolute-pointer table][records each prefixed +with 02 00]`. The `02 00` is unexplained -- it may be a record type or an +alignment the loader needs -- but it is constant, so it carries no per-record +information either.