Snapshot for handoff. Contains the mission-audio + threading fixes and the
crash-investigation instrumentation (all diagnostic cvars default-OFF).
Fixes (behavioral):
- threading_posix.cc: reap-once guard on PosixCondition<Thread>::post_execution
(double pthread_join at mission teardown -> fault loop -> audio death + freeze).
- xma_decoder.cc: work_event_->Set() in Pause() so the idle XMA worker observes
paused_ and signals pause_fence_ (Pause() deadlock -> permanent audio death).
- audio_system / xma_context_master / xboxkrnl_audio / apu_flags / alsa: mission
audio keepalive + guest_audio_flags + watchdogs.
Instrumentation (additive, default-off): xboxkrnl_debug cache-throw diag +
guest-catch dispatcher, xex_module PE/PDATA/EH scans, kernel_state mem_watch
(NOTE: mem_watch DEFAULTS TRUE -- an always-on host poll thread; prime crash suspect).
NEW ORACLE (see HANDOFF-crash-oracle-2026-07-16.md): stock 6e5b8324f built with
our toolchain + zero custom code = NO crash, NO sound-stop, plays the Ready Room.
=> the Ready-Room out_of_range crash is introduced by THESE changes, not the game
and not the (LTO-broken) build chain. Bisection plan + suspect ranking in the note.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Adds AUDIT-HLC probes for every path that signals an XEvent or duplicates
its handle, so the round-23 puzzle (waits completing without visible
NtSetEvent/KeSetEvent) can be cross-referenced by underlying X_KEVENT VA
and by primary handle.
* NtCreateEvent_inner: always log kevent_va for handle/VA cross-ref
* XEvent::Set: universal hook prints primary handle + kevent_va + LR;
catches all paths into the event regardless of shim used
* NtSetEvent: extended with PPC back-chain walk for caller's guest_lr
(same idiom as the wait probe), so the signaler function is
immediately identifiable
* NtReadFile / NtReadFileScatter / NtWriteFile: log when signal_event
path fires ev->Set() inline at IO completion (bypasses both
NtSetEvent and KeSetEvent shims)
* CompleteOverlappedEx (kernel_state.cc): log when overlapped event
is signaled at completion
* NtDuplicateObject: log src/dst handle pair (round-24 confirmed silph
event is dup'd before signaling, explaining the handle-mismatch
puzzle between NtSetEvent's `handle=` argument and XEvent::Set's
primary handle())
Result: silph wait at sub_821CB030+0x1B0 on handle F80000A0 is signaled
via NtSetEvent on handle F80000A8 (the duplicate created by sub_8245D9D8
at lr=0x82450DF4 inside the worker chain sub_82450A28 ← 0xA68 ← 0xB68).
Verdict A confirmed: signaler exists and is reachable, but round-17.β
missed it because the search keyed on the wrong handle. No bypass path;
the worker chain is identical between canary and ours-impl, but ours
signals different handles (work-item queue divergence at sub_82452DC0).
Audit-only diagnostic. No semantic changes. Net delta +86 LOC across 7
files. All probes gated on the existing audit_handle_lifecycle cvar
(default off). Tested via Sylpheed boot (35 s, 4 MB log). Audit-handle-
lifecycle-probes branch, local-only.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Round-14 of AUDIT-2BF (singleton-dump). Pairs with xenia-rs'
--audit-mem-read-hex to emit one comparable XELOGKERNEL line resolving
the bctrl target at sub_822F1AA8+0x90 (PC 0x822F1B4C):
[0x828E1F08] -> singleton instance ptr
[singleton+0] -> vtable
[vtable+0] -> vtable[0] (= first virtual method, bctrl tgt)
[vtable+24] -> vtable[24] (= slot 6, silph chain target)
Two complementary hooks:
1. src/xenia/cpu/backend/x64/x64_emitter.cc: extend
AuditLogJitPrologArgs. New cvar `audit_jit_prolog_mem_dump` (uint32).
When non-zero and an `audit_jit_prolog_pc` fire happens, the host
side dereferences the VA 3 levels deep and emits one
AUDIT-MEM-READ line in the same format ours emits. Defensive
per-level null + VA-range checks.
2. src/xenia/kernel/kernel_state.cc: one-shot dump in
EmulateCPInterruptDPC of the same chain (hard-coded to
0x828E1F08). Useful when audit_jit_prolog_pc isn't set; fires the
first time the CP interrupt path runs (after the singleton ctor
has had time to populate).
Read-only. Both gates default-off; no impact when cvars unset.
~65 LOC total across the two files.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
New cvar `audit_handle_lifecycle` (Auditing group, default false).
When enabled, emits one-line XELOGKERNEL traces tagged AUDIT-HLC at:
NtCreateEvent return, NtSetEvent entry, KeSetEvent entry,
NtWaitForSingleObjectEx entry + completion,
EmulateCPInterruptDPC entry.
Observation-only: zero-overhead when cvar off (single branch + flag
read). Intended for handle disambiguation between xenia-rs and
canary under the Wine cross-build oracle.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- Change OddObj to X_DISPATCH_HEADER
- Add unknown X_KWAIT_REASON flag
- Fixed InitializeGuestObject mistake
- Replaces unknowns in kthread using nukernel as reference
Previous global TLS bitmap was shared across all processes. Now
per-process TLS bitmaps stored X_KPROCESS structures which should
better match Xbox360 architecture.
When a thread wakes from a kernel wait, the Xenon scheduler boosts its
effective priority by the increment passed to the signaling call
(KeSetEvent, KeReleaseSemaphore, KeReleaseMutant). The boost is clamped
to the per-thread max_dynamic_priority cap, respects the guest
boost_disabled flag, and is drained on the next quantum expiry.
Guest KTHREAD priority fields are now initialized from parent process
defaults, and the previously unknown fields involved have been renamed
to match their identified purpose.
And default ignore_thread_priorities to false.
Map Xenon's 0-31 priority range across all 5 host priority levels
instead of collapsing 0-17 into kNormal.
Use timer-driven quantum decay (~20ms period) matching Xenon's
60-quantum / 3-per-tick cycle to prevent starvation by gradually lowering
effective priority for non-real-time threads (< 18), piggybacking on the
existing 1ms timestamp timer.
Some games persist BGM volume through their own save files but never
call XMPSetVolume. Add a TitlePatch system that intercepts NtReadFile/
NtWriteFile to apply game-specific logic as well as logic to identify
the memory location that the volume data is read into and monitor that
memory location for changes, updating XMP player volume if it changes
during gameplay.
Includes patches for known games with this issue:
Dead or Alive Xtreme 2 (544307D2), PGR4 (4D5307F9) and PGR3 (4D5307D1)
- Added handling (partial or dummy) for SMC actions:
- QUERY_TEMP_SENSOR, QUERY_TRAY, QUERY_AV_PACK, QUERY_SMC_VERSION, QUERY_IR_ADDRESS, QUERY_TILT_SENSOR
- SET_FAN_SPEED_CPU, SET_FAN_SPEED_GPU, SET_DVD_TRAY, SET_IR_ADDRESS, SET_POWER_LED, SET_LEDS
- Stub HalOpenCloseODDTray, XamLoaderGetMediaInfo, XamLoaderGetMediaInfoEx
- Partially Implement HalSendSMCMessage
- Implement XamLoaderGetDvdTrayState
- HalOpenCloseODDTray is used by dash and HalSendSMCMessage can be used by custom dashboards
- Discovered new unknown kXNotificationID use by XNotifyBroadcast together and wanted to record them before I forget them.
- Changed kXNotificationID to kXNotification
- Added kXNotificationSystemPXLiveSystemUpdate
Externally it is still applied via: ApplyTitleUpdate
But internally it is splitted into:
- FindTitleUpdate
- LoadTitleUpdate
- IsPatchSignatureProper
- ApplyTitleUpdate
Added host window with warning about TU incompatibility
Based off of pull request xenia-project#2047. Convert magic numbers numbers to enum to improve readability. Includes currently unused one for future use.