From 5d2401f9c539b7e4aa8717a8c4541f62c7b7c541 Mon Sep 17 00:00:00 2001 From: MechaCat02 Date: Wed, 6 May 2026 20:08:13 +0200 Subject: [PATCH] fix(xam): XamUserGetSigninState returns SignedInLocally=1 for user 0 Mirrors canary xam_user.cc:90-101. User 0 returns 1 (SignedInLocally), all other indices return 0. Replaces stub_return_zero registration that was reaching guest-side branches looking up signin state. Tests: 599 -> 600. Co-Authored-By: Claude Opus 4.7 (1M context) --- crates/xenia-kernel/src/xam.rs | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/crates/xenia-kernel/src/xam.rs b/crates/xenia-kernel/src/xam.rs index d794748..9950e45 100644 --- a/crates/xenia-kernel/src/xam.rs +++ b/crates/xenia-kernel/src/xam.rs @@ -45,7 +45,7 @@ pub fn register_exports(state: &mut KernelState) { // User state.register_export(Xam, 0x020A, "XamUserGetXUID", xam_user_get_xuid); state.register_export(Xam, 0x020E, "XamUserGetName", xam_user_get_name); - state.register_export(Xam, 0x0210, "XamUserGetSigninState", stub_return_zero); + state.register_export(Xam, 0x0210, "XamUserGetSigninState", xam_user_get_signin_state); state.register_export(Xam, 0x0219, "XamUserReadProfileSettings", xam_user_read_profile_settings); state.register_export(Xam, 0x021A, "XamUserWriteProfileSettings", stub_success); @@ -329,6 +329,12 @@ fn xam_user_read_profile_settings(ctx: &mut PpcContext, _mem: &GuestMemory, _sta ctx.gpr[3] = 0x0000_048B; // ERROR_NOT_FOUND } +fn xam_user_get_signin_state(ctx: &mut PpcContext, _mem: &GuestMemory, _state: &mut KernelState) { + // r3 = user_index + let user_index = ctx.gpr[3] as u32; + ctx.gpr[3] = if user_index == 0 { 1 } else { 0 }; +} + // ===== System ===== fn xam_get_execution_id(ctx: &mut PpcContext, mem: &GuestMemory, state: &mut KernelState) { @@ -572,6 +578,22 @@ mod tests { assert_eq!(ctx.gpr[3], 8); } + #[test] + fn xam_user_get_signin_state_user0_signed_in_locally() { + let (mut ctx, mem, mut state) = fresh(); + ctx.gpr[3] = 0; + xam_user_get_signin_state(&mut ctx, &mem, &mut state); + assert_eq!(ctx.gpr[3], 1); + + ctx.gpr[3] = 1; + xam_user_get_signin_state(&mut ctx, &mem, &mut state); + assert_eq!(ctx.gpr[3], 0); + + ctx.gpr[3] = 4; + xam_user_get_signin_state(&mut ctx, &mem, &mut state); + assert_eq!(ctx.gpr[3], 0); + } + fn drain_notifications(state: &mut KernelState, mem: &GuestMemory, handle: u32) -> Vec<(u32, u32)> { let id_ptr = SCRATCH_BASE + 0x100; let param_ptr = SCRATCH_BASE + 0x104;