Source changes (dormant parity infra, retained from iterate 2.AI/2.AO): - xenia-kernel/exports.rs: nt_create_event manual_reset polarity + related event wiring - xenia-gpu/mmio_region.rs: D1MODE_VBLANK_VLINE_STATUS hardcode parity Also lands the audit-runs/ analysis notes (.md/.txt/.json digests) for the iterate 2.x VSync/0x10e8/0x1004 wedge investigation. Raw trace dumps (.jsonl/.gz/.csv/.stdout) and agent worktrees (.claude/) are gitignored as regenerable local artifacts — see memory + HANDOFF for the running findings. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
79 lines
3.1 KiB
Diff
79 lines
3.1 KiB
Diff
# Phase C — fix patch
|
|
|
|
The fix is in the **diff/snapshot infrastructure**, not in either
|
|
engine's XEX loader. No engine bug was found; the Phase B STOP
|
|
invariant was over-strict.
|
|
|
|
## Files modified
|
|
|
|
1. `xenia-rs/tools/diff-state/diff_state.py` — relaxed STOP invariant.
|
|
When `--xex-json` is supplied AND both snapshots have `image.bin`,
|
|
compute `image_canonical_sha256` (XEX import slots masked) and check
|
|
that as the STOP key. The raw `image_loaded_sha256` is reported but
|
|
informational.
|
|
2. `xenia-rs/crates/xenia-kernel/src/phase_b_snapshot.rs` — when
|
|
`phase_b_dump_section_content` is set, also write `image.bin` with
|
|
raw bytes of the XEX-image region. Default-off; inert when cvar OFF
|
|
(cvar-OFF digest byte-identical to pre-Phase-C baseline).
|
|
3. `xenia-canary/src/xenia/kernel/phase_b_snapshot.cc` — same.
|
|
|
|
## Diff (relative to pre-Phase-C state)
|
|
|
|
Generated via `git diff --no-index` against an unmodified baseline. The
|
|
full unified diffs are below; see also re-validation.md for proof both
|
|
engines still build and all gates pass.
|
|
|
|
--- /dev/fd/63 2026-05-13 22:41:06.597568277 +0200
|
|
+++ /dev/fd/62 2026-05-13 22:41:06.596568265 +0200
|
|
@@ -1,2 +1,25 @@
|
|
let _ = write_file(&engine_dir.join("manifest.json"), &body);
|
|
+
|
|
+ // Phase C: when dump_section_content is on, write raw bytes of the
|
|
+ // XEX image region to <engine_dir>/image.bin. This is the only
|
|
+ // region positionally matched between canary and ours, so it's the
|
|
+ // only one suitable for byte-level diff.
|
|
+ if state.phase_b_dump_section_content && state.image_base != 0 {
|
|
+ let mut sz: u32 = 0;
|
|
+ let mut a = state.image_base;
|
|
+ while mem.is_mapped(a) {
|
|
+ sz = sz.wrapping_add(4096);
|
|
+ let next = a.wrapping_add(4096);
|
|
+ if next < a {
|
|
+ break;
|
|
+ }
|
|
+ a = next;
|
|
+ }
|
|
+ if sz > 0 {
|
|
+ let bytes = read_bytes(mem, state.image_base, sz);
|
|
+ if let Err(e) = std::fs::write(engine_dir.join("image.bin"), &bytes) {
|
|
+ tracing::warn!("phase_b_snapshot: image.bin write failed: {}", e);
|
|
+ }
|
|
+ }
|
|
+ }
|
|
}
|
|
|
|
---canary phase_b_snapshot.cc change (only the appended block):
|
|
// Phase C: when dump_section_content is on, write raw bytes of the
|
|
// XEX image region to <engine_dir>/image.bin. This is the only
|
|
// region positionally matched between canary and ours, so it's the
|
|
// only one suitable for byte-level diff.
|
|
if (cvars::phase_b_dump_section_content) {
|
|
auto exec_module = kstate->GetExecutableModule();
|
|
if (exec_module) {
|
|
uint32_t image_base = exec_module->xex_module()->base_address();
|
|
uint32_t image_size = exec_module->xex_module()->image_size();
|
|
uint8_t* host =
|
|
kstate->memory()->TranslateVirtual<uint8_t*>(image_base);
|
|
if (host && image_size > 0) {
|
|
std::filesystem::path ip = engine_dir / "image.bin";
|
|
std::FILE* bf = std::fopen(ip.string().c_str(), "wb");
|
|
if (bf) {
|
|
std::fwrite(host, 1, image_size, bf);
|
|
std::fflush(bf);
|
|
std::fclose(bf);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|