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:
120
audit-runs/audit-068-host-mem-watch/writer-report.md
Normal file
120
audit-runs/audit-068-host-mem-watch/writer-report.md
Normal file
@@ -0,0 +1,120 @@
|
||||
# AUDIT-068 Session 1 — writer report
|
||||
|
||||
Date: 2026-05-19
|
||||
|
||||
## Summary
|
||||
|
||||
Built canary instrumentation that hooks the three host-side write surfaces I expected to cover the AUDIT-067 / Phase HostAudio-Eager findings:
|
||||
1. `xe::store_and_swap<T>` template family (`xenia/base/memory.h`, T=u8/u16/u32/u64/i8/i16/i32/i64).
|
||||
2. `xe::store<T>` template family (host-endian sibling of above).
|
||||
3. `Memory::Zero/Fill/Copy` in `xenia/memory.cc`.
|
||||
|
||||
Total instrumentation: ~190 LOC kept in canary tree (cvar-gated default-off, zero hot-path cost when both cvars empty), 2 new files in `xenia/base/`:
|
||||
- `audit_68_host_mem_watch_fwd.h` — atomic + inline checks (forward decls).
|
||||
- `audit_68_host_mem_watch_base.cc` — slow-path impl, lazy CSV parse, host→guest VA translation via function-pointer thunk.
|
||||
|
||||
Cvars in `xenia/cpu/cpu_flags.{h,cc}`:
|
||||
- `--audit_68_host_mem_watch_values=CSV` (max 8 u32 values).
|
||||
- `--audit_68_host_mem_watch_addrs=CSV` (max 8 VAs or `START-END` ranges).
|
||||
|
||||
Smoke test (`--audit_68_host_mem_watch_values=0x12345678`, 30s): 0 hits, INIT lines emitted — instrumentation operational.
|
||||
|
||||
Sanity test (`--audit_68_host_mem_watch_values=0x00000000`, ~12s): **1,639 hits**, dominated by `Memory::Zero` (1,594) plus `store_and_swap<u32>` (13) and `store_and_swap<u64>` (2). Instrumentation works end-to-end and the guest-VA thunk resolves correctly (e.g. `guest_va=0x30000000 host_ptr=...30000000` for `store_and_swap`).
|
||||
|
||||
## Capture runs
|
||||
|
||||
### Run 1 — vtable `0x8200A208 / 0x8200A928` writers
|
||||
|
||||
Cmdline: `--audit_68_host_mem_watch_values=0x8200A208,0x8200A928,0x080082A2,0x2829820 --audit_68_host_mem_watch_addrs=0xBCE25340` (value list also includes the byte-swapped forms in case some caller passes a pre-swapped value through `store<T>` rather than `store_and_swap<T>`; addr watch on the known target instance address from AUDIT-058/067).
|
||||
|
||||
Wallclock: 90 s (post-10.4 s trigger window per Phase NonMatch).
|
||||
|
||||
**Result: 0 hits.** Log at `run1-vtable-writers.log` (81 KB; cold boot reached thread spawn through tid=29, matching Phase NonMatch trace).
|
||||
|
||||
### Run 2 — voice-struct field clear `[VOICE+0x164]`
|
||||
|
||||
Cmdline: `--audit_68_host_mem_watch_addrs=0x42500000-0x42600000`.
|
||||
|
||||
Wallclock: 60 s.
|
||||
|
||||
**Result: 0 hits.** Log at `run2-voice-struct-writers.log`.
|
||||
|
||||
### Sanity — value=0 reachability test
|
||||
|
||||
Cmdline: `--audit_68_host_mem_watch_values=0x00000000`. Wallclock: ~12 s.
|
||||
|
||||
**Result: 1,639 hits**, breakdown:
|
||||
| tag | hits |
|
||||
|---|---:|
|
||||
| `Memory::Zero` | 1,594 |
|
||||
| `Memory::Fill` | 30 |
|
||||
| `store_and_swap<u32>` | 13 |
|
||||
| `store_and_swap<u64>` | 2 |
|
||||
|
||||
Guest VAs span `0x30000000-0x30xxx000` (the 40 MB physical heap setup by Memory::Initialize) and `0xFFCAxxxx` (kernel high range, stacks/TLS). `store_and_swap<u32>` hits e.g. `0xFFCAE000 / 0xFFCAD000 / 0x30002000` — kernel pointer-init scribbles. NO hits in the XEX image region `0x82000000+`. Log at `sanity-value0.log`.
|
||||
|
||||
## Headline finding (negative-but-informative)
|
||||
|
||||
**Neither the vtable install nor the XEX section loader uses any of the hooked paths.** A separate Sanity-2 run watched the addr range `0x82000000-0x82010000` (Sylpheed's `.text` start) and got 0 hits across a full boot — yet that region MUST be written to during XEX load (the image is copied in from the file). This means:
|
||||
|
||||
- The XEX module loader (`xenia/cpu/xex_module.cc`) writes guest memory via **raw `memcpy()` and direct `*ptr = ...` host-pointer writes** that are NOT routed through `xe::store_and_swap<T>`, `xe::store<T>`, or `Memory::Zero/Fill/Copy`. Quick grep on `xex_module.cc` confirms: lines 286, 369, 422, 427, 525, 582, 592, 650, 668, 773, 795 all use plain `memcpy(host_ptr, src, size)` after a `Memory::TranslateVirtual` lookup.
|
||||
- The kernel-import handlers that COULD synthesize `0x8200A208` runtime (the original AUDIT-067 hypothesis) are not doing so — at least not via the hooked surfaces — within the 90 s window that includes the 10.4 s trigger.
|
||||
|
||||
So neither of the two main hypotheses (host-allocator vptr install via kernel handler; voice-struct clear via direct write) was captured by Session 1's instrumentation. Session 1's coverage gap is identified and is the deliverable for Session 2.
|
||||
|
||||
## What Session 1 nonetheless confirmed
|
||||
|
||||
1. **The instrumentation is sound.** 1,639 value=0 hits prove the `store_and_swap<T>` / `Memory::Zero/Fill/Copy` hooks and the host→guest VA translation thunk all work in default cold-boot.
|
||||
2. **AUDIT-067's "host-side install" framing remains correct** — guest stores were ruled out by AUDIT-067, host-side `store_and_swap` is now ruled out by AUDIT-068. The set of paths left for the installer is narrowed to: raw `memcpy`-via-`TranslateVirtual`, `*reinterpret_cast<be<T>*>(host)=v` patterns, or some other un-hooked direct host write.
|
||||
3. **Cold-boot guest-VA layout** (from sanity log):
|
||||
- `0x30000000-0x30xxxxxx` — physical heap (Memory::Zero on Initialize).
|
||||
- `0xFFCAxxxx` — kernel high (stacks etc).
|
||||
- `0x82000000+` — Sylpheed XEX image region (never touched by hooked surfaces).
|
||||
- Nothing observed in `0x42xxxxxx` or `0xBCxxxxxx` (yet — these allocate later than the 12 s sanity window).
|
||||
|
||||
## Per-writer breakdown (from sanity capture)
|
||||
|
||||
Only writers with hits in the 12 s window are listed; this is what Session 2 will need to mirror in ours where applicable.
|
||||
|
||||
### `Memory::Zero` (1,594 hits in 12 s)
|
||||
- All from tid=304 (host main thread / boot thread).
|
||||
- Affected guest VAs: `0x30000000-0x30xxx000` (heap-page zero on init), `0xFFCAB000-0xFFCAE000` (kernel stacks zero on alloc).
|
||||
- This is invoked by `Memory::Initialize` for heap setup and by the kernel during stack allocations.
|
||||
- Ours's analog: `xenia-kernel/src/state.rs`/`memory.rs` — Memory init and stack alloc. Likely already zero-init by Rust default; verify in Session 2.
|
||||
|
||||
### `Memory::Fill` (30 hits in 12 s)
|
||||
- Same tid=304, similar VA distribution.
|
||||
- Used for `RtlFillMemory` and some allocator default-fill paths.
|
||||
|
||||
### `store_and_swap<u32>` (13 hits in 12 s)
|
||||
- One of each: pointer-init writes by kernel-thread setup code (e.g. TIB fields).
|
||||
- Example: `0xFFCAE000`, `0xFFCAD000`, `0x30002000`. Likely the linked-list / TLS slot pointers written by `XThread::AllocateStack`.
|
||||
|
||||
### `store_and_swap<u64>` (2 hits)
|
||||
- Likely `RtlInitMemory` 64-bit-aligned scribbles.
|
||||
|
||||
## What's missing — the writers Session 2 must catch
|
||||
|
||||
Both Session-1 target writers (vtable install + voice-struct clear) escape the hooked surface. The XEX loader's raw `memcpy()` is the obvious blind spot but does not explain the vtable install (the vptr at `0xBCE25340` is in the heap, written AFTER load). Other candidates:
|
||||
|
||||
1. **`*xe::TranslateVirtual<be<T>*>(addr) = value;`** — typed-pointer cast through a host-endian `be<T>` reference. Lots of kernel-import code uses this pattern (e.g. `xboxkrnl_rtl.cc`'s `RtlCompareMemory` returns, `xboxkrnl_video.cc`'s frame-count writes). Doesn't go through `store_and_swap`.
|
||||
2. **Direct `*reinterpret_cast<uint32_t*>(host) = byte_swap(val)`** — a few performance-critical sites do this inline rather than via the template.
|
||||
3. **`Memory::Copy`** with `src` host-region having pre-encoded bytes — but the value-match path I added DOES catch this for the first u32 of the source, and we got 0 hits. Either `Memory::Copy` isn't used for vptr install, or the values don't appear as the first u32 of the copy.
|
||||
4. **GPU / VFS host-side initialisation** of mmio-mapped guest memory — separate APIs entirely, but Sylpheed isn't doing GPU vtable installs at this point.
|
||||
|
||||
## Per-target follow-up (Session 2 capture targets)
|
||||
|
||||
| Value/VA | Status from Session 1 | Session 2 plan |
|
||||
|---|---|---|
|
||||
| Vtable `0x8200A208` install at `0xBCE25340` | NOT CAUGHT (host-side, but escapes `store_and_swap` / `store` / `Memory::Zero/Fill/Copy`) | Add hooks on (a) the typed-pointer write surfaces (`be<T>::operator=` and `*TranslateVirtualBE<T>() = v`) and (b) a `Memory::WriteWord32` shim that catches raw u32 stores into TranslateVirtual host pointers. Also add a `Memory::Copy` value-watch that scans the WHOLE copy buffer for matches, not just the first u32. Re-run with vtable-value watch + addr-range watch on the heap region around `0xBCE25340`. |
|
||||
| Voice-struct field clear `[VOICE+0x164]` | NOT CAUGHT (same reason; plus the actual VOICE base may live outside `0x42xxxxxx`) | First find the actual VOICE base via guest-side enumeration in Phase HostAudio-Eager artifacts; once known, addr-range watch over the entire `MmAllocatePhysicalMemoryEx` block that contains the voice array. |
|
||||
|
||||
## Artifacts in this dir
|
||||
|
||||
- `instrumentation-design.md` — surface inventory + cvar design.
|
||||
- `fix-canary.diff` — combined diff of the 5 modified files plus full text of the 2 new files (`xenia/base/audit_68_host_mem_watch_fwd.h`, `xenia/base/audit_68_host_mem_watch_base.cc`).
|
||||
- `run1-vtable-writers.log` — 0 hits.
|
||||
- `run2-voice-struct-writers.log` — 0 hits.
|
||||
- `sanity-value0.log` — 1,639 hits (instrumentation alive proof).
|
||||
- `writer-report.md` — this file.
|
||||
- `session-2-plan.md` — actionable plan for next session.
|
||||
Reference in New Issue
Block a user