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.
This commit is contained in:
@@ -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.
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user