Files
xenia-rs/audit-runs/phase-b-state-equivalence/ours-changes.md
MechaCat02 ef93a4fa14 handoff: VSync/event-wedge fixes + iterate 2.A–2.BC research notes
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>
2026-06-05 07:19:08 +02:00

62 lines
4.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Phase B — ours changes inventory
All instrumentation is additive and cvar-gated default-off. With
`KernelState::phase_b_snapshot_dir == None` (the default), the
worker_prologue hook is one Option-tag test; the emitter module is
unreached. Gate 1 verified `xenia-rs check --stable-digest -n 50M`
produces a byte-identical digest pre/post-patch (see `validation.md`).
## New files
- [crates/xenia-kernel/src/phase_b_snapshot.rs](../../../crates/xenia-kernel/src/phase_b_snapshot.rs) — emitter for all five snapshot files + manifest. Stdlib `serde_json` + `sha2`; no new transitive deps beyond what was already pulled into the workspace. ~590 LOC.
- [tools/diff-state/diff_state.py](../../../tools/diff-state/diff_state.py) — stdlib-only Python. Reads both engines' snapshot dirs, classifies divergences by class (σ-structural, δ-content, γ-kernel-content, κ-cache, ε-host-allocator, τ-host-timing), enforces STOP gate on `image_loaded_sha256`/`xex_entry_point`/`iso_sha256`. ~380 LOC.
- [tools/diff-state/README.md](../../../tools/diff-state/README.md) — usage + rules reference.
## Modified files
### [crates/xenia-app/src/main.rs](../../../crates/xenia-app/src/main.rs)
- Around line 251: three new `Exec` flags — `--phase-b-snapshot-dir <DIR>`, `--phase-b-snapshot-and-exit`, `--phase-b-dump-section-content`.
- Around line 420: env-var fallback (`XENIA_PHASE_B_SNAPSHOT_DIR`, `XENIA_PHASE_B_SNAPSHOT_AND_EXIT`, `XENIA_PHASE_B_DUMP_SECTION_CONTENT`); plumbed through `cmd_exec` (signature gained three trailing args).
- Around line 945: `kernel.entry_pc = entry; kernel.phase_b_snapshot_dir = …;` etc. — feeds the resolved values to `KernelState` for the hook to read.
- Around line 2228 (`worker_prologue`): single hook call into `xenia_kernel::phase_b_snapshot::fire_if_entry_thread(kernel, mem, pc, current_tid)`, gated by `kernel.phase_b_snapshot_dir.is_some()` (zero-cost when None).
- `cmd_check` updated to thread three `None`/`false` defaults so the golden digest path stays unaffected.
### [crates/xenia-kernel/src/state.rs](../../../crates/xenia-kernel/src/state.rs)
- Four new public fields on `KernelState`: `phase_b_snapshot_dir: Option<PathBuf>`, `phase_b_snapshot_and_exit: bool`, `phase_b_dump_section_content: bool`, `entry_pc: u32`. Default-constructed `None`/`false`/`0`.
### [crates/xenia-kernel/src/lib.rs](../../../crates/xenia-kernel/src/lib.rs)
- Adds `pub mod phase_b_snapshot;` to the module list (alphabetical position after `objects`).
### [crates/xenia-kernel/Cargo.toml](../../../crates/xenia-kernel/Cargo.toml)
- New dependencies: `serde_json` (workspace), `sha2` (workspace, newly added), `libc = "0.2"` (for `_exit`).
### [Cargo.toml](../../../Cargo.toml) (workspace)
- New `sha2 = "0.10"` workspace dependency.
## Snapshot mechanism
When `phase_b_snapshot_dir` is `Some`, the hook in `worker_prologue` calls
`fire_if_entry_thread` exactly once. The helper:
1. Fast-path early-returns when `phase_b_snapshot_dir == None` (Option-tag check).
2. Returns if `DONE` is already set (subsequent slot visits).
3. Returns if `pc != entry_pc || current_tid != INITIAL_GUEST_TID` (this slot visit is not the entry thread's first instruction).
4. CAS-claims `CLAIMED` (one-shot guard against any race).
5. Calls `write_snapshot`, which builds five `serde_json::Value` trees, serializes each with `serialize_sorted` (a deterministic walker that sorts object keys via `BTreeMap`-equivalent), writes each via `File::create + flush + sync_all`, indexes the SHA-256s into `manifest.json`.
6. If `phase_b_snapshot_and_exit`, calls `libc::_exit(0)` so the snapshot is durable and the process terminates before the host scheduler or other threads can perturb on-disk state.
## What's in each snapshot file (ours side)
| file | content |
|---|---|
| `cpu_state.json` | `pc` (= entry_pc), `gpr[32]` (raw u64 hex), `fpr[32]` (raw bit-pattern hex), `vr[128]` + `vscr` (32-hex BE byte order), `cr[8]`, `xer`/`msr`/`ctr`/`lr`/`vrsave`/`fpscr`, `thread_id`, `stack_base/limit`, `tls_base`, `pcr_base`. |
| `memory.json` | `regions[]` — named ranges (XEX image, main stack, PCR, TLS) each with SHA-256. `heaps[]` — 4 heap descriptors with committed-page histograms. `committed_pages_total`. |
| `kernel.json` | `objects[]` (sorted by FNV-1a stable `handle_semantic_id`) — type, type_code, details (per-type fields like `thread_id`/`is_entry_thread`). `exports_registered_count/sha256/sample[]`. |
| `vfs.json` | `resolve_path_probes[]` — canonical 10-path probe set. `mounted_devices_observed_count`. `cache_root_listing[]`. |
| `config.json` | `xex_entry_point`, `xex_image_base/size`, `image_loaded_sha256` (the primary cross-engine invariant), `cvars{}`, `host_ns_at_snapshot` / `wall_clock_iso8601` (deterministic_skip-flagged). |