From ed9212e4bfb02ffc271231159dece80b025d0217 Mon Sep 17 00:00:00 2001 From: Julian Uy Date: Thu, 18 Dec 2025 20:51:35 -0600 Subject: [PATCH 1/2] fix: [mcserv] use switch statement for functions Re-add compat for older RPC with newer modules --- iop/memorycard/mcserv/src/mcserv.c | 217 +++++++++++++++-------------- 1 file changed, 113 insertions(+), 104 deletions(-) diff --git a/iop/memorycard/mcserv/src/mcserv.c b/iop/memorycard/mcserv/src/mcserv.c index ebb2a30c7cfb..29dfc489f130 100644 --- a/iop/memorycard/mcserv/src/mcserv.c +++ b/iop/memorycard/mcserv/src/mcserv.c @@ -16,84 +16,6 @@ // 0x02,0x08 IRX_ID(MODNAME, 2, 8); -#ifdef BUILDING_XMCSERV -static const u8 XMCSERV_RpcCmd[2][16] = -{ // libmc rpc cmd values for XMCMAN/XMCSERV - { 0xFE, // CMD_INIT - 0x01, // CMD_GETINFO - 0x02, // CMD_OPEN - 0x03, // CMD_CLOSE - 0x04, // CMD_SEEK - 0x05, // CMD_READ - 0x06, // CMD_WRITE - 0x0A, // CMD_FLUSH - 0x0C, // CMD_CHDIR - 0x0D, // CMD_GETDIR - 0x0E, // CMD_SETFILEINFO - 0x0F, // CMD_DELETE - 0x10, // CMD_FORMAT - 0x11, // CMD_UNFORMAT - 0x12, // CMD_GETENTSPACE - 0x33 // CMD_CHECKBLOCK (calls xmcman_funcs: 45) - }, - { // corresponding internal rpc function - 0x00, // sceMcInit - 0x12, // sceMcGetInfo2 - 0x01, // sceMcOpen - 0x02, // sceMcClose - 0x05, // sceMcSeek - 0x11, // sceMcRead2 - 0x04, // sceMcWrite - 0x0A, // sceMcFlush - 0x0B, // sceMcChDir - 0x06, // sceMcGetDir - 0x0C, // sceMcSetFileInfo - 0x09, // sceMcDelete - 0x07, // sceMcFormat - 0x10, // sceMcUnformat - 0x13, // sceMcGetEntSpace - 0x14 // sceMcCheckBlock (calls xmcman_funcs: 45) - } -}; -#endif - -// rpc command handling array -static void *rpc_funcs_array[21] = { - (void *)sceMcInit, - (void *)sceMcOpen, - (void *)sceMcClose, - (void *)sceMcRead, - (void *)sceMcWrite, - (void *)sceMcSeek, - (void *)sceMcGetDir, - (void *)sceMcFormat, - (void *)sceMcGetInfo, - (void *)sceMcDelete, - (void *)sceMcFlush, - (void *)sceMcChDir, - (void *)sceMcSetFileInfo, - (void *)sceMcEraseBlock, - (void *)sceMcReadPage, - (void *)sceMcWritePage, - (void *)sceMcUnformat, - (void *)sceMcRead2, -#ifdef BUILDING_XMCSERV - (void *)sceMcGetInfo2, -#else - (void *)NULL, -#endif -#ifdef BUILDING_XMCSERV - (void *)sceMcGetEntSpace, -#else - (void *)NULL, -#endif -#ifdef BUILDING_XMCSERV - (void *)sceMcCheckBlock, -#else - (void *)NULL, -#endif -}; - static int mcserv_tidS_0400; static int mcserv_in_rpc_0400 = 0; @@ -196,40 +118,127 @@ void thread_rpc_S_0400(void* arg) //-------------------------------------------------------------- void *cb_rpc_S_0400(u32 fno, void *buf, int size) { - // Rpc Callback function - int (*rpc_func)(void); + int need_replace_bad_block; (void)buf; (void)size; -#ifdef BUILDING_XMCSERV - { - register int i; - - for (i=0; i<16; i++) { // retrieve correct function number for xmcserv - if (fno == XMCSERV_RpcCmd[0][i]) { - fno = XMCSERV_RpcCmd[1][i]; - break; - } - } - } -#else - { // retrieve correct function number for mcserv - fno -= 112; - if (fno > 16) - return (void *)&rpc_stat; - } -#endif - - // Get function pointer - rpc_func = (void *)rpc_funcs_array[fno]; + need_replace_bad_block = 1; mcserv_in_rpc_0400 = 1; - // Call needed rpc func - rpc_stat.result = rpc_func(); + switch (fno) + { + case 0x70: +#ifdef BUILDING_XMCSERV + case 0xFE: // CMD_INIT +#endif + rpc_stat.result = sceMcInit(); + break; + case 0x71: +#ifdef BUILDING_XMCSERV + case 0x02: // CMD_OPEN +#endif + rpc_stat.result = sceMcOpen(); + break; + case 0x72: +#ifdef BUILDING_XMCSERV + case 0x03: // CMD_CLOSE +#endif + rpc_stat.result = sceMcClose(); + break; + case 0x73: + rpc_stat.result = sceMcRead(); + break; + case 0x74: +#ifdef BUILDING_XMCSERV + case 0x06: // CMD_WRITE +#endif + rpc_stat.result = sceMcWrite(); + break; + case 0x75: +#ifdef BUILDING_XMCSERV + case 0x04: // CMD_SEEK +#endif + rpc_stat.result = sceMcSeek(); + break; + case 0x76: +#ifdef BUILDING_XMCSERV + case 0x0D: // CMD_GETDIR +#endif + rpc_stat.result = sceMcGetDir(); + break; + case 0x77: +#ifdef BUILDING_XMCSERV + case 0x10: // CMD_FORMAT +#endif + rpc_stat.result = sceMcFormat(); + break; + case 0x78: + rpc_stat.result = sceMcGetInfo(); + break; + case 0x79: +#ifdef BUILDING_XMCSERV + case 0x0F: // CMD_DELETE +#endif + rpc_stat.result = sceMcDelete(); + break; + case 0x7A: +#ifdef BUILDING_XMCSERV + case 0x0A: // CMD_FLUSH +#endif + rpc_stat.result = sceMcFlush(); + break; + case 0x7B: +#ifdef BUILDING_XMCSERV + case 0x0C: // CMD_CHDIR +#endif + rpc_stat.result = sceMcChDir(); + break; + case 0x7C: +#ifdef BUILDING_XMCSERV + case 0x0E: // CMD_SETFILEINFO +#endif + rpc_stat.result = sceMcSetFileInfo(); + break; + case 0x7D: + rpc_stat.result = sceMcEraseBlock(); + break; + case 0x7E: + rpc_stat.result = sceMcReadPage(); + break; + case 0x7F: + rpc_stat.result = sceMcWritePage(); + break; + case 0x80: +#ifdef BUILDING_XMCSERV + case 0x11: // CMD_UNFORMAT +#endif + rpc_stat.result = sceMcUnformat(); + break; +#ifdef BUILDING_XMCSERV + case 0x01: // CMD_GETINFO + rpc_stat.result = sceMcGetInfo2(); + break; + case 0x05: // CMD_READ + rpc_stat.result = sceMcRead2(); + break; + case 0x12: // CMD_GETENTSPACE + rpc_stat.result = sceMcGetEntSpace(); + break; + case 0x33: // CMD_CHECKBLOCK (calls xmcman_funcs: 45) + rpc_stat.result = sceMcCheckBlock(); + break; +#endif + default: + // Do not set a result value + // (needed for detection of version by libmc) + need_replace_bad_block = 0; + break; + } - McReplaceBadBlock(); + if (need_replace_bad_block) + McReplaceBadBlock(); mcserv_in_rpc_0400 = 0; From 1269cb4cd47878f01d48610b74e3f9e83742a848 Mon Sep 17 00:00:00 2001 From: Julian Uy Date: Thu, 18 Dec 2025 20:52:13 -0600 Subject: [PATCH 2/2] feat: [libmc] automatically detect and use RPC variant --- ee/rpc/memorycard/include/libmc.h | 7 +- ee/rpc/memorycard/src/libmc.c | 102 ++++++++++++++++++++---------- 2 files changed, 71 insertions(+), 38 deletions(-) diff --git a/ee/rpc/memorycard/include/libmc.h b/ee/rpc/memorycard/include/libmc.h index f0662bda3941..66a9b6710782 100644 --- a/ee/rpc/memorycard/include/libmc.h +++ b/ee/rpc/memorycard/include/libmc.h @@ -15,8 +15,8 @@ /* NOTE: These functions will work with the MCMAN/MCSERV or XMCMAN/XMCSERV - modules stored in rom0. To determine which one you are using, send the - appropriate arg to the mcInit() function (MC_TYPE_MC or MC_TYPE_XMC) + modules stored in rom0. The library will automatically detect which + module is used and will use the appropriate RPC commands accordingly. NOTE: These functions seem to work for both psx and ps2 memcards @@ -193,6 +193,7 @@ typedef struct } mcTable __attribute__((deprecated, aligned (64))); // values to send to mcInit() to use either mcserv or xmcserv +// These definitions are retained for backwards compatibility #define MC_TYPE_MC 0 #define MC_TYPE_XMC 1 @@ -202,7 +203,7 @@ extern "C" { /** init memcard lib * - * @param type MC_TYPE_MC = use MCSERV/MCMAN; MC_TYPE_XMC = use XMCSERV/XMCMAN + * @param type Retained for backwards compatibility. Nominally specify MC_TYPE_MC. * @return 0 = successful; < 0 = error */ extern int mcInit(int type); diff --git a/ee/rpc/memorycard/src/libmc.c b/ee/rpc/memorycard/src/libmc.c index 5bebca2e9d1f..e191800269d5 100644 --- a/ee/rpc/memorycard/src/libmc.c +++ b/ee/rpc/memorycard/src/libmc.c @@ -230,9 +230,11 @@ static void mcStoreDir(void* arg) int mcInit(int type) { int ret=0; + int err=0; mcRpcStat_t *rpcStat = (mcRpcStat_t*)UNCACHED_SEG(&g_rdata.rpcStat); static int _rb_count = 0; + (void)type; if(_rb_count != _iop_reboot_count) { _rb_count = _iop_reboot_count; @@ -244,9 +246,6 @@ int mcInit(int type) sceSifInitRpc(0); - // set which modules to use - g_mcType = type; - // bind to mc rpc on iop do { @@ -266,65 +265,98 @@ int mcInit(int type) // for some reason calling this init sif function with 'mcserv' makes all other // functions not work properly. although NOT calling it means that detecting // whether or not cards are formatted doesnt seem to work :P - if(g_mcType == MC_TYPE_MC) - { + + // Start with calling flush with an invalid fd (so it sets the return value to + // sceMcResDeniedPermit, which MC_RPCCMD_INIT will not return) + g_descParam.fd = 0xFFFFFFFF; + sceSifCallRpc(&g_cdata, mcRpcCmd[MC_TYPE_XMC][MC_RPCCMD_FLUSH], 0, &g_descParam, sizeof(g_descParam), &g_rdata, 4, NULL, NULL); + sceSifCallRpc(&g_cdata, mcRpcCmd[MC_TYPE_MC][MC_RPCCMD_FLUSH], 0, &g_descParam, sizeof(g_descParam), &g_rdata, 4, NULL, NULL); #ifdef MC_DEBUG - printf("libmc: using MCMAN & MCSERV\n"); + printf("libmc: using XMCMAN & XMCSERV\n"); +#endif + // Try XMCSERV RPC + g_mcType = MC_TYPE_XMC; + // call init function + if((ret = sceSifCallRpc(&g_cdata, mcRpcCmd[g_mcType][MC_RPCCMD_INIT], 0, &g_descParam, sizeof(g_descParam), &g_rdata, 12, NULL, NULL)) < 0) + { + // init error +#ifdef MC_DEBUG + printf("libmc: initialisation error\n"); #endif - g_descParam.offset = -217; + err = ret - 100; + } - // call init function - if((ret = sceSifCallRpc(&g_cdata, mcRpcCmd[g_mcType][MC_RPCCMD_INIT], 0, &g_descParam, sizeof(g_descParam), &g_rdata, 4, NULL, NULL))>=0) + // If result was sceMcResDeniedPermit, RPC was unhandled + if (!err && rpcStat->result == sceMcResDeniedPermit) + { + err = -122; + } + + if (!err) + { + // check if old version of mcserv loaded + if (rpcStat->mcserv_version < 0x205) { - ret = g_rdata.result; +#ifdef MC_DEBUG + printf("libmc: mcserv is too old (%x)\n", rpcStat->mcserv_version); +#endif + err = -120; } - else{ - // init error + + // check if old version of mcman loaded + if (rpcStat->mcman_version < 0x206) + { #ifdef MC_DEBUG - printf("libmc: initialisation error\n"); + printf("libmc: mcman is too old (%x)\n", rpcStat->mcman_version); #endif - g_mclibInited = 0; - return g_rdata.result - 100; + err = -121; } } - else if(g_mcType == MC_TYPE_XMC) + + if (!err) + { + ret = rpcStat->result; + } + + if (err && rpcStat->result == sceMcResDeniedPermit) { + err = 0; + + // Try MCSERV RPC + g_mcType = MC_TYPE_MC; #ifdef MC_DEBUG - printf("libmc: using XMCMAN & XMCSERV\n"); + printf("libmc: using MCMAN & MCSERV\n"); #endif + g_descParam.offset = -217; + // call init function - if((ret = sceSifCallRpc(&g_cdata, mcRpcCmd[g_mcType][MC_RPCCMD_INIT], 0, &g_descParam, sizeof(g_descParam), &g_rdata, 12, NULL, NULL)) < 0) + if((ret = sceSifCallRpc(&g_cdata, mcRpcCmd[g_mcType][MC_RPCCMD_INIT], 0, &g_descParam, sizeof(g_descParam), &g_rdata, 4, NULL, NULL)) < 0) { // init error #ifdef MC_DEBUG printf("libmc: initialisation error\n"); #endif - g_mclibInited = 0; - return ret - 100; + err = ret - 100; } - // check if old version of mcserv loaded - if(rpcStat->mcserv_version < 0x205) + // If result was sceMcResDeniedPermit, RPC was unhandled + if (!err && rpcStat->result == sceMcResDeniedPermit) { -#ifdef MC_DEBUG - printf("libmc: mcserv is too old (%x)\n", rpcStat->mcserv_version); -#endif - g_mclibInited = 0; - return -120; + err = -122; } - // check if old version of mcman loaded - if(rpcStat->mcman_version < 0x206) + if (!err) { -#ifdef MC_DEBUG - printf("libmc: mcman is too old (%x)\n", rpcStat->mcman_version); -#endif - g_mclibInited = 0; - return -121; + ret = g_rdata.result; } - ret = rpcStat->result; + } + + if (err) + { + g_mclibInited = 0; + return err; } // successfully inited