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>
This commit is contained in:
MechaCat02
2026-06-05 07:19:08 +02:00
parent acd1656753
commit ef93a4fa14
620 changed files with 108303 additions and 1 deletions

View File

@@ -0,0 +1,110 @@
# Phase C+13 fix.diff — targeted excerpt
# (full tree has many uncommitted prior-phase changes; this file
# documents only the C+13 delta against the pre-C+13 state.)
## crates/xenia-kernel/src/exports.rs
### 1. New helper `is_disc_prefix` (~30 LOC, inserted near `STATUS_OBJECT_NAME_COLLISION`, ~line 1282)
```rust
/// Phase C+13 — does `raw_path` start with a prefix that aliases the
/// (read-only) game disc? Used to scope the synth-empty fallback in
/// `open_vfs_file`: missing disc files report `STATUS_OBJECT_NAME_NOT_FOUND`
/// (matching canary's `NtCreateFile_entry` for game-data lookups), while
/// missing writable-partition paths keep the legacy zero-byte synth.
///
/// Mirrors the disc-mapped subset of `crate::path::DEVICE_PREFIXES`:
/// - `game:\` — canary's symbolic-link alias for the disc
/// (xenia-canary/src/xenia/kernel/kernel_state.cc registrations).
/// - `d:\` / `D:\` — drive-letter alias for the disc.
/// - `\Device\Cdrom0\` — NT device path for the disc.
///
/// Compares case-insensitively to match canary's path resolver.
fn is_disc_prefix(raw_path: &str) -> bool {
let lowered = raw_path.trim_start().to_ascii_lowercase();
const DISC_PREFIXES: &[&str] = &[
"game:\\",
"game:/",
"d:\\",
"d:/",
"\\device\\cdrom0\\",
"\\device\\cdrom0/",
];
DISC_PREFIXES.iter().any(|p| lowered.starts_with(p))
}
```
### 2. `open_vfs_file` — capture raw path (after the `path` initialization, ~line 1314)
```rust
// Phase C+13 — recover the raw (un-stripped) path so we can tell a
// disc-aliased prefix (`game:\`, `d:\`, `\Device\Cdrom0\`) apart from a
// writable-partition prefix (`\Device\Harddisk0\…`, `\??\`, raw "no
// prefix" cases). The synth-empty fallback below covers both today but
// canary's `NtCreateFile_entry` (xboxkrnl_io.cc:83-110) returns the
// VFS lookup status verbatim, which is `STATUS_OBJECT_NAME_NOT_FOUND`
// for any disc path that isn't in the ISO. Scoping the synth to
// non-disc prefixes makes us match canary's behaviour for missing
// game-data files (e.g. `game:\dat\files.tbl` at Phase C+13 idx 103862).
let raw_path = crate::path::object_attributes_raw_name(mem, obj_attrs_ptr)
.unwrap_or_default();
```
### 3. `open_vfs_file` — short-circuit disc paths in the `Err(e)` synth-empty branch (~line 1413)
```rust
Err(e) => {
// Phase C+13 — scope the synth-empty fallback to non-disc
// prefixes only. Canary's `NtCreateFile_entry` returns the VFS
// result verbatim (xboxkrnl_io.cc:83-110); for a missing disc
// file like `game:\dat\files.tbl` that's
// `STATUS_OBJECT_NAME_NOT_FOUND`. Sylpheed handles NOT_FOUND
// cleanly (next event in canary's trace at idx 103862 is
// `RtlNtStatusToDosError(0xc0000034) -> 2`, then the boot
// validator continues), so the synth was masking the
// correct branch.
//
// Synth-empty is still kept for writable system partitions
// (`\Device\Harddisk0\…`, `\Device\Mass*`, `\??\`, raw paths)
// because those aren't backed by the disc — Canary mounts
// them on host directories
// ([xenia_main.cc:612-651](xenia-canary/src/xenia/app/xenia_main.cc));
// ours skips the host mount for those and falls back to the
// legacy stub to avoid regressing audit-006 / audit-018
// disc-validation probes. `cache:/` was already routed to
// `open_cache_file` upstream of this branch (AUDIT-038).
if is_disc_prefix(&raw_path) {
if handle_out != 0 {
mem.write_u32(handle_out, 0);
}
write_io_status_block(
mem,
io_status_block,
STATUS_OBJECT_NAME_NOT_FOUND as u32,
0,
);
tracing::info!(
"Disc path missing: raw={:?} norm={:?} err={} -> NOT_FOUND",
raw_path,
path,
e
);
return STATUS_OBJECT_NAME_NOT_FOUND;
}
// … existing synth-empty branch unchanged …
}
```
### 4. Tests — 4 new tests inserted before `cache_resolve_strips_path_traversal` (~line 7838)
- `is_disc_prefix_recognises_disc_aliases` — unit test for the prefix classifier; covers `game:\`, `D:\`, `\Device\Cdrom0\`, and several non-disc prefixes that MUST return false.
- `nt_create_file_game_prefix_missing_returns_not_found` — primary fix test (idx 103862 in canary's cold trace). Asserts `STATUS_OBJECT_NAME_NOT_FOUND`, null handle, and IOSB.status records NOT_FOUND.
- `nt_create_file_cdrom_prefix_missing_returns_not_found` — `\Device\Cdrom0\` alias variant.
- `nt_create_file_non_disc_prefix_missing_still_synthesizes` — regression guard: a missing `\Device\Harddisk0\Partition1\sys.bin` still gets a zero-byte synth (preserves audit-006 / audit-018 behaviour).
## Summary
Total: ~30 LOC engine code + ~95 LOC tests = ~125 LOC. Kernel tests 177 → 181.
Stable digest shifts: `ad4f74ee324fdedb0bfdd4cc4c6468e9` → `e1dfcb1559f987b35012a7f2dc6d93f5`.
Phase B `image_loaded_sha256` unchanged: `ea8d160e…`.
Main cold-vs-cold matched prefix: **103862 → 104574 (+712)**.