Repository navigation
fix(iop): accept temporary IOP sids (bit31) and answer the loader queue's cid-0 SifSendCmd with a completion reply - #404
Open
LeandroSSB wants to merge 1 commit into
Open
LeandroSSB wants to merge 1 commit into
LeandroSSB wants to merge 1 commit into
Conversation
…-0 SifSendCmd with a completion reply Two contract gaps in the EE-side SIF path: 1. Games' IOP glue requests *temporary* sids (bit31 set, e.g. 0x80000006 for the module-query channel). SifBindRpc refused them (no registered route, no emulated server), so client->server stayed null forever and the SDK glue spun in its bind-retry wall (on MOH:Vanguard: a 0x100000-iteration delay loop at the module-presence check, boot frozen). SifBindRpc now allocates the server descriptor for the temporary range; registered-sid handling and plain-sid refusal are unchanged. 2. The game's loader queue issues sceSifSendCmd(cid=0) requests whose completion is signaled by an IOP-authored cid=1 reply carrying the same handle; the runtime let the request vanish, so the consumer polled a ticket that never retired. sceSifSendCmd now synthesizes the 32-byte cid=1 completion reply for cid=0 requests of >= 0x18 bytes: [+0xC] = the request packet's +0x14 handle (echoed verbatim), [+0x10] = 2 (the complete-record status), dispatched through the existing ps2_stubs::dispatchSifCommand so the game's own registered handler runs as a queued EE invocation. The handler reads exactly +0xC (handle) and +0x10 (selector); delivery is a verbatim memcpy of the request block. cid != 0 traffic (the game's own reply direction) is never echoed. Also answer SifCallRpc with rpc 0xFF and a 4-byte receive buffer with the "2800" version tag the glue's version probe accepts instead of zeros, so the module-query init completes its version match. Tests (ps2_sif_rpc_tests, ps2_sif_dma_tests): bind of a bit31 sid completes the handshake and stays stable across clients; plain unregistered sids still refuse; the version probe answers the accepted tag while other unhandled rpcs keep the zero fallback; a cid=0 command yields exactly one synthesized cid=1 reply with the echoed handle, consumed by the game's registered completion handler. Co-Authored-By: Claude Code <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Root cause (two contract gaps in the EE-side SIF path)
0x80000006for its module-query channel).SifBindRpconly served registered routes / emulated servers, soclient->serverstayed null forever and the SDK glue spun in its bind-retry wall — on MOH:Vanguard a 0x100000-iteration delay loop at the module-presence check, boot frozen at 199 CD reads.sceSifSendCmd(cid=0); completion is signaled by an IOP-authoredcid=1reply carrying the same handle. The runtime let the request vanish, so the consumer polled a ticket that never retired (measured: exactly one SifSendCmd in the whole run, ack frozen while the producer counter grew).Fix
SifBindRpcallocates the server descriptor for sids with bit31 set (the temporary per-function range games use for their own IOP modules); registered-sid handling and plain-sid refusal are unchanged.sceSifSendCmdsynthesizes the 32-bytecid=1completion reply forcid=0requests of >= 0x18 bytes:[+0xC]= the request packet's+0x14handle echoed verbatim,[+0x10]= 2 (complete status), dispatched through the existingps2_stubs::dispatchSifCommandso the game's own registered cmd handler runs as a queued EE invocation. The reply shape is audited against the game's handler: it reads exactly+0xC(handle) and+0x10(selector); the other bytes are never loaded.cid != 0traffic (the game's own reply direction) is never echoed.SifCallRpcwith rpc0xFFand a 4-byte receive buffer answers the"2800"version tag the glue's version probe accepts instead of zeros, so the module-query init completes its version match.Test
ps2_sif_rpc_tests/ps2_sif_dma_tests: bind of a bit31 sid completes the handshake and stays stable across clients; plain unregistered sids still refuse; the version probe answers the accepted tag while other unhandled rpcs keep the zero fallback; a cid=0 command yields exactly one synthesized cid=1 reply with the echoed handle, consumed by a registered completion handler (semaphore-parked consumer wakes and observes the reply fields).Measured (MOH:Vanguard)
SDK bind-retry wall extinct (boot-thread park 0 of 260+ samples, was ~77%); CD reads resume 199 → 226; after the reply fix the loader poll region is extinct and the main thread leaves the loader for engine code.
Note: this PR deliberately carries no address-specific diagnostics — the bring-up probes used to decode the two contracts are not part of the fix.
Related: #339 delivers
sceSifSendCmdto the IOP and modelsSIF_CMD_SET_SREG— a different slice of the same surface; it does not synthesize the cid-1 completion reply nor accept the bit31 bind, so the two are complementary.🤖 Generated with Claude Code
Suite evidence
Fresh configure+build of
ps2x_testson this branch (VS 2022, Release): 451/451 passed, 0 failed.