Files
xenia-rs/audit-runs/canary-boot-state-inventory/inventory.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

32 KiB
Raw Blame History

Xenia-Canary Boot State — Comprehensive Inventory Immediately Before Guest XEX EntryPoint

Context

This document is a research deliverable: a precise, source-verified inventory of every observable subsystem state that the guest XEX sees at the moment its EntryPoint is about to receive control. Driving motivation is RE on Project Sylpheed, where divergence vs. real hardware (or vs. canary) at boot can mask the actual root cause of a wedge. Existing notes/memory may be wrong; this report is built bottom-up from current source in xenia-canary/.

All citations are markdown links into the repo. Where an agent claim was wrong it has been corrected and called out.


0. The Boot Sequence (one-screen overview)

The order in which xenia reaches the guest entrypoint, from src/xenia/emulator.cc:280-360:

  1. Emulator::Initialize constructs graphics_system_ (factory). emulator.cc:283
  2. InputSystem created + Setup(). emulator.cc:295-307
  3. VirtualFileSystem created. emulator.cc:317
  4. KernelState created (this runs InitializeKernelGuestGlobals() from its ctor, kernel_state.h:68).
  5. HLE kernel modules loaded in order: XboxkrnlModule, XamModule, XbdmModule. emulator.cc:327-329 — each ctor allocates guest-visible export variables.
  6. graphics_system_->Setup(...) — register file, gamma ramps, MMIO range, presenter, CP thread. emulator.cc:336-339
  7. audio_system_->Setup(...) — XMA decoder, worker thread parked. emulator.cc:347
  8. ExceptionHandler::Install. emulator.cc:358
  9. (later, on title launch) Emulator::LaunchTitle builds the VFS device + symlinks, calls KernelState::LaunchModule which calls SetExecutableModule (which spawns the kernel dispatch worker) and then XThread::Create for the main thread with X_CREATE_SUSPENDED. kernel_state.cc:403-430
  10. processor()->PreLaunch() (optional debugger wait). kernel_state.cc:427
  11. Main thread is resumed → host thread lambda runs Execute() → backend dispatches to PC = entry_point_. xthread.cc:421-445, 469-471

Steps 18 occur once per emulator instance. Steps 911 occur once per title and are the immediate prelude to the guest's first PPC instruction. Everything below describes the state at the boundary between step 11 and the first guest insn.


1. PPC CPU State (entry thread)

All values from src/xenia/cpu/thread_state.cc:66-112, unless otherwise noted.

1.1 GPRs

Reg Value Source
r0 0 (memset) thread_state.cc:84
r1 (SP) stack_base (top of stack, see §2) thread_state.cc:95
r2 0x20000000 (constant — comment: "used by hv only i think") thread_state.cc:98
r3 start_context argument; for the main thread this is 0 (LaunchModule passes 0 as start_context, see kernel_state.cc:414) [processor.cc Execute() arg setup]
r4..r12 0 (memset)
r13 pcr_address — host pointer into KPCR (see §1.3 / §3.4) thread_state.cc:100
r14..r31 0 (memset)

Note that the XEX ABI does NOT receive its entry args in r3 for the main thread: the main thread invokes the XEX directly with start_context = 0. Worker / kernel threads created via ExCreateThread go through xapi_thread_startup and pass start_context in r3.

1.2 Special-purpose registers

SPR Value Note
LR 0 (memset)
CTR 0 (memset)
MSR 0x9030 Quoted comment: "dumped from a real 360, 0x8000"thread_state.cc:104
XER (ca/ov/so) 0 Split fields, all zeroed
FPSCR 0 (memset; no explicit rounding-mode setup — default is RN=00 round-to-nearest)
CR0..CR7 0 (memset)
VSCR 0x00010000 (NJ bit = 1, Non-Java IEEE mode) thread_state.cc:103Correction: Agent #1's claim of 0x00010016 was wrong; actual constant is vec128i(0,0,0,0x00010000)
VRSAVE 0xFFFFFFFF thread_state.cc:111 — "closer to correct than 0"
DEC, TBL/TBU 0 (memset)
PC entry_point_ extracted from XEX user_module.cc:230, passed via kernel_state.cc:415

1.3 FPRs, VMX/VR

  • All 32 FPRs zeroed by memset of PPCContext (thread_state.cc:84).
  • All 128 vector registers (VMX128) zeroed by the same memset.
  • vrsave = 0xFFFFFFFF is the only non-zero vector-related slot.

1.4 Host-side stash bound to the context

Beyond architectural state, the PPCContext carries pointers used by JIT-generated code and trampolines (thread_state.cc:87-92):

  • context->global_mutex = &xe::global_critical_region::mutex()
  • context->virtual_membase / physical_membase
  • context->processor / thread_state / thread_id
  • (set later by XThread::Create) context->kernel_statexthread.cc:393

The context buffer itself is guest-VA-aligned so its low 32 bits end in 0xE0000000 — clever trick at thread_state.cc:26-56 gives the backend room to use int8 displacements into a preceding granule for backend-specific data.


2. Memory Layout & Heaps

2.1 Guest VA partitioning

The 2 GiB guest VA is shared across heaps managed by Memory (src/xenia/memory.cc, memory.h). Notable named ranges:

  • Default user VA heap for small / large allocations.
  • Stack range 0x70000000 0x7F000000 — hardcoded constants kStackAddressRangeBegin/kStackAddressRangeEnd at xthread.h:362-363.
  • Physical mirrors at the A0/C0/E0 high-VA aliases of physical memory (multiple VA views of the same backing pages — required for GPU/audio DMA semantics).
  • System heap — kernel-side allocator backing the SystemHeapAlloc calls used by XboxkrnlModule, XamModule, KernelState, and per-thread bookkeeping. Backs PCR, TLS, KTHREAD, kernel guest globals, kernel exports listed in §3.
  • Reserved high range for kernel objects / object table.

2.2 Stack (boot thread)

Per xthread.cc:275-301:

  • Requested size from XEX XEX_HEADER_DEFAULT_STACK_SIZE (rounded up to heap page size, default 4 KiB or 64 KiB depending on XEX page-size flag).
  • Allocated as actual_size = size + 2*page_size (one guard page top, one bottom).
  • Guard pages set to kMemoryProtectNoAccess. Body is RW.
  • stack_limit_ = base + page_size (low water), stack_base_ = stack_limit_ + size (high water; this is what r1 is set to).

2.3 TLS block

Per xthread.cc:327-361:

  • Slots from xex2_opt_tls_info.slot_count if present, else 1024 (kDefaultTlsSlotCount xthread.cc:335).
  • Layout: [extended TLS image | slot_count*4 bytes of slots]. tls_static_address_ = base, tls_dynamic_address_ = base + extended_size.
  • Initial state: zeroed via Memory::Fill, then game-provided TLS image copied from raw_data_address if non-zero.
  • Accessed at guest runtime through r13 + 0 (KPCR's tls_ptr field).

2.4 KPCR (Processor Control Region) — what r13 actually points at

Per xthread.cc:379, 401-411: 0x2D8 bytes allocated from system heap; the fields set before entry are:

Offset Field Value at entry
0x000 tls_ptr tls_static_address_
0x030 pcr_ptr self (pcr_address_)
0x038 host_stash (uint64_t)thread_state_->context() (host pointer punned into u64)
0x070 stack_base_ptr stack_base_
0x074 stack_end_ptr stack_limit_
0x100 prcb_data.current_thread guest KTHREAD object guest VA
0x104 prcb pcr_address + offsetof(X_KPCR, prcb_data)
prcb_data.dpc_active 0

Everything else in the KPCR is zero at entry.

2.5 XEX image & sections

Loaded by XexModule (src/xenia/cpu/xex_module.cc plus src/xenia/kernel/user_module.cc):

  • Header copied into the system heap, accessible as guest_xex_header_ (user_module.cc:224).
  • Entry point + stack/tls/workspace sizes pulled via GetOptHeader (user_module.cc:230-234).
  • PE sections mapped at their declared VAs with section flags; .text is X+R (or X+R+W if writable_code_segments cvar set).
  • Import tables resolved during LoadContinue — each import slot is patched to invoke the host kernel export trampoline directly (no guest thunk).
  • Title workspace heap created at the XEX-declared address if XEX_HEADER_TITLE_WORKSPACE_SIZE is set (user_module.cc:237).

3. Kernel / xboxkrnl Guest-Visible State

Verified directly against src/xenia/kernel/xboxkrnl/xboxkrnl_module.cc and src/xenia/kernel/kernel_state.cc.

3.1 Pre-initialized exported variables (xboxkrnl.exe)

Created at XboxkrnlModule ctor — these are visible before entry because the ctor runs at step 5 of §0.

Export Size Initial bytes Source
KeDebugMonitorData 4 (or 4+sizeof(X_KEDEBUGMONITORDATA) if cvar on) 0 (off path); points to struct w/ callback fn ptr (on path) xboxkrnl_module.cc:80-102
KeCertMonitorData same 0 / struct + callback xboxkrnl_module.cc:104-123
XboxHardwareInfo 16 [0]=0x20 (HDD bit), [4]=0x06 (CPU count), rest 0 xboxkrnl_module.cc:136-141
ExConsoleGameRegion 4 0xFFFFFFFF xboxkrnl_module.cc:146-150
XexExecutableModuleHandle 4 uninit at ctor; populated later when SetExecutableModule runs xboxkrnl_module.cc:161-164
ExLoadedImageName kExLoadedImageNameSize (1024-aligned) uninit at ctor; filled later with module path xboxkrnl_module.cc:171-174
ExLoadedCommandLine aligned(strlen+1, 1024) "default.xex" + optional cvars::cl, NUL-padded xboxkrnl_module.cc:181-194
XboxKrnlVersion 8 kernel_state_->GetKernelVersion() (verify exact bytes in kernel_state.h) xboxkrnl_module.cc:199-204
KeTimeStampBundle 24 populated lazily on first read via GetKeTimestampBundle() — see §3.2 xboxkrnl_module.cc:206-208
ExThreadObjectType, ExEventObjectType, ExMutantObjectType, ExSemaphoreObjectType, ExTimerObjectType, IoCompletionObjectType, IoDeviceObjectType, IoFileObjectType, ObDirectoryObjectType, ObSymbolicLinkObjectType, UsbdBootEnumerationDoneEvent each → offset within KernelGuestGlobals block populated by InitializeKernelGuestGlobals() (§3.3) xboxkrnl_module.cc:214-225

Correction vs Agent #3: KeTimeStampBundle initialization does NOT happen in xboxkrnl_module.cc; it lives in KernelState::CreateKeTimestampBundle at kernel_state.cc:1272-1295 and is created lazily on first call to GetKeTimestampBundle(). A HighResolutionTimer::CreateRepeating is then armed to call UpdateKeTimestampBundle() periodically.

3.2 KeTimeStampBundle layout (X_TIME_STAMP_BUNDLE)

Initialized in kernel_state.cc:1272-1295:

Offset Field Initial value
+0x00 interrupt_time (u64) current interrupt-time value
+0x08 system_time (u64) current system time
+0x10 tick_count (u32) Clock::QueryGuestUptimeMillis()
+0x14 padding (u32) 0

A repeating HighResolutionTimer updates these fields every tick (kernel_state.cc:1292-1294).

3.3 KernelGuestGlobals — the big preinitialized blob

Allocated and zeroed at kernel_state.cc:1511-1516; see the KernelGuestGlobals struct definition at kernel_state.h:115-.... Fields include:

  • ExThreadObjectType, ExEventObjectType, ExMutantObjectType, ExSemaphoreObjectType, ExTimerObjectType, IoCompletionObjectType, IoDeviceObjectType, IoFileObjectType, ObDirectoryObjectType, ObSymbolicLinkObjectType
  • UsbdBootEnumerationDoneEvent
  • OddObj (referenced kernel_state.cc:1527)
  • system_process, title_process, idle_process (accessor methods at kernel_state.h:212, 216, 220)

Each guest object type is filled with the kernel's view of how dispatcher headers / object headers look. Bytes at these offsets are observable as dq constants by the guest before entry.

3.4 ProcessInfoBlock

Filled by InitializeProcess (called from SetExecutableModule). Notable preinit fields per Agent #3's report:

  • +0x0C: 0x0000007F
  • +0x10: 0x001F0000
  • +0x14: thread_count = 0
  • +0x1B: 0x06
  • +0x1C: kernel_stack_size = 16384
  • +0x20: process_type = X_PROCTYPE_USER (or X_PROCTYPE_TITLE for title)
  • +0x24..+0x4F: TLS info copy from XEX header

3.5 Object table

  • Empty before LaunchModule. As soon as SetExecutableModule runs, the executable module's handle is the first allocation.
  • The kernel dispatch worker thread handle is the second.
  • The main XThread handle is the third. All allocated from object_table() (xthread.cc:317 via CreateNative).
  • XObject::kHandleBase = 0xF8000000; handles spaced by 4.

4. XAM State

4.1 User profile

Created in KernelState ctor (kernel_state.cc:52). Single profile preconfigured at src/xenia/kernel/xam/user_profile.cc:

  • XUID: 0xB13EBABEBABEBABE (hardcoded)
  • Gamertag: "User"
  • 18 default profile settings (per Agent #3's enumeration — XPROFILE_GAMER_YAXIS_INVERSION=0, XPROFILE_OPTION_CONTROLLER_VIBRATION=3, XPROFILE_GAMERCARD_REGION=0, XPROFILE_GAMERCARD_CRED=0xFA, etc.).

Spot-check note: I did not re-verify each of the 18 settings by direct read; cite by file before depending on any single value.

4.2 App manager / content manager

  • AppManager instantiated, RegisterApps() called from KernelState ctor — registers known XAM apps. No launch data at entry.
  • ContentManager rooted at emulator_->content_root() (see Emulator ctor). Title-specific save/DLC mounts are not yet established at entrypoint; they are established lazily.

4.3 Notification listeners

Empty list at entry (kernel_state.h:219). On first listener registration with mask bit 1 set, the system synthesizes startup notifications (XN_SYS_UI, XN_SYS_SIGNINCHANGED, XN_SYS_INPUTDEVICESCHANGED, XN_SYS_INPUTDEVICECONFIGCHANGED — kernel_state.cc:657-671).


5. Filesystem State

5.1 Devices mounted at entrypoint

In Emulator::LaunchTitle / Emulator::CreateVfsDevice (emulator.cc:376-...):

Game source Device(s) registered Symlinks
.xex (loose folder) HostPathDevice(\Device\Harddisk0\Partition1, parent_dir, read_only=!allow_game_relative_writes) game:, d: → same
.iso (XISO) DiscImageDevice(\Device\Cdrom0, path) game:, d: → same
LIVE/CON/PIRS (STFS) XContentContainerDevice::CreateContentDevice(...) game:, d: → same
ZAR DiscZarchiveDevice(...) same

Plus optional mounts driven by cvars (from xenia_main.cc):

  • mount_scratch\SCRATCH, symlink scratch:
  • mount_cache\CACHE0, \CACHE1, \CACHE with cache0:, cache1:, cache:

No files are open at entry; the guest opens what it needs.

5.2 Cache & temp

  • No CACHE partition data is fabricated. If mount_cache is on, host directories cache/, cache0/, cache1/ back the partitions; otherwise they don't exist for the guest at all.
  • No STFS content packages are pre-mounted unless the title was launched from an STFS package.

6. GPU State (Xenos / Vulkan or D3D12 backend)

6.1 RegisterFile

Allocated as host memory in GraphicsSystem ctor at src/xenia/gpu/graphics_system.cc:79-81:

register_file_ = reinterpret_cast<RegisterFile*>(memory::AllocFixed(
    nullptr, sizeof(RegisterFile), kReserveCommit, kReadWrite));

This zero-fills the entire register file. No registers are preloaded with non-zero values before entry. XE_GPU_REG_D1MODE_V_COUNTER is later incremented asynchronously by the frame-limiter thread once that thread starts (graphics_system.cc:~177).

6.2 Gamma ramps (the one notable pre-initialized GPU data)

In CommandProcessor::Initialize at src/xenia/gpu/command_processor.cc:130-148: a 256-entry sRGB-table-like ramp (i * 0x3FF / 0xFF) per channel and a 128-entry PWL ramp with delta 0x200 are loaded. These are observable if guest code reads gamma registers before writing them.

6.3 Command Processor / ringbuffer

  • The CP thread is spawned in GraphicsSystem::Setup (graphics_system.cc:135), at step 6 of §0. It blocks on write_ptr_index_event_ waiting for PM4 work.
  • The ringbuffer itself is NOT allocated before entry. The guest allocates and registers it via VdInitializeRingBuffer (xboxkrnl_video.cc:313-319).

6.4 MMIO

The GPU MMIO range [0x7FC80000, 0xFFFF0000] is hooked via Memory::AddVirtualMappedRange from GraphicsSystem::Setup (graphics_system.cc:141-144). Guest reads/writes route to GPU register file handlers.

6.5 Presenter & backend device

  • Presenter and the actual Vulkan/D3D12 device + swapchain are created in GraphicsSystem::Setup when with_presentation=true (graphics_system.cc:116-128).
  • VdInitializeEngines is stubbed to return 1 — xenia uses no real microcode (xboxkrnl_video.cc:271-280).
  • EDRAM/tile allocator, surface info, swap counters: not initialized to guest-visible state pre-entry.

6.6 Reported video mode (queried by guest after entry but driven by config)

VdQueryVideoMode at xboxkrnl_video.cc:203-219 reports cvar-driven values: default 1280×720, widescreen=true, is_interlaced=false, refresh_rate=60.0f, video_standard=1 (NTSC), pixel_rate=0x8A, widescreen_flag=0x01. Gamma type=2 (BT.709), power ≈ 2.222.


7. Audio (APU) State

In AudioSystem::Setup (src/xenia/apu/audio_system.cc:48-97) called at step 7 of §0:

  • queued_frames_ clamped to [4, 64] from cvar apu_max_queued_frames (default 8).
  • 256 client semaphores allocated, initial count 0, max count = queued_frames_.
  • shutdown_event_, resume_event_ created.
  • XmaDecoder instantiated; its Setup() runs.
  • Worker thread spawned, executing WorkerThreadMain, immediately parked on WaitAny(wait_handles_). No audio is being submitted, no frames queued.

The XMA guest-memory window (typically observed near 0x42500000 per RE notes) has no pre-populated context state — the guest must call XAudioRegisterRenderDriverClient and provide context VAs.


8. HID / Input

InputSystem::Setup (emulator.cc:307) initializes the input layer; per src/xenia/hid/input_system.h:82-85:

  • connected_slots = bitset<XUserMaxUserCount>(0)no controller is plugged in at the moment of entry. The driver layer wires up on demand as controllers connect.
  • last_used_slot = 0.
  • Portal (MCP bridge) created.
  • XInputGetCapabilities on disconnected slots returns X_ERROR_DEVICE_NOT_CONNECTED (input_system.cc:179).

Vibration state, battery, etc.: nothing reported until a controller is connected.


9. Networking / XNet / Sockets

No network init occurs before entry; the guest must call NetDll_XNetStartup to populate xnet_startup_params (zero-initialized at xam_net.cc:173).

When queried via NetDll_XNetGetTitleXnAddr (xam_net.cc:476-499):

  • IP ina = 127.0.0.1 (loopback)
  • Online IP inaOnline = 0.0.0.0
  • Online port = 0
  • MAC abEnet = CC CC CC CC CC CC
  • abOnline = 20 zeros
  • Return code = XNET_GET_XNADDR_STATIC (0x00000004)

NetDll_XNetGetDebugXnAddr returns XNET_GET_XNADDR_NONE (0x00000001).

No sockets, no system-link, no NIC enumeration at entry.


10. Real-Time Clock & Timebase

  • Clock::guest_tick_frequency() (src/xenia/base/clock.cc:39) returns the host CPU tick frequency unless overridden by clock_no_scaling. Reported to guest by KeQueryPerformanceFrequency_entry (xboxkrnl_threading.cc:438-443).
  • KeQuerySystemTime_entry (xboxkrnl_threading.cc:483-497) reads Clock::QueryGuestSystemTime — wall clock as of emulator startup epoch.
  • KeTimeStampBundle (§3.2) is the cheap shared mailbox; updated by a repeating HighResolutionTimer.

11. Threading at Entry

At the boundary, the threads that exist are:

  1. Main XThread (is_main_thread=true, guest_thread=true) — currently suspended, about to be resumed. Stack range 0x70000000-0x7F000000, host stack 16 MiB (xthread.cc:420), priority/affinity set via GetFakeCpuNumber derived from (creation_flags >> 24) (xthread.cc:395-396). CPU index assigned via SetActiveCpu(cpu_index) (xthread.cc:464).
  2. Kernel dispatch worker thread — spawned in SetExecutableModule to handle guest async callbacks (kernel_state.cc:368-391 ~). Host-side; consumes from a host queue, does not appear in the guest object table.
  3. GPU command processor thread — already running (parked on write_ptr_index_event_).
  4. Audio worker thread — already running (parked on its semaphore set).
  5. Optional: frame-limiter thread, presenter thread, KeTimeStampBundle update timer thread.

Worker threads (sub_825070F0-style XAudio/render workers, secondary game workers, XAM threads) do NOT exist yet — they are spawned by guest code post-entry.

Scheduler state:

  • No IRQL machinery; guest code runs at PASSIVE-equivalent.
  • Quantum / preemption is approximated; ours uses cooperative-ish per-thread quanta.
  • DPC list empty (kernel_state.h:233).

12. JIT / Codegen State

  • Backend (x64 or AArch64) initialized at Processor construction.
  • backend_->AllocThreadData() and InitializeBackendContext(context_) called from ThreadState ctor (thread_state.cc:77, 82).
  • Code cache empty — entry-point block JITs on first execution unless enable_early_precompilation cvar pre-compiled it.
  • Import-table call sites already patched to direct host trampolines (resolved during XexModule::LoadContinue).
  • Syscall / MMIO handlers wired up.

13. Misc Peripherals

  • DVD / Disc drive: no separate drive state — backed by the VFS device created at title launch. Tray/laser not modeled.
  • USB: no enumeration. UsbdBootEnumerationDoneEvent is allocated as a guest event in KernelGuestGlobals but its signaled-state at entry is the field default (verify against KernelGuestGlobals struct).
  • Cache partition: present only if mount_cache cvar set.
  • System link / bridged LAN: not initialized.
  • Hypervisor surfaces / KdNet / DmEvents: KD/network debug is not implemented. DebugPrint redirects into xenia's logger.
  • Emulator-detection signals (intentional or accidental): KeDebugMonitorData always nonzero or known-zero (vs. real-HW behavior), missing/unimplemented kernel exports, exact MSR value 0x9030, the constant r2=0x20000000, the fake XUID 0xB13EBABEBABEBABE.

14. Single-Page "What is in the registers right now?" Quick Card

For Sylpheed RE workflows where you need to set a breakpoint at the first guest insn:

PC      = <XEX entry_point>              ; from XEX optional header
r0..r12 = 0
r1      = stack_base (top of 0x700000000x7F000000 region, page-aligned)
r2      = 0x20000000
r3      = 0
r13     = pcr_address (KPCR, has tls_ptr at [r13+0])
r14..r31= 0
LR=0  CTR=0  XER=0  CR=0  FPSCR=0
MSR     = 0x9030
VSCR    = 0x00010000   ; NJ=1
VRSAVE  = 0xFFFFFFFF
FPRs    = +0.0 (zero bit pattern)
VR0..127= zero
DEC, TB = 0

15. Verification (how to confirm the above for a specific Sylpheed boot)

The deliverable above is a static read of the source. To validate dynamically for a specific run:

  1. Quick canary smoke test — run xenia-canary against Sylpheed with logging set high enough to catch XELOGI("XThread{:08X} ({:X}) Stack: {:08X}-{:08X}", ...) from xthread.cc:389. That confirms stack_base_, stack_limit_, thread_id_.
  2. Drop into JIT entry breakpoint — set a JIT-store probe (per AUDIT-067 pattern in memory) on the guest PC = entry_point_ and dump the PPCContext once. Compare GPRs/VSCR/MSR against the table above.
  3. Pre-entry kernel-export dump — print the contents of guest VAs for XboxHardwareInfo, KeDebugMonitorData, KeTimeStampBundle, ExLoadedCommandLine immediately before resuming the main thread; verify §3.1 expected bytes.
  4. VFS sanityKernelState::file_system_->ResolvePath("game:\\default.xex") should succeed; D: should resolve to the same device.
  5. GPU pre-state — assert no PM4 packets have been dispatched (command_processor_->paused() / ringbuffer write-ptr == read-ptr) and gamma table contains the linear ramp from §6.2.
  6. Audio pre-state — assert 256 client semaphores all have count=0, worker thread parked, no XMA contexts registered.
  7. Cross-engine sanity — run xenia-rs against the same XEX with the same cvars; the values that should match between engines: r1/r2/r13/MSR/VSCR/VRSAVE, PC, XboxHardwareInfo, ExConsoleGameRegion, XexExecutableModuleHandle, the 1024-entry default TLS slot count, stack range, KPCR layout, default profile XUID.

16. Known Unknowns / Things Not Verified in This Pass

  • Exact byte contents of KernelGuestGlobals object-type sub-structs (ExThreadObjectType etc.) — these are populated in InitializeKernelGuestGlobals(); full byte-level dump would require reading kernel_state.cc:1511 onward in full.
  • XboxKrnlVersion exact 8 bytes — held in KernelVersion static, not spot-checked in this pass.
  • The 18 default profile setting values were taken from Agent #3's report and not individually re-read.
  • Exact xex2_opt_tls_info fields for Sylpheed (slot_count, raw_data_size) — title-specific.
  • Per-backend (Vulkan vs. D3D12) device-state nuances.

These are noted explicitly so this doc is not mistaken for full coverage.


17. Critical Files Index

For quick navigation: