Phase C+8 — KeResetEvent canary-parity return value (sibling of C+7) ==================================================================== Scope: `crates/xenia-kernel/src/exports.rs` LOC: ~12 body + ~80 test = ~92 net Body change — `ke_reset_event` (~4160-4181): -------------------------------------------- -fn ke_reset_event(ctx: &mut PpcContext, mem: &GuestMemory, state: &mut KernelState) { - let h = ctx.gpr[3] as u32; - ensure_dispatcher_object(state, mem, h); - let previous = match state.objects.get_mut(&h) { - Some(KernelObject::Event { signaled, .. }) => { - let prev = *signaled; - *signaled = false; - prev as u32 - } - _ => 0, - }; - ctx.gpr[3] = previous as u64; -} +fn ke_reset_event(ctx: &mut PpcContext, mem: &GuestMemory, state: &mut KernelState) { + // r3 = PKEVENT on Ke* (guest pointer). See `ensure_dispatcher_object` + // for the lazy-shadow step. + let h = ctx.gpr[3] as u32; + ensure_dispatcher_object(state, mem, h); + // Canary parity (xevent.cc:72-75): `XEvent::Reset` returns constant `1` + // on success — exact sibling of `XEvent::Set`. The NT contract claims + // the prior signaled state, but canary hardcodes `1` and the game + // observes that value via Phase A oracle at idx=102164. Sibling fix + // of Phase C+7 KeSetEvent (xevent.cc:60-64). The `assert_always; + // return 0` arm is preserved (no shadow -> 0). + let (previous, found) = match state.objects.get_mut(&h) { + Some(KernelObject::Event { signaled, .. }) => { + let prev = *signaled; + *signaled = false; + (prev as u32, true) + } + _ => (0u32, false), + }; + state.audit_signal(h, ctx.lr as u32, "KeResetEvent", previous as u64); + ctx.gpr[3] = if found { 1 } else { 0 }; +} Existing test (~5631-5647) comment-only update: ----------------------------------------------- - assert_eq!(ctx.gpr[3], 1, "previous state must be reported"); + assert_eq!(ctx.gpr[3], 1, "canary parity: KeResetEvent returns constant 1 on hit"); (plus updated doc explaining canary parity) New tests added at module end (mirror of C+7's KeSetEvent block): ----------------------------------------------------------------- // Phase C+8 -- KeResetEvent canary-parity return value (sibling of C+7) 1. ke_reset_event_returns_constant_one_on_unsignaled_manual_reset (this is THE Phase A oracle case -- prior state 0, canary returns 1) 2. ke_reset_event_returns_constant_one_on_signaled_auto_reset (distinguish from prior-state-return bug: prior 1 == constant 1) 3. ke_reset_event_returns_zero_on_missing_object (canary's `assert_always; return 0` arm -- invalid handle) 4. nt_clear_event_resets_shadow_and_returns_status_success (already canary-parity; symmetry coverage) `nt_clear_event` body: no change. Canary `NtClearEvent_entry` calls `xeNtClearEvent` which uses `XEvent::Clear` (void return); already returning STATUS_SUCCESS in ours. Cascade outcome: ---------------- - A=verify canary's return: DONE, `1` confirmed from xevent.cc:72-75 - B=land fix: DONE - C=main chain advances past 102164: DONE -- 102164 -> 102197 (+33) - D=clean re-validation: DONE - E=no escalation: DONE (12-LOC body change, additive tests only) Next target: XamContentCreateEnumerator at tid=6->1 idx=102197 canary return_value=1317 (0x525 = X_ERROR_NO_CONTENT) ours return_value=0 (likely STATUS_SUCCESS or missing impl)