Psp go internal storage fix (#19100)

* fix(psp): derive user data path from launch device vice hardcoded ms0:

- Extract the storage prefix (ms0:/ or ef0:/) from the executable's path
  so user data lives on the same device RetroArch was launched from in
  order to fix PSP Go EF0 storage compatibility
- Fall back to ms0:/ when the path doesn't contain a recognizable device
  prefix

* fix(bootstrap): use sceKernelLoadExecVSHEf2 for ef0: paths on PSP Go

On PSP Go installs to internal flash RetroArch relaunches cores through
sceKernelLoadExecVSHMs2, the Memory Stick loader, which fails when
handed an ef0: path. Route ef0: targets through the internal flash
loader instead so core loads and relaunches work from internal storage.

- Add LoadExecEf.S importing sceKernelLoadExecVSHEf2 (NID 0x032A7938)
  from the LoadExecForKernel PRX, ms0: and all other paths keep using
  sceKernelLoadExecVSHMs2
- Branch on the ef0: prefix in exitspawn_kernel (main.c)
- Add LoadExecEf.o to the PRX Makefile OBJS

NID 0x032A7938 is documented in uOFW (src/kd/loadexec) and PSPLibDoc
(PSPGoLibDoc/6.61), the sceKernelLoadExecVSHEf2 name is just an alias
for the otherwise unnamed export. Tested on PSP Go (6.61 CFW). Core swap
loads from ef0: with config persisting, ms0: path is unchanged so no
regression.

* fix(bootstrap): add LoadExecEf.o to PRX OBJS so the EF2 import links

The previous commit added LoadExecEf.S with the sceKernelLoadExecVSHEf2
import stub but forgot to wire it into the PRX build, so the object
never got compiled in and the link failed with an undefined reference
and the PSP CI caught it. Adding LoadExecEf.o to OBJS fixes it so the
stub assembles and the EF2 loader resolves at link time.

---------

Co-authored-by: Zadeis <[email protected]>
This commit is contained in:
tylerbibandZadeis authored and GitHub committed 2026-06-12 04:14:07 +02:00
1 parent f02918957b
commit a57c0cbfe0
4 files changed
+26 -3

No files matched your search

@@ -0,0 +1,6 @@
.set noreorder
#include "pspimport.s"
IMPORT_START "LoadExecForKernel",0x00010000
IMPORT_FUNC "LoadExecForKernel",0x032A7938,sceKernelLoadExecVSHEf2
+1 -1
View File
@@ -1,5 +1,5 @@
TARGET = kernel_functions
OBJS = main.o
OBJS = main.o LoadExecEf.o
PSP_FW_VERSION = 150
INCDIR =
+7 -1
View File
@@ -7,6 +7,9 @@
PSP_MODULE_INFO("kernel_functions", PSP_MODULE_KERNEL, 0, 0);
PSP_MAIN_THREAD_ATTR(0);
extern int sceKernelLoadExecVSHEf2(const char *file,
struct SceKernelLoadExecVSHParam *param);
void exitspawn_kernel(const char *fileName, SceSize args, void *argp)
{
int k1;
@@ -25,7 +28,10 @@ void exitspawn_kernel(const char *fileName, SceSize args, void *argp)
game_param.unk5 = 0x10000;
k1 = pspSdkSetK1(0);
sceKernelLoadExecVSHMs2(fileName, &game_param);
if (!strncmp(fileName, "ef0:", 4))
sceKernelLoadExecVSHEf2(fileName, &game_param);
else
sceKernelLoadExecVSHMs2(fileName, &game_param);
pspSdkSetK1(k1);
}
+12 -1
View File
@@ -142,7 +142,18 @@ static void frontend_psp_get_env_settings(int *argc, char *argv[],
strlcpy(eboot_path, argv[0], sizeof(eboot_path));
/* for PSP, use uppercase directories, and no trailing slashes
otherwise mkdir fails */
strlcpy(user_path, "ms0:/PSP/RETROARCH", sizeof(user_path));
/* Derive the user data root from the storage device RetroArch was
launched from (such as "ms0:/" or "ef0:/" on PSP Go). That way user
data follows the binary instead of being hardcoded to ms0: */
if (strlen(eboot_path) >= 5 && eboot_path[4] == '/')
{
strlcpy(user_path, eboot_path, sizeof(user_path));
user_path[5] = '\0';
}
else
strlcpy(user_path, "ms0:/", sizeof(user_path));
strlcat(user_path, "PSP/RETROARCH", sizeof(user_path));
RARCH_LOG("[PSP]: Using %s for user data.\n", user_path);
fill_pathname_basedir(g_defaults.dirs[DEFAULT_DIR_PORT], argv[0],
sizeof(g_defaults.dirs[DEFAULT_DIR_PORT]));