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

452 lines
32 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.
# 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/](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](xenia-canary/src/xenia/emulator.cc#L280-L360):
1. `Emulator::Initialize` constructs `graphics_system_` (factory). [emulator.cc:283](xenia-canary/src/xenia/emulator.cc#L283)
2. `InputSystem` created + `Setup()`. [emulator.cc:295-307](xenia-canary/src/xenia/emulator.cc#L295-L307)
3. `VirtualFileSystem` created. [emulator.cc:317](xenia-canary/src/xenia/emulator.cc#L317)
4. `KernelState` created (this runs `InitializeKernelGuestGlobals()` from its ctor, [kernel_state.h:68](xenia-canary/src/xenia/kernel/kernel_state.h#L68)).
5. HLE kernel modules loaded in order: `XboxkrnlModule`, `XamModule`, `XbdmModule`. [emulator.cc:327-329](xenia-canary/src/xenia/emulator.cc#L327-L329) — each ctor allocates guest-visible export variables.
6. `graphics_system_->Setup(...)` — register file, gamma ramps, MMIO range, presenter, CP thread. [emulator.cc:336-339](xenia-canary/src/xenia/emulator.cc#L336-L339)
7. `audio_system_->Setup(...)` — XMA decoder, worker thread parked. [emulator.cc:347](xenia-canary/src/xenia/emulator.cc#L347)
8. `ExceptionHandler::Install`. [emulator.cc:358](xenia-canary/src/xenia/emulator.cc#L358)
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](xenia-canary/src/xenia/kernel/kernel_state.cc#L403-L430)
10. `processor()->PreLaunch()` (optional debugger wait). [kernel_state.cc:427](xenia-canary/src/xenia/kernel/kernel_state.cc#L427)
11. Main thread is resumed → host thread lambda runs `Execute()` → backend dispatches to PC = `entry_point_`. [xthread.cc:421-445, 469-471](xenia-canary/src/xenia/kernel/xthread.cc#L421-L471)
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](xenia-canary/src/xenia/cpu/thread_state.cc#L66-L112), unless otherwise noted.
### 1.1 GPRs
| Reg | Value | Source |
|----|----|----|
| r0 | 0 (memset) | [thread_state.cc:84](xenia-canary/src/xenia/cpu/thread_state.cc#L84) |
| **r1** (SP) | `stack_base` (top of stack, see §2) | [thread_state.cc:95](xenia-canary/src/xenia/cpu/thread_state.cc#L95) |
| **r2** | `0x20000000` (constant — comment: "used by hv only i think") | [thread_state.cc:98](xenia-canary/src/xenia/cpu/thread_state.cc#L98) |
| **r3** | `start_context` argument; for the main thread this is `0` (LaunchModule passes 0 as `start_context`, see [kernel_state.cc:414](xenia-canary/src/xenia/kernel/kernel_state.cc#L414)) | [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](xenia-canary/src/xenia/cpu/thread_state.cc#L100) |
| 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](xenia-canary/src/xenia/cpu/thread_state.cc#L104) |
| 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:103](xenia-canary/src/xenia/cpu/thread_state.cc#L103) — **Correction: Agent #1's claim of `0x00010016` was wrong; actual constant is `vec128i(0,0,0,0x00010000)`** |
| **VRSAVE** | `0xFFFFFFFF` | [thread_state.cc:111](xenia-canary/src/xenia/cpu/thread_state.cc#L111) — "closer to correct than 0" |
| DEC, TBL/TBU | 0 (memset) | — |
| PC | `entry_point_` extracted from XEX | [user_module.cc:230](xenia-canary/src/xenia/kernel/user_module.cc#L230), passed via [kernel_state.cc:415](xenia-canary/src/xenia/kernel/kernel_state.cc#L415) |
### 1.3 FPRs, VMX/VR
- All 32 FPRs zeroed by memset of `PPCContext` ([thread_state.cc:84](xenia-canary/src/xenia/cpu/thread_state.cc#L84)).
- 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](xenia-canary/src/xenia/cpu/thread_state.cc#L87-L92)):
- `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_state` — [xthread.cc:393](xenia-canary/src/xenia/kernel/xthread.cc#L393)
The context buffer itself is *guest-VA-aligned* so its low 32 bits end in `0xE0000000` — clever trick at [thread_state.cc:26-56](xenia-canary/src/xenia/cpu/thread_state.cc#L26-L56) 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](xenia-canary/src/xenia/memory.cc), [memory.h](xenia-canary/src/xenia/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](xenia-canary/src/xenia/kernel/xthread.h#L362-L363).
- **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](xenia-canary/src/xenia/kernel/xthread.cc#L275-L301):
- 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](xenia-canary/src/xenia/kernel/xthread.cc#L327-L361):
- Slots from `xex2_opt_tls_info.slot_count` if present, else **1024** (`kDefaultTlsSlotCount` [xthread.cc:335](xenia-canary/src/xenia/kernel/xthread.cc#L335)).
- 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](xenia-canary/src/xenia/kernel/xthread.cc#L379-L411): 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](xenia-canary/src/xenia/kernel/user_module.cc#L224)).
- Entry point + stack/tls/workspace sizes pulled via `GetOptHeader` ([user_module.cc:230-234](xenia-canary/src/xenia/kernel/user_module.cc#L230-L234)).
- 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](xenia-canary/src/xenia/kernel/user_module.cc#L237)).
---
## 3. Kernel / xboxkrnl Guest-Visible State
Verified directly against [src/xenia/kernel/xboxkrnl/xboxkrnl_module.cc](xenia-canary/src/xenia/kernel/xboxkrnl/xboxkrnl_module.cc) and [src/xenia/kernel/kernel_state.cc](xenia-canary/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](xenia-canary/src/xenia/kernel/xboxkrnl/xboxkrnl_module.cc#L80-L102) |
| **KeCertMonitorData** | same | `0` / struct + callback | [xboxkrnl_module.cc:104-123](xenia-canary/src/xenia/kernel/xboxkrnl/xboxkrnl_module.cc#L104-L123) |
| **XboxHardwareInfo** | 16 | `[0]=0x20` (HDD bit), `[4]=0x06` (CPU count), rest 0 | [xboxkrnl_module.cc:136-141](xenia-canary/src/xenia/kernel/xboxkrnl/xboxkrnl_module.cc#L136-L141) |
| **ExConsoleGameRegion** | 4 | `0xFFFFFFFF` | [xboxkrnl_module.cc:146-150](xenia-canary/src/xenia/kernel/xboxkrnl/xboxkrnl_module.cc#L146-L150) |
| **XexExecutableModuleHandle** | 4 | uninit at ctor; populated later when `SetExecutableModule` runs | [xboxkrnl_module.cc:161-164](xenia-canary/src/xenia/kernel/xboxkrnl/xboxkrnl_module.cc#L161-L164) |
| **ExLoadedImageName** | `kExLoadedImageNameSize` (1024-aligned) | uninit at ctor; filled later with module path | [xboxkrnl_module.cc:171-174](xenia-canary/src/xenia/kernel/xboxkrnl/xboxkrnl_module.cc#L171-L174) |
| **ExLoadedCommandLine** | aligned(strlen+1, 1024) | `"default.xex"` + optional `cvars::cl`, NUL-padded | [xboxkrnl_module.cc:181-194](xenia-canary/src/xenia/kernel/xboxkrnl/xboxkrnl_module.cc#L181-L194) |
| **XboxKrnlVersion** | 8 | `kernel_state_->GetKernelVersion()` (verify exact bytes in `kernel_state.h`) | [xboxkrnl_module.cc:199-204](xenia-canary/src/xenia/kernel/xboxkrnl/xboxkrnl_module.cc#L199-L204) |
| **KeTimeStampBundle** | 24 | populated lazily on first read via `GetKeTimestampBundle()` — see §3.2 | [xboxkrnl_module.cc:206-208](xenia-canary/src/xenia/kernel/xboxkrnl/xboxkrnl_module.cc#L206-L208) |
| **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](xenia-canary/src/xenia/kernel/xboxkrnl/xboxkrnl_module.cc#L214-L225) |
> **Correction vs Agent #3**: KeTimeStampBundle initialization does NOT happen in `xboxkrnl_module.cc`; it lives in `KernelState::CreateKeTimestampBundle` at [kernel_state.cc:1272-1295](xenia-canary/src/xenia/kernel/kernel_state.cc#L1272-L1295) 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](xenia-canary/src/xenia/kernel/kernel_state.cc#L1272-L1295):
| 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](xenia-canary/src/xenia/kernel/kernel_state.cc#L1292-L1294)).
### 3.3 KernelGuestGlobals — the big preinitialized blob
Allocated and zeroed at [kernel_state.cc:1511-1516](xenia-canary/src/xenia/kernel/kernel_state.cc#L1511-L1516); see the `KernelGuestGlobals` struct definition at [kernel_state.h:115-...](xenia-canary/src/xenia/kernel/kernel_state.h#L115). Fields include:
- `ExThreadObjectType`, `ExEventObjectType`, `ExMutantObjectType`, `ExSemaphoreObjectType`, `ExTimerObjectType`, `IoCompletionObjectType`, `IoDeviceObjectType`, `IoFileObjectType`, `ObDirectoryObjectType`, `ObSymbolicLinkObjectType`
- `UsbdBootEnumerationDoneEvent`
- `OddObj` (referenced [kernel_state.cc:1527](xenia-canary/src/xenia/kernel/kernel_state.cc#L1527))
- `system_process`, `title_process`, `idle_process` (accessor methods at [kernel_state.h:212, 216, 220](xenia-canary/src/xenia/kernel/kernel_state.h#L212-L220))
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](xenia-canary/src/xenia/kernel/xthread.cc#L317) via `CreateNative`).
- `XObject::kHandleBase = 0xF8000000`; handles spaced by 4.
---
## 4. XAM State
### 4.1 User profile
Created in `KernelState` ctor ([kernel_state.cc:52](xenia-canary/src/xenia/kernel/kernel_state.cc#L52)). 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](xenia-canary/src/xenia/kernel/kernel_state.h#L219)). 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](xenia-canary/src/xenia/kernel/kernel_state.cc#L657-L671)).
---
## 5. Filesystem State
### 5.1 Devices mounted at entrypoint
In `Emulator::LaunchTitle` / `Emulator::CreateVfsDevice` ([emulator.cc:376-...](xenia-canary/src/xenia/emulator.cc#L376)):
| 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](xenia-canary/src/xenia/gpu/graphics_system.cc#L79-L81):
```cpp
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](xenia-canary/src/xenia/gpu/command_processor.cc#L130-L148): 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](xenia-canary/src/xenia/gpu/graphics_system.cc#L135)), 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](xenia-canary/src/xenia/kernel/xboxkrnl/xboxkrnl_video.cc#L313-L319)).
### 6.4 MMIO
The GPU MMIO range `[0x7FC80000, 0xFFFF0000]` is hooked via `Memory::AddVirtualMappedRange` from `GraphicsSystem::Setup` ([graphics_system.cc:141-144](xenia-canary/src/xenia/gpu/graphics_system.cc#L141-L144)). 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](xenia-canary/src/xenia/gpu/graphics_system.cc#L116-L128)).
- `VdInitializeEngines` is stubbed to return 1 — xenia uses no real microcode ([xboxkrnl_video.cc:271-280](xenia-canary/src/xenia/kernel/xboxkrnl/xboxkrnl_video.cc#L271-L280)).
- 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](xenia-canary/src/xenia/kernel/xboxkrnl/xboxkrnl_video.cc#L203-L219) 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](xenia-canary/src/xenia/apu/audio_system.cc#L48-L97)) 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](xenia-canary/src/xenia/emulator.cc#L307)) initializes the input layer; per [src/xenia/hid/input_system.h:82-85](xenia-canary/src/xenia/hid/input_system.h#L82-L85):
- `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](xenia-canary/src/xenia/hid/input_system.cc#L179)).
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](xenia-canary/src/xenia/kernel/xam/xam_net.cc#L173)).
When queried via `NetDll_XNetGetTitleXnAddr` ([xam_net.cc:476-499](xenia-canary/src/xenia/kernel/xam/xam_net.cc#L476-L499)):
- 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](xenia-canary/src/xenia/base/clock.cc#L39)) returns the host CPU tick frequency unless overridden by `clock_no_scaling`. Reported to guest by `KeQueryPerformanceFrequency_entry` ([xboxkrnl_threading.cc:438-443](xenia-canary/src/xenia/kernel/xboxkrnl/xboxkrnl_threading.cc#L438-L443)).
- `KeQuerySystemTime_entry` ([xboxkrnl_threading.cc:483-497](xenia-canary/src/xenia/kernel/xboxkrnl/xboxkrnl_threading.cc#L483-L497)) 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](xenia-canary/src/xenia/kernel/xthread.cc#L420)), priority/affinity set via `GetFakeCpuNumber` derived from `(creation_flags >> 24)` ([xthread.cc:395-396](xenia-canary/src/xenia/kernel/xthread.cc#L395-L396)). CPU index assigned via `SetActiveCpu(cpu_index)` ([xthread.cc:464](xenia-canary/src/xenia/kernel/xthread.cc#L464)).
2. **Kernel dispatch worker thread** — spawned in `SetExecutableModule` to handle guest async callbacks ([kernel_state.cc:368-391 ~](xenia-canary/src/xenia/kernel/kernel_state.cc#L368-L391)). 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](xenia-canary/src/xenia/kernel/kernel_state.h#L233)).
---
## 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](xenia-canary/src/xenia/cpu/thread_state.cc#L77-L82)).
- 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](xenia-canary/src/xenia/kernel/xthread.cc#L389). 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 sanity**`KernelState::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](xenia-canary/src/xenia/kernel/kernel_state.cc#L1511) 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:
- [src/xenia/cpu/thread_state.cc](xenia-canary/src/xenia/cpu/thread_state.cc) — PPC context init (canonical truth for GPRs/MSR/VSCR/VRSAVE).
- [src/xenia/kernel/xthread.cc](xenia-canary/src/xenia/kernel/xthread.cc) — stack, TLS, KPCR, KTHREAD, host-thread creation, `Execute` dispatch.
- [src/xenia/kernel/kernel_state.cc](xenia-canary/src/xenia/kernel/kernel_state.cc) — LaunchModule, SetExecutableModule, KernelGuestGlobals, KeTimeStampBundle.
- [src/xenia/kernel/kernel_state.h](xenia-canary/src/xenia/kernel/kernel_state.h) — `KernelGuestGlobals` struct.
- [src/xenia/kernel/xboxkrnl/xboxkrnl_module.cc](xenia-canary/src/xenia/kernel/xboxkrnl/xboxkrnl_module.cc) — preinit'd guest-visible kernel-exported variables.
- [src/xenia/kernel/xboxkrnl/xboxkrnl_video.cc](xenia-canary/src/xenia/kernel/xboxkrnl/xboxkrnl_video.cc) — Vd* stubs.
- [src/xenia/kernel/xboxkrnl/xboxkrnl_threading.cc](xenia-canary/src/xenia/kernel/xboxkrnl/xboxkrnl_threading.cc) — KeQueryPerformanceFrequency / KeQuerySystemTime.
- [src/xenia/kernel/xam/xam_net.cc](xenia-canary/src/xenia/kernel/xam/xam_net.cc) — XNADDR and network defaults.
- [src/xenia/kernel/xam/user_profile.cc](xenia-canary/src/xenia/kernel/xam/user_profile.cc) — default user profile.
- [src/xenia/kernel/user_module.cc](xenia-canary/src/xenia/kernel/user_module.cc) — XEX header parsing, entry_point extraction.
- [src/xenia/emulator.cc](xenia-canary/src/xenia/emulator.cc) — Initialize/LaunchTitle subsystem order; VFS device factory.
- [src/xenia/gpu/graphics_system.cc](xenia-canary/src/xenia/gpu/graphics_system.cc) — GPU setup.
- [src/xenia/gpu/command_processor.cc](xenia-canary/src/xenia/gpu/command_processor.cc) — gamma ramp init, CP thread.
- [src/xenia/apu/audio_system.cc](xenia-canary/src/xenia/apu/audio_system.cc) — audio worker, client semaphores.
- [src/xenia/hid/input_system.h](xenia-canary/src/xenia/hid/input_system.h), [.cc](xenia-canary/src/xenia/hid/input_system.cc) — controller slots empty at entry.
- [src/xenia/memory.cc](xenia-canary/src/xenia/memory.cc), [.h](xenia-canary/src/xenia/memory.h) — heap topology, physical mirrors.
- [src/xenia/base/clock.cc](xenia-canary/src/xenia/base/clock.cc) — tick frequency, system time.