coreinit: Fix initialization order

Threads were initialized before SDA values were available from RPL loader. Fixes crash in Skylanders Swap Force and some other games
This commit is contained in:
Exzap 2026-02-09 07:08:01 +01:00
parent 8cd5ce102f
commit 9f58f3a118
10 changed files with 65 additions and 32 deletions

View File

@ -427,10 +427,8 @@ void cemu_initForGame()
cemuLog_log(LogType::Force, "------- Run title -------"); cemuLog_log(LogType::Force, "------- Run title -------");
// wait till GPU thread is initialized // wait till GPU thread is initialized
while (g_isGPUInitFinished == false) std::this_thread::sleep_for(std::chrono::milliseconds(50)); while (g_isGPUInitFinished == false) std::this_thread::sleep_for(std::chrono::milliseconds(50));
// init initial thread // run coreinit rpl_entry
OSThread_t* initialThread = coreinit::OSGetDefaultThread(1); RPLLoader_CallCoreinitEntrypoint();
coreinit::OSSetThreadPriority(initialThread, 16);
coreinit::OSRunThread(initialThread, PPCInterpreter_makeCallableExportDepr(coreinit_start), 0, nullptr);
// init AX and start AX I/O thread // init AX and start AX I/O thread
snd_core::AXOut_init(); snd_core::AXOut_init();
} }

View File

@ -2305,6 +2305,25 @@ void RPLLoader_CallEntrypoints()
} }
} }
// calls the entrypoint of coreinit and marks it as called so that RPLLoader_CallEntrypoints() wont call it again later
void RPLLoader_CallCoreinitEntrypoint()
{
// for HLE modules we need to check the dependency list
for (auto& dependency : rplDependencyList)
{
if (strcmp(dependency->modulename, "coreinit") != 0)
continue;
if (!dependency->rplHLEModule)
continue;
if (dependency->hleEntrypointCalled)
continue;
dependency->rplHLEModule->rpl_entry(dependency->coreinitHandle, coreinit::RplEntryReason::Loaded);
dependency->hleEntrypointCalled = true;
return;
}
cemu_assert_unimplemented(); // coreinit.rpl present in cafelibs? We currently do not support native coreinit and no thread context exists yet to do a PPC call
}
void RPLLoader_NotifyControlPassedToApplication() void RPLLoader_NotifyControlPassedToApplication()
{ {
rplLoader_applicationHasMemoryControl = true; rplLoader_applicationHasMemoryControl = true;
@ -2350,11 +2369,13 @@ uint32 RPLLoader_FindModuleOrHLEExport(uint32 moduleHandle, bool isData, const c
uint32 RPLLoader_GetSDA1Base() uint32 RPLLoader_GetSDA1Base()
{ {
cemu_assert_debug(rplModuleCount > 0); // this should not be called before the main executable was loaded
return rplLoader_sdataAddr; return rplLoader_sdataAddr;
} }
uint32 RPLLoader_GetSDA2Base() uint32 RPLLoader_GetSDA2Base()
{ {
cemu_assert_debug(rplModuleCount > 0);
return rplLoader_sdata2Addr; return rplLoader_sdata2Addr;
} }

View File

@ -25,6 +25,7 @@ void RPLLoader_SetMainModule(RPLModule* rplLoaderContext);
uint32 RPLLoader_GetMainModuleHandle(); uint32 RPLLoader_GetMainModuleHandle();
void RPLLoader_CallEntrypoints(); void RPLLoader_CallEntrypoints();
void RPLLoader_CallCoreinitEntrypoint();
void RPLLoader_NotifyControlPassedToApplication(); void RPLLoader_NotifyControlPassedToApplication();
void RPLLoader_AddDependency(std::string_view name); void RPLLoader_AddDependency(std::string_view name);

View File

@ -331,7 +331,7 @@ namespace coreinit
// init GHS and threads // init GHS and threads
coreinit::PrepareGHSRuntime(); coreinit::PrepareGHSRuntime();
coreinit::InitializeThread(); coreinit::MapThreadExports();
// reset threads // reset threads
activeThreadCount = 0; activeThreadCount = 0;
@ -353,13 +353,13 @@ namespace coreinit
coreinit::InitializeLC(); coreinit::InitializeLC();
coreinit::InitializeMP(); coreinit::InitializeMP();
coreinit::InitializeTimeAndCalendar(); coreinit::InitializeTimeAndCalendar();
coreinit::InitializeAlarm(); coreinit::MapAlarmExports();
coreinit::InitializeFS(); coreinit::InitializeFS();
coreinit::InitializeSystemInfo(); coreinit::InitializeSystemInfo();
coreinit::InitializeConcurrency(); coreinit::InitializeConcurrency();
coreinit::InitializeSpinlock(); coreinit::InitializeSpinlock();
coreinit::InitializeMessageQueue(); coreinit::InitializeMessageQueue();
coreinit::InitializeIPC(); coreinit::MapIPCExports();
coreinit::InitializeIPCBuf(); coreinit::InitializeIPCBuf();
coreinit::InitializeMemoryMapping(); coreinit::InitializeMemoryMapping();
coreinit::InitializeCodeGen(); coreinit::InitializeCodeGen();
@ -373,16 +373,20 @@ namespace coreinit
coreinit::miscInit(); coreinit::miscInit();
osLib_addFunction("coreinit", "OSGetSharedData", coreinitExport_OSGetSharedData); osLib_addFunction("coreinit", "OSGetSharedData", coreinitExport_OSGetSharedData);
osLib_addFunction("coreinit", "UCReadSysConfig", coreinitExport_UCReadSysConfig); osLib_addFunction("coreinit", "UCReadSysConfig", coreinitExport_UCReadSysConfig);
// async callbacks
InitializeAsyncCallback();
}; };
void rpl_entry(uint32 moduleHandle, coreinit::RplEntryReason reason) override void rpl_entry(uint32 moduleHandle, coreinit::RplEntryReason reason) override
{ {
if (reason == coreinit::RplEntryReason::Loaded) if (reason == coreinit::RplEntryReason::Loaded)
{ {
// todo coreinit::InitializeThread();
coreinit::InitializeAlarm();
coreinit::InitializeIPC();
InitializeAsyncCallback();
// remaining coreinit initialization happens in coreinit_start and requires a valid PPC context
OSThread_t* initialThread = coreinit::OSGetDefaultThread(1);
coreinit::OSSetThreadPriority(initialThread, 16);
coreinit::OSRunThread(initialThread, PPCInterpreter_makeCallableExportDepr(coreinit_start), 0, nullptr);
} }
else if (reason == coreinit::RplEntryReason::Unloaded) else if (reason == coreinit::RplEntryReason::Unloaded)
{ {

View File

@ -349,7 +349,7 @@ namespace coreinit
} }
} }
void InitializeAlarm() void MapAlarmExports()
{ {
cafeExportRegister("coreinit", OSCreateAlarm, LogType::CoreinitAlarm); cafeExportRegister("coreinit", OSCreateAlarm, LogType::CoreinitAlarm);
cafeExportRegister("coreinit", OSCreateAlarmEx, LogType::CoreinitAlarm); cafeExportRegister("coreinit", OSCreateAlarmEx, LogType::CoreinitAlarm);
@ -358,7 +358,10 @@ namespace coreinit
cafeExportRegister("coreinit", OSSetPeriodicAlarm, LogType::CoreinitAlarm); cafeExportRegister("coreinit", OSSetPeriodicAlarm, LogType::CoreinitAlarm);
cafeExportRegister("coreinit", OSSetAlarmUserData, LogType::CoreinitAlarm); cafeExportRegister("coreinit", OSSetAlarmUserData, LogType::CoreinitAlarm);
cafeExportRegister("coreinit", OSGetAlarmUserData, LogType::CoreinitAlarm); cafeExportRegister("coreinit", OSGetAlarmUserData, LogType::CoreinitAlarm);
}
void InitializeAlarm()
{
// init event // init event
OSInitEvent(g_alarmEvent.GetPtr(), OSEvent::EVENT_STATE::STATE_NOT_SIGNALED, OSEvent::EVENT_MODE::MODE_AUTO); OSInitEvent(g_alarmEvent.GetPtr(), OSEvent::EVENT_STATE::STATE_NOT_SIGNALED, OSEvent::EVENT_MODE::MODE_AUTO);

View File

@ -49,5 +49,6 @@ namespace coreinit
void alarm_update(); void alarm_update();
void MapAlarmExports();
void InitializeAlarm(); void InitializeAlarm();
} }

View File

@ -445,15 +445,8 @@ namespace coreinit
return r; return r;
} }
void InitializeIPC() void MapIPCExports()
{ {
for (uint32 i = 0; i < Espresso::CORE_COUNT; i++)
{
IPCDriver_InitForCore(i);
IPCDriver_InitIPCThread(i);
}
// register API
cafeExportRegister("coreinit", IOS_Open, LogType::PPC_IPC); cafeExportRegister("coreinit", IOS_Open, LogType::PPC_IPC);
cafeExportRegister("coreinit", IOS_Close, LogType::PPC_IPC); cafeExportRegister("coreinit", IOS_Close, LogType::PPC_IPC);
cafeExportRegister("coreinit", IOS_Ioctl, LogType::PPC_IPC); cafeExportRegister("coreinit", IOS_Ioctl, LogType::PPC_IPC);
@ -462,4 +455,13 @@ namespace coreinit
cafeExportRegister("coreinit", IOS_IoctlvAsync, LogType::PPC_IPC); cafeExportRegister("coreinit", IOS_IoctlvAsync, LogType::PPC_IPC);
} }
void InitializeIPC()
{
for (uint32 i = 0; i < Espresso::CORE_COUNT; i++)
{
IPCDriver_InitForCore(i);
IPCDriver_InitIPCThread(i);
}
}
}; };

View File

@ -12,5 +12,6 @@ namespace coreinit
IOS_ERROR IOS_Ioctlv(IOSDevHandle devHandle, uint32 requestId, uint32 numIn, uint32 numOut, IPCIoctlVector* vec); IOS_ERROR IOS_Ioctlv(IOSDevHandle devHandle, uint32 requestId, uint32 numIn, uint32 numOut, IPCIoctlVector* vec);
IOS_ERROR IOS_IoctlvAsync(IOSDevHandle devHandle, uint32 requestId, uint32 numIn, uint32 numOut, IPCIoctlVector* vec, MEMPTR<void> asyncResultFunc, MEMPTR<void> asyncResultUserParam); IOS_ERROR IOS_IoctlvAsync(IOSDevHandle devHandle, uint32 requestId, uint32 numIn, uint32 numOut, IPCIoctlVector* vec, MEMPTR<void> asyncResultFunc, MEMPTR<void> asyncResultUserParam);
void MapIPCExports();
void InitializeIPC(); void InitializeIPC();
}; };

View File

@ -1588,7 +1588,7 @@ namespace coreinit
} }
} }
void InitializeThread() void MapThreadExports()
{ {
cafeExportRegister("coreinit", OSCreateThreadType, LogType::CoreinitThread); cafeExportRegister("coreinit", OSCreateThreadType, LogType::CoreinitThread);
cafeExportRegister("coreinit", OSCreateThread, LogType::CoreinitThread); cafeExportRegister("coreinit", OSCreateThread, LogType::CoreinitThread);
@ -1632,16 +1632,16 @@ namespace coreinit
// OSThreadQueue // OSThreadQueue
cafeExportRegister("coreinit", OSInitThreadQueue, LogType::CoreinitThread); cafeExportRegister("coreinit", OSInitThreadQueue, LogType::CoreinitThread);
cafeExportRegister("coreinit", OSInitThreadQueueEx, LogType::CoreinitThread); cafeExportRegister("coreinit", OSInitThreadQueueEx, LogType::CoreinitThread);
OSInitThreadQueue(g_activeThreadQueue.GetPtr());
for (sint32 i = 0; i < PPC_CORE_COUNT; i++)
OSInitThreadQueue(g_coreRunQueue.GetPtr() + i);
for (sint32 i = 0; i < PPC_CORE_COUNT; i++)
__currentCoreThread[i] = nullptr;
__OSInitDefaultThreads();
__OSInitTerminatorThreads();
} }
void InitializeThread()
{
OSInitThreadQueue(g_activeThreadQueue.GetPtr());
for (sint32 i = 0; i < Espresso::CORE_COUNT; i++)
OSInitThreadQueue(g_coreRunQueue.GetPtr() + i);
for (sint32 i = 0; i < Espresso::CORE_COUNT; i++)
__currentCoreThread[i] = nullptr;
__OSInitDefaultThreads();
__OSInitTerminatorThreads();
}
} }

View File

@ -503,7 +503,9 @@ static_assert(sizeof(OSThread_t) == 0x6A0);
namespace coreinit namespace coreinit
{ {
void MapThreadExports();
void InitializeThread(); void InitializeThread();
void InitializeConcurrency(); void InitializeConcurrency();
bool __CemuIsMulticoreMode(); bool __CemuIsMulticoreMode();