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:
@@ -0,0 +1,81 @@
|
||||
# AUDIT-068 Session 1 — host-side memory-write watch (canary instrumentation)
|
||||
|
||||
Date: 2026-05-19
|
||||
|
||||
## Goal
|
||||
|
||||
Capture which host C++ functions perform the writes to guest memory that ours never reproduces:
|
||||
1. Vtable install at `0xBCE25340 = 0x8200A208` (and clone `0x8200A928`) — gates `sub_825070F0`.
|
||||
2. Voice-struct field clear `[VOICE+0x164]` (value `0x00000000`, on guest-VA likely in heap `0x425xxxxx`).
|
||||
3. Anything else surfaced.
|
||||
|
||||
## Write-path surface inventory (canary)
|
||||
|
||||
### A. `xe::store_and_swap<T>` template family (`xenia-canary/src/xenia/base/memory.h:410-475`)
|
||||
|
||||
- Sized specializations for T = int8/uint8/int16/uint16/int32/uint32/int64/uint64/float/double.
|
||||
- String specializations recurse to `store_and_swap<uint8_t>` / `<uint16_t>`.
|
||||
- Receives `void* mem` = HOST pointer; does `*p = byte_swap(value)`.
|
||||
- **This is the canonical path** for host-side typed writes to guest memory used by kernel-import handlers in `xboxkrnl_*.cc`. Confirmed wide use (16 kernel sub-modules call `store_and_swap<uint32_t>` alone).
|
||||
- Vtable install (PPC `stw vptr,0(obj)` equivalent on host side) almost certainly uses `store_and_swap<uint32_t>(host_ptr, vptr)`.
|
||||
|
||||
### B. `Memory::Zero/Fill/Copy` (`xenia/memory.cc:542-554`)
|
||||
|
||||
- Use `std::memset`/`std::memcpy` directly via host pointer (after `TranslateVirtual`).
|
||||
- Wrappers for `RtlZeroMemory`, `RtlFillMemory`, `RtlMoveMemory`, `RtlCopyMemory`.
|
||||
- Bypass `store_and_swap` — must instrument separately if we want full coverage.
|
||||
- Voice-struct clears via `0x00000000` could plausibly come through here (RtlZeroMemory) or directly via `store_and_swap<uint32_t>` (typed write).
|
||||
|
||||
### C. Direct guest writes via `*TranslateVirtual<T*>() = …`
|
||||
|
||||
- Some sites cast and write through the host pointer directly without going through `store_and_swap`.
|
||||
- Lower coverage priority — start with A+B; add C only if first 2 don't catch our targets.
|
||||
|
||||
## Cvar design (mimics audit_67 pattern)
|
||||
|
||||
Two new cvars in `xenia/cpu/cpu_flags.{h,cc}`:
|
||||
|
||||
```cpp
|
||||
DECLARE_string(audit_68_host_mem_watch_values); // CSV of u32 values (max 8)
|
||||
DECLARE_string(audit_68_host_mem_watch_addrs); // CSV of guest VAs or VA ranges (max 8)
|
||||
```
|
||||
|
||||
Format examples:
|
||||
- Values: `--audit_68_host_mem_watch_values=0x8200A208,0x8200A928`
|
||||
- Addrs single: `--audit_68_host_mem_watch_addrs=0xBCE25340`
|
||||
- Addrs range: `--audit_68_host_mem_watch_addrs=0x42500000-0x42600000,0xBCE25340`
|
||||
|
||||
Default empty → zero overhead.
|
||||
|
||||
Sample log line (XELOGI):
|
||||
```
|
||||
AUDIT-068-HOST-WRITE guest_va=0xBCE25340 val=0x8200A208 sz=4 fn=<host_function> host_ns=10123456789 tid=N
|
||||
```
|
||||
|
||||
`fn=<host_function>` is filled by the caller (each `store_and_swap<T>` specialization passes `__FUNCTION__` or a tag). We can't get a real backtrace cheaply across MSVC; we instead instrument the high-fanout entry points (kernel-import handlers, `Memory::Zero/Fill/Copy`) with a string tag. For Session 1, capture is sufficient with just template name + caller tag.
|
||||
|
||||
## Implementation strategy
|
||||
|
||||
1. New file `xenia/audit_68_host_mem_watch.h` (top-level): forward decls of helper functions in `namespace xe::audit_68`:
|
||||
```cpp
|
||||
extern std::atomic<uint8_t> g_active; // 0=off, 1=values, 2=addrs, 3=both
|
||||
void check_host_write(const void* host_ptr, uint64_t value, uint8_t size,
|
||||
const char* tag);
|
||||
void check_guest_write(uint32_t guest_va, uint64_t value, uint8_t size,
|
||||
const char* tag);
|
||||
```
|
||||
2. New file `xenia/audit_68_host_mem_watch.cc`: lazy-parse the cvars on first call, atomic-bool sets active. Performs `Memory::active()->HostToGuestVirtual(host_ptr)` translation, then matches against value-list and addr-range list, emits XELOGI.
|
||||
3. `xenia/memory.h`: add public static `Memory::active()` (returns `active_memory_`).
|
||||
4. `xenia/base/memory.h`: extend `store_and_swap<T>` specializations (uint8/uint16/uint32/uint64 only — the integer typed paths most likely to write vptrs / clear flags) to check `g_active` and call the helper. Hot path: 1 atomic load + branch when off. The added cost when on is one cmp+jne per byte/word/dword/qword store; acceptable for capture runs.
|
||||
5. `xenia/memory.cc`: instrument `Memory::Zero/Fill/Copy` with calls to `check_guest_write` (each ranges through the affected guest VAs; for capture purposes we only log the first matching byte+size+tag — we don't expand to per-byte events).
|
||||
|
||||
Total estimated LOC: ~120-160 LOC across 5 files.
|
||||
|
||||
## Capture protocol
|
||||
|
||||
- Build canary with the new code.
|
||||
- Smoke test: `--audit_68_host_mem_watch_values=0x12345678` (no expected hits) → confirm no spurious lines, build/init OK.
|
||||
- Sanity test: `--audit_68_host_mem_watch_values=0x82000000` (very common vtable-base) → confirm many lines, then revert.
|
||||
- Run 1 (vtable install): `--audit_68_host_mem_watch_values=0x8200A208,0x8200A928 --mute=true`. Kill after ~90s.
|
||||
- Run 2 (voice-struct clear): `--audit_68_host_mem_watch_addrs=0x42500000-0x42600000 --mute=true`. Kill after ~30s (this is heap-region wide; likely lots of hits, capture early window only). May need narrower range once we see the first writes.
|
||||
- Cold-protocol: backup canary's cache (`xenia-canary/build-cross/bin/Windows/Debug/cache/`) to `/tmp/canary-cache-bak-audit-068`, wipe before run, restore after.
|
||||
Reference in New Issue
Block a user