This reverts commit b836f2198c.
7.2 KiB
Relocation Manifest Format
STATUS AMENDMENT (2026-07, BIOS profiles). The bulk boot-time ROM-to-RAM copy case this document originally targeted is now carried by the BIOS profile instead:
[[recompiler.address_model.copy]]inbios/<STEM>.toml(single source of truth for the recompiler, the emitted C, and the runtime viapsx_bios_image; seerecompiler/src/bios_address_model.h). The kernel-bless mechanism inmemory.cremains the runtime enforcement of the "verify live RAM against the ROM source before dispatching AOT code" contract described here. This document stays authoritative ONLY for the oracle-observed case — regions withsrc_rom_addr: nullthat cannot be seen statically — which remains unimplemented.
Status: Phase B (design + first iteration), 2026-04-30.
File on disk: generated/address_aliases.json.
Authority: PLAN.md:941-967 ("BIOS Relocation Is a Hard Gate"), CLAUDE.md:333-365 (Rule 18).
Companion files: generated/normalization_rule.md, generated/relocation_proofs/<name>/.
Purpose
Records every region of code that lives at a RAM address at runtime but
that the static recompiler cannot see in SCPH1001.BIN byte-for-byte
at compile time. Two flavors:
- ROM↔RAM aliases. BIOS copies bytes from
0xBFCxxxxxto a kernel-RAM address during init and runs the RAM copy. Same bytes, two addresses. - Trace-discovered RAM regions. BIOS installs code at a RAM address via a mechanism we may not have statically identified (relocated copy, patched copy, runtime-assembled, etc.). We have observed bytes via the oracle.
Both flavors share one record shape so the recompiler can ingest them
uniformly. The discovered_by field records how the entry was proven.
File shape
generated/address_aliases.json:
{
"version": 1,
"normalization_rule": "addr & 0x1FFFFFFF",
"entries": [ /* AliasEntry[] */ ]
}
version increments on incompatible schema changes. normalization_rule
mirrors generated/normalization_rule.md so the recompiler can check
agreement at load time.
AliasEntry
| Field | Type | Required | Notes |
|---|---|---|---|
name |
string | yes | Slug, used as proof-directory name and as part of emitted function names. [a-z0-9_]+. |
dst_ram_addr |
hex string | yes | Physical RAM address (post-normalization). E.g. "0x00005800". Recompiled function dispatch keys are derived from this. |
length |
int | yes | Byte length of the region. Must be a multiple of 4 (MIPS instruction size). |
entrypoints |
array of hex string | yes | RAM addresses at which psx_dispatch may enter this region. The recompiler emits a separate compiled function per entrypoint. At least one entry, must include dst_ram_addr if the region's first instruction is callable. |
bytes_hash |
string | yes | sha256:<64 hex chars> of the region bytes. Runtime verifies against live RAM before dispatching the AOT function. |
bytes_file |
string | yes | Path (relative to repo root) to the raw bytes file under generated/relocation_proofs/<name>/bytes.bin. Recompiler reads from here when src_rom_addr is null. |
src_rom_addr |
hex string | optional | Physical ROM address the bytes were copied from, if known. E.g. "0x1FC2D800". When present, recompiler reads from ROM and additionally checks ROM[src..src+length] hash matches bytes_hash. |
discovered_by |
object | yes | Provenance. See below. |
discovered_by
| Field | Type | Required | Notes |
|---|---|---|---|
tool |
string | yes | Identifier of the oracle / static tool. E.g. "beetle_psx_oracle", "ghidra_static_copy_loop", "recomp_install_hook_log". |
writer_pc |
hex string | null | when known | PC of the instruction that wrote the LAST byte of this region during install. null if not observed. |
first_exec_pc |
hex string | null | when known | First PC inside this region that the oracle executed. Useful for cross-validating entrypoints[0]. |
reason |
string | yes | One-line human explanation of why this region matters and what evidence drove its inclusion. |
captured_at |
ISO-8601 date | yes | When the proof was captured. |
captured_session |
string | optional | Free-form session/commit reference. |
Proof directory
Per PLAN.md every entry must have a directory generated/relocation_proofs/<name>/
containing:
| File | Required | Purpose |
|---|---|---|
proof.json |
yes | Canonical record of the entry (full AliasEntry plus extra evidence fields). |
bytes.bin |
yes | Raw bytes of the region, exactly length bytes. |
wtrace_excerpt.json |
when discovered_by.tool=oracle | Slice of the Beetle wtrace ring covering the writer events. |
dispatch_excerpt.json |
optional | Slice of recomp dispatch_tail showing the gap (we never dispatched these PCs). |
ghidra_*.{json,png} |
when discovered_by.tool starts with ghidra | Static analysis artifact. |
address_aliases.json is GENERATED from the proof directories — never
hand-edited. A small tool (tools/build_address_aliases.py, Phase C)
walks generated/relocation_proofs/, validates each proof.json +
bytes.bin, and emits the top-level manifest.
Normalization
Working rule (per PLAN.md Phase 1e draft): normalized = addr & 0x1FFFFFFF.
Handles the four PSX address-space windows:
| Region | Virtual base | Normalized |
|---|---|---|
| KUSEG (raw) | 0x00000000 | self |
| KSEG0 (cached) | 0x80000000 | strip top 3 bits |
| KSEG1 (uncached) | 0xA0000000 | strip top 3 bits |
| BIOS via KSEG1 | 0xBFC00000 | 0x1FC00000 (distinct from RAM) |
So 0x00007568, 0x80007568, 0xA0007568 all normalize to 0x00007568
and refer to the same RAM byte. 0xBFC07568 stays at 0x1FC07568 — a
distinct ROM byte. The recompiler stores all dispatch keys in normalized
form.
First-iteration scope
Today's first manifest entries cover only the two dark RAM windows
identified in docs/CASE_A_AOT_GAP.md:
| name | dst_ram_addr | length | entrypoints |
|---|---|---|---|
memcard_handler_4f00 |
0x00004F00 | 0x100 | 0x4F0C, 0x4F54 |
memcard_handler_5800 |
0x00005800 | 0x800 | 0x5800, 0x5DB8, 0x5DD0, 0x5DD8, 0x5EF4, 0x5FA8 |
Both are flagged discovered_by.tool="beetle_psx_oracle", both have
non-null writer_pc (from the wtrace) and first_exec_pc. Both have
src_rom_addr=null in this iteration — the BIOS source these were
copied from is not yet identified statically. When we identify the
source (e.g. via tracing the BIOS init copy loops in Beetle and
matching them against ROM), we'll set src_rom_addr and drop
bytes.bin from the proof directory.
Future iterations expand coverage and add static src identification.
Failure modes the manifest is designed to catch
- Stale AOT dispatch. If live RAM bytes drift from
bytes_hash, runtime aborts loudly rather than running the wrong code. - Duplicate logical function. If two entries normalize to the
same
dst_ram_addr, the recompiler refuses to build. - Unproven alias. If an entry exists in
address_aliases.jsonbut the matchingrelocation_proofs/<name>/directory is missing or has the wrong hash, the recompiler refuses to build. - Speculative addition. Every entry must point to a proof. No "I think this region exists" entries.