Implement proc_ui.rpl + stub SYSSwitchToEManual() to avoid softlocks

- Full reimplementation of proc_ui.rpl with all 19 exports
- Foreground/Background messages now go to the coreinit system message queue as they should (instead of using a hack where proc_ui receives them directly)
- Add missing coreinit API needed by proc_ui: OSGetPFID(), OSGetUPID(), OSGetTitleID(), __OSCreateThreadType()
- Use big-endian types in OSMessage
- Flesh out the stubs for OSDriver_Register and OSDriver_Unregister a bit more since we need to call it from proc_ui. Similiar small tweaks to other coreinit API
- Stub sysapp SYSSwitchToEManual() and _SYSSwitchToEManual() in such a way that they will trigger the expected background/foreground transition, avoiding softlocks in games that call these functions
This commit is contained in:
Exzap
2024-04-30 23:29:15 +02:00
parent c038e758ae
commit 1c73dc9e1b
21 changed files with 1146 additions and 95 deletions
+1
View File
@@ -39,6 +39,7 @@ bin/sdcard/*
bin/screenshots/*
bin/dump/*
bin/cafeLibs/*
bin/portable/*
bin/keys.txt
!bin/shaderCache/info.txt
+1 -1
View File
@@ -221,5 +221,5 @@ void osLib_load()
nsyskbd::nsyskbd_load();
swkbd::load();
camera::load();
procui_load();
proc_ui::load();
}
-22
View File
@@ -179,27 +179,6 @@ void coreinitExport_OSGetSharedData(PPCInterpreter_t* hCPU)
osLib_returnFromFunction(hCPU, 1);
}
typedef struct
{
MPTR getDriverName;
MPTR ukn04;
MPTR onAcquiredForeground;
MPTR onReleaseForeground;
MPTR ukn10;
}OSDriverCallbacks_t;
void coreinitExport_OSDriver_Register(PPCInterpreter_t* hCPU)
{
#ifdef CEMU_DEBUG_ASSERT
cemuLog_log(LogType::Force, "OSDriver_Register(0x{:08x},0x{:08x},0x{:08x},0x{:08x},0x{:08x},0x{:08x})", hCPU->gpr[3], hCPU->gpr[4], hCPU->gpr[5], hCPU->gpr[6], hCPU->gpr[7], hCPU->gpr[8]);
#endif
OSDriverCallbacks_t* driverCallbacks = (OSDriverCallbacks_t*)memory_getPointerFromVirtualOffset(hCPU->gpr[5]);
// todo
osLib_returnFromFunction(hCPU, 0);
}
namespace coreinit
{
sint32 OSGetCoreId()
@@ -379,7 +358,6 @@ void coreinit_load()
coreinit::miscInit();
osLib_addFunction("coreinit", "OSGetSharedData", coreinitExport_OSGetSharedData);
osLib_addFunction("coreinit", "UCReadSysConfig", coreinitExport_UCReadSysConfig);
osLib_addFunction("coreinit", "OSDriver_Register", coreinitExport_OSDriver_Register);
// async callbacks
InitializeAsyncCallback();
@@ -2,6 +2,12 @@
namespace coreinit
{
enum class RplEntryReason
{
Loaded = 1,
Unloaded = 2,
};
uint32 OSDynLoad_SetAllocator(MPTR allocFunc, MPTR freeFunc);
void OSDynLoad_SetTLSAllocator(MPTR allocFunc, MPTR freeFunc);
uint32 OSDynLoad_GetAllocator(betype<MPTR>* funcAlloc, betype<MPTR>* funcFree);
+1 -1
View File
@@ -837,7 +837,7 @@ namespace coreinit
FSAsyncResult* FSGetAsyncResult(OSMessage* msg)
{
return (FSAsyncResult*)memory_getPointerFromVirtualOffset(_swapEndianU32(msg->message));
return (FSAsyncResult*)memory_getPointerFromVirtualOffset(msg->message);
}
sint32 __FSProcessAsyncResult(FSClient_t* fsClient, FSCmdBlock_t* fsCmdBlock, sint32 fsStatus, uint32 errHandling)
@@ -126,7 +126,7 @@ namespace coreinit
return physicalAddr;
}
void OSMemoryBarrier(PPCInterpreter_t* hCPU)
void OSMemoryBarrier()
{
// no-op
}
@@ -5,4 +5,9 @@ namespace coreinit
void InitializeMemory();
void OSGetMemBound(sint32 memType, MPTR* offsetOutput, uint32* sizeOutput);
void* OSBlockMove(MEMPTR<void> dst, MEMPTR<void> src, uint32 size, bool flushDC);
void* OSBlockSet(MEMPTR<void> dst, uint32 value, uint32 size);
void OSMemoryBarrier();
}
@@ -3,6 +3,8 @@
namespace coreinit
{
void UpdateSystemMessageQueue();
void HandleReceivedSystemMessage(OSMessage* msg);
SysAllocator<OSMessageQueue> g_systemMessageQueue;
SysAllocator<OSMessage, 16> _systemMessageQueueArray;
@@ -27,6 +29,9 @@ namespace coreinit
bool OSReceiveMessage(OSMessageQueue* msgQueue, OSMessage* msg, uint32 flags)
{
bool isSystemMessageQueue = (msgQueue == g_systemMessageQueue);
if(isSystemMessageQueue)
UpdateSystemMessageQueue();
__OSLockScheduler(msgQueue);
while (msgQueue->usedCount == (uint32be)0)
{
@@ -50,6 +55,8 @@ namespace coreinit
if (!msgQueue->threadQueueSend.isEmpty())
msgQueue->threadQueueSend.wakeupSingleThreadWaitQueue(true);
__OSUnlockScheduler(msgQueue);
if(isSystemMessageQueue)
HandleReceivedSystemMessage(msg);
return true;
}
@@ -3,12 +3,21 @@
namespace coreinit
{
enum class SysMessageId : uint32
{
MsgAcquireForeground = 0xFACEF000,
MsgReleaseForeground = 0xFACEBACC,
MsgExit = 0xD1E0D1E0,
HomeButtonDenied = 0xCCC0FFEE,
NetIoStartOrStop = 0xAAC0FFEE,
};
struct OSMessage
{
MPTR message;
uint32 data0;
uint32 data1;
uint32 data2;
uint32be message;
uint32be data0;
uint32be data1;
uint32be data2;
};
struct OSMessageQueue
@@ -36,5 +45,7 @@ namespace coreinit
bool OSPeekMessage(OSMessageQueue* msgQueue, OSMessage* msg);
sint32 OSSendMessage(OSMessageQueue* msgQueue, OSMessage* msg, uint32 flags);
OSMessageQueue* OSGetSystemMessageQueue();
void InitializeMessageQueue();
};
@@ -1,5 +1,6 @@
#include "Cafe/OS/common/OSCommon.h"
#include "Cafe/OS/libs/coreinit/coreinit_Misc.h"
#include "Cafe/OS/libs/coreinit/coreinit_MessageQueue.h"
#include "Cafe/CafeSystem.h"
#include "Cafe/Filesystem/fsc.h"
#include <pugixml.hpp>
@@ -371,6 +372,23 @@ namespace coreinit
return true;
}
uint32 OSGetPFID()
{
return 15; // hardcoded as game
}
uint32 OSGetUPID()
{
return OSGetPFID();
}
uint64 s_currentTitleId;
uint64 OSGetTitleID()
{
return s_currentTitleId;
}
uint32 s_sdkVersion;
uint32 __OSGetProcessSDKVersion()
@@ -470,9 +488,78 @@ namespace coreinit
return 0;
}
void OSReleaseForeground()
{
cemuLog_logDebug(LogType::Force, "OSReleaseForeground not implemented");
}
bool s_transitionToBackground = false;
bool s_transitionToForeground = false;
void StartBackgroundForegroundTransition()
{
s_transitionToBackground = true;
s_transitionToForeground = true;
}
// called at the beginning of OSReceiveMessage if the queue is the system message queue
void UpdateSystemMessageQueue()
{
if(!OSIsInterruptEnabled())
return;
cemu_assert_debug(!__OSHasSchedulerLock());
// normally syscall 0x2E is used to get the next message
// for now we just have some preliminary logic here to allow a fake transition to background & foreground
if(s_transitionToBackground)
{
// add transition to background message
OSMessage msg{};
msg.data0 = stdx::to_underlying(SysMessageId::MsgReleaseForeground);
msg.data1 = 0; // 1 -> System is shutting down 0 -> Begin transitioning to background
OSMessageQueue* systemMessageQueue = coreinit::OSGetSystemMessageQueue();
if(OSSendMessage(systemMessageQueue, &msg, 0))
s_transitionToBackground = false;
return;
}
if(s_transitionToForeground)
{
// add transition to foreground message
OSMessage msg{};
msg.data0 = stdx::to_underlying(SysMessageId::MsgAcquireForeground);
msg.data1 = 1; // ?
msg.data2 = 1; // ?
OSMessageQueue* systemMessageQueue = coreinit::OSGetSystemMessageQueue();
if(OSSendMessage(systemMessageQueue, &msg, 0))
s_transitionToForeground = false;
return;
}
}
// called when OSReceiveMessage returns a message from the system message queue
void HandleReceivedSystemMessage(OSMessage* msg)
{
cemu_assert_debug(!__OSHasSchedulerLock());
cemuLog_log(LogType::Force, "Receiving message: {:08x}", (uint32)msg->data0);
}
uint32 OSDriver_Register(uint32 moduleHandle, sint32 priority, OSDriverInterface* driverCallbacks, sint32 driverId, uint32be* outUkn1, uint32be* outUkn2, uint32be* outUkn3)
{
cemuLog_logDebug(LogType::Force, "OSDriver_Register stubbed");
return 0;
}
uint32 OSDriver_Deregister(uint32 moduleHandle, sint32 driverId)
{
cemuLog_logDebug(LogType::Force, "OSDriver_Deregister stubbed");
return 0;
}
void miscInit()
{
s_currentTitleId = CafeSystem::GetForegroundTitleId();
s_sdkVersion = CafeSystem::GetForegroundTitleSDKVersion();
s_transitionToBackground = false;
s_transitionToForeground = false;
cafeExportRegister("coreinit", __os_snprintf, LogType::Placeholder);
cafeExportRegister("coreinit", OSReport, LogType::Placeholder);
@@ -480,6 +567,10 @@ namespace coreinit
cafeExportRegister("coreinit", COSWarn, LogType::Placeholder);
cafeExportRegister("coreinit", OSLogPrintf, LogType::Placeholder);
cafeExportRegister("coreinit", OSConsoleWrite, LogType::Placeholder);
cafeExportRegister("coreinit", OSGetPFID, LogType::Placeholder);
cafeExportRegister("coreinit", OSGetUPID, LogType::Placeholder);
cafeExportRegister("coreinit", OSGetTitleID, LogType::Placeholder);
cafeExportRegister("coreinit", __OSGetProcessSDKVersion, LogType::Placeholder);
g_homeButtonMenuEnabled = true; // enabled by default
@@ -489,6 +580,11 @@ namespace coreinit
cafeExportRegister("coreinit", OSLaunchTitleByPathl, LogType::Placeholder);
cafeExportRegister("coreinit", OSRestartGame, LogType::Placeholder);
cafeExportRegister("coreinit", OSReleaseForeground, LogType::Placeholder);
cafeExportRegister("coreinit", OSDriver_Register, LogType::Placeholder);
cafeExportRegister("coreinit", OSDriver_Deregister, LogType::Placeholder);
}
};
+20
View File
@@ -2,9 +2,29 @@
namespace coreinit
{
uint32 OSGetUPID();
uint32 OSGetPFID();
uint64 OSGetTitleID();
uint32 __OSGetProcessSDKVersion();
uint32 OSLaunchTitleByPathl(const char* path, uint32 pathLength, uint32 argc);
uint32 OSRestartGame(uint32 argc, MEMPTR<char>* argv);
void OSReleaseForeground();
void StartBackgroundForegroundTransition();
struct OSDriverInterface
{
MEMPTR<void> getDriverName;
MEMPTR<void> init;
MEMPTR<void> onAcquireForeground;
MEMPTR<void> onReleaseForeground;
MEMPTR<void> done;
};
static_assert(sizeof(OSDriverInterface) == 0x14);
uint32 OSDriver_Register(uint32 moduleHandle, sint32 priority, OSDriverInterface* driverCallbacks, sint32 driverId, uint32be* outUkn1, uint32be* outUkn2, uint32be* outUkn3);
uint32 OSDriver_Deregister(uint32 moduleHandle, sint32 driverId);
void miscInit();
};
+13 -6
View File
@@ -294,9 +294,9 @@ namespace coreinit
__OSUnlockScheduler();
}
bool OSCreateThreadType(OSThread_t* thread, MPTR entryPoint, sint32 numParam, void* ptrParam, void* stackTop2, sint32 stackSize, sint32 priority, uint32 attr, OSThread_t::THREAD_TYPE threadType)
bool OSCreateThreadType(OSThread_t* thread, MPTR entryPoint, sint32 numParam, void* ptrParam, void* stackTop, sint32 stackSize, sint32 priority, uint32 attr, OSThread_t::THREAD_TYPE threadType)
{
OSCreateThreadInternal(thread, entryPoint, memory_getVirtualOffsetFromPointer(stackTop2) - stackSize, stackSize, attr, threadType);
OSCreateThreadInternal(thread, entryPoint, memory_getVirtualOffsetFromPointer(stackTop) - stackSize, stackSize, attr, threadType);
thread->context.gpr[3] = _swapEndianU32(numParam); // num arguments
thread->context.gpr[4] = _swapEndianU32(memory_getVirtualOffsetFromPointer(ptrParam)); // arguments pointer
__OSSetThreadBasePriority(thread, priority);
@@ -317,9 +317,15 @@ namespace coreinit
return true;
}
bool OSCreateThread(OSThread_t* thread, MPTR entryPoint, sint32 numParam, void* ptrParam, void* stackTop2, sint32 stackSize, sint32 priority, uint32 attr)
bool OSCreateThread(OSThread_t* thread, MPTR entryPoint, sint32 numParam, void* ptrParam, void* stackTop, sint32 stackSize, sint32 priority, uint32 attr)
{
return OSCreateThreadType(thread, entryPoint, numParam, ptrParam, stackTop2, stackSize, priority, attr, OSThread_t::THREAD_TYPE::TYPE_APP);
return OSCreateThreadType(thread, entryPoint, numParam, ptrParam, stackTop, stackSize, priority, attr, OSThread_t::THREAD_TYPE::TYPE_APP);
}
// alias to OSCreateThreadType, similar to OSCreateThread, but with an additional parameter for the thread type
bool __OSCreateThreadType(OSThread_t* thread, MPTR entryPoint, sint32 numParam, void* ptrParam, void* stackTop, sint32 stackSize, sint32 priority, uint32 attr, OSThread_t::THREAD_TYPE threadType)
{
return OSCreateThreadType(thread, entryPoint, numParam, ptrParam, stackTop, stackSize, priority, attr, threadType);
}
bool OSRunThread(OSThread_t* thread, MPTR funcAddress, sint32 numParam, void* ptrParam)
@@ -445,12 +451,12 @@ namespace coreinit
return currentThread->specificArray[index].GetPtr();
}
void OSSetThreadName(OSThread_t* thread, char* name)
void OSSetThreadName(OSThread_t* thread, const char* name)
{
thread->threadName = name;
}
char* OSGetThreadName(OSThread_t* thread)
const char* OSGetThreadName(OSThread_t* thread)
{
return thread->threadName.GetPtr();
}
@@ -1371,6 +1377,7 @@ namespace coreinit
{
cafeExportRegister("coreinit", OSCreateThreadType, LogType::CoreinitThread);
cafeExportRegister("coreinit", OSCreateThread, LogType::CoreinitThread);
cafeExportRegister("coreinit", __OSCreateThreadType, LogType::CoreinitThread);
cafeExportRegister("coreinit", OSExitThread, LogType::CoreinitThread);
cafeExportRegister("coreinit", OSGetCurrentThread, LogType::CoreinitThread);
+5 -3
View File
@@ -449,7 +449,7 @@ struct OSThread_t
/* +0x578 */ sint32 alarmRelatedUkn;
/* +0x57C */ std::array<MEMPTR<void>, 16> specificArray;
/* +0x5BC */ betype<THREAD_TYPE> type;
/* +0x5C0 */ MEMPTR<char> threadName;
/* +0x5C0 */ MEMPTR<const char> threadName;
/* +0x5C4 */ MPTR waitAlarm; // used only by OSWaitEventWithTimeout/OSSignalEvent ?
/* +0x5C8 */ uint32 userStackPointer;
@@ -505,6 +505,7 @@ namespace coreinit
void* OSGetDefaultThreadStack(sint32 coreIndex, uint32& size);
bool OSCreateThreadType(OSThread_t* thread, MPTR entryPoint, sint32 numParam, void* ptrParam, void* stackTop2, sint32 stackSize, sint32 priority, uint32 attr, OSThread_t::THREAD_TYPE threadType);
bool __OSCreateThreadType(OSThread_t* thread, MPTR entryPoint, sint32 numParam, void* ptrParam, void* stackTop, sint32 stackSize, sint32 priority, uint32 attr, OSThread_t::THREAD_TYPE threadType);
void OSCreateThreadInternal(OSThread_t* thread, uint32 entryPoint, MPTR stackLowerBaseAddr, uint32 stackSize, uint8 affinityMask, OSThread_t::THREAD_TYPE threadType);
bool OSRunThread(OSThread_t* thread, MPTR funcAddress, sint32 numParam, void* ptrParam);
void OSExitThread(sint32 exitValue);
@@ -519,8 +520,8 @@ namespace coreinit
bool OSSetThreadPriority(OSThread_t* thread, sint32 newPriority);
uint32 OSGetThreadAffinity(OSThread_t* thread);
void OSSetThreadName(OSThread_t* thread, char* name);
char* OSGetThreadName(OSThread_t* thread);
void OSSetThreadName(OSThread_t* thread, const char* name);
const char* OSGetThreadName(OSThread_t* thread);
sint32 __OSResumeThreadInternal(OSThread_t* thread, sint32 resumeCount);
sint32 OSResumeThread(OSThread_t* thread);
@@ -530,6 +531,7 @@ namespace coreinit
void OSSuspendThread(OSThread_t* thread);
void OSSleepThread(OSThreadQueue* threadQueue);
void OSWakeupThread(OSThreadQueue* threadQueue);
bool OSJoinThread(OSThread_t* thread, uint32be* exitValue);
void OSTestThreadCancelInternal();
+3 -4
View File
@@ -22,10 +22,9 @@ namespace coreinit
osLib_returnFromFunction(hCPU, (uint32)osTime);
}
void export_OSGetTime(PPCInterpreter_t* hCPU)
uint64 OSGetTime()
{
uint64 osTime = coreinit_getOSTime();
osLib_returnFromFunction64(hCPU, osTime);
return coreinit_getOSTime();
}
void export_OSGetSystemTime(PPCInterpreter_t* hCPU)
@@ -360,7 +359,7 @@ namespace coreinit
void InitializeTimeAndCalendar()
{
osLib_addFunction("coreinit", "OSGetTime", export_OSGetTime);
cafeExportRegister("coreinit", OSGetTime, LogType::Placeholder);
osLib_addFunction("coreinit", "OSGetSystemTime", export_OSGetSystemTime);
osLib_addFunction("coreinit", "OSGetTick", export_OSGetTick);
osLib_addFunction("coreinit", "OSGetSystemTick", export_OSGetSystemTick);
+2 -1
View File
@@ -45,7 +45,8 @@ namespace coreinit
};
void OSTicksToCalendarTime(uint64 ticks, OSCalendarTime_t* calenderStruct);
uint64 OSGetTime();
uint64 coreinit_getOSTime();
uint64 coreinit_getTimerTick();
+2
View File
@@ -19,5 +19,7 @@ namespace GX2
void GX2SetTVBuffer(void* imageBuffePtr, uint32 imageBufferSize, E_TVRES tvResolutionMode, uint32 surfaceFormat, E_TVBUFFERMODE bufferMode);
void GX2SetTVGamma(float gamma);
void GX2Invalidate(uint32 invalidationFlags, MPTR invalidationAddr, uint32 invalidationSize);
void GX2MiscInit();
};
+2 -1
View File
@@ -9,6 +9,7 @@
#include "Cafe/OS/libs/proc_ui/proc_ui.h"
#include "Cafe/OS/libs/coreinit/coreinit_Time.h"
#include "Cafe/OS/libs/coreinit/coreinit_Misc.h"
namespace nn
{
@@ -37,7 +38,7 @@ namespace nn
void StubPostAppReleaseBackground(PPCInterpreter_t* hCPU)
{
coreinit::OSSleepTicks(ESPRESSO_TIMER_CLOCK * 2); // Sleep 2s
ProcUI_SendForegroundMessage();
coreinit::StartBackgroundForegroundTransition();
}
sint32 StubPostApp(void* pAnyPostParam)
File diff suppressed because it is too large Load Diff
+42 -3
View File
@@ -1,5 +1,44 @@
void procui_load();
namespace proc_ui
{
enum class ProcUIStatus
{
Foreground = 0,
Background = 1,
Releasing = 2,
Exit = 3
};
void ProcUI_SendForegroundMessage();
void ProcUI_SendBackgroundMessage();
enum class ProcUICallbackId
{
AcquireForeground = 0,
ReleaseForeground = 1,
Exit = 2,
NetIoStart = 3,
NetIoStop = 4,
HomeButtonDenied = 5,
COUNT = 6
};
void ProcUIInit(MEMPTR<void> callbackReadyToRelease);
void ProcUIInitEx(MEMPTR<void> callbackReadyToReleaseEx, MEMPTR<void> userParam);
void ProcUIShutdown();
bool ProcUIIsRunning();
bool ProcUIInForeground();
bool ProcUIInShutdown();
void ProcUIRegisterCallback(ProcUICallbackId callbackType, void* funcPtr, void* userParam, sint32 priority);
void ProcUIRegisterCallbackCore(ProcUICallbackId callbackType, void* funcPtr, void* userParam, sint32 priority, uint32 coreIndex);
void ProcUIRegisterBackgroundCallback(void* funcPtr, void* userParam, uint64 tickDelay);
void ProcUIClearCallbacks();
void ProcUISetSaveCallback(void* funcPtr, void* userParam);
void ProcUISetCallbackStackSize(uint32 newStackSize);
uint32 ProcUICalcMemorySize(uint32 numCallbacks);
sint32 ProcUISetMemoryPool(void* memBase, uint32 size);
void ProcUISetBucketStorage(void* memBase, uint32 size);
void ProcUISetMEM1Storage(void* memBase, uint32 size);
void ProcUIDrawDoneRelease();
ProcUIStatus ProcUIProcessMessages(bool isBlockingInBackground);
ProcUIStatus ProcUISubProcessMessages(bool isBlockingInBackground);
void load();
}
+23
View File
@@ -639,11 +639,34 @@ namespace sysapp
return coreinit::OSRestartGame(argc, argv);
}
struct EManualArgs
{
sysStandardArguments_t stdArgs;
uint64be titleId;
};
static_assert(sizeof(EManualArgs) == 0x10);
void _SYSSwitchToEManual(EManualArgs* args)
{
// the struct has the titleId at offset 8 and standard args at 0 (total size is most likely 0x10)
cemuLog_log(LogType::Force, "SYSSwitchToEManual called. Opening the manual is not supported");
coreinit::StartBackgroundForegroundTransition();
}
void SYSSwitchToEManual()
{
EManualArgs args{};
args.titleId = coreinit::OSGetTitleID();
_SYSSwitchToEManual(&args);
}
void load()
{
cafeExportRegisterFunc(SYSClearSysArgs, "sysapp", "SYSClearSysArgs", LogType::Placeholder);
cafeExportRegisterFunc(_SYSLaunchTitleByPathFromLauncher, "sysapp", "_SYSLaunchTitleByPathFromLauncher", LogType::Placeholder);
cafeExportRegisterFunc(SYSRelaunchTitle, "sysapp", "SYSRelaunchTitle", LogType::Placeholder);
cafeExportRegister("sysapp", _SYSSwitchToEManual, LogType::Placeholder);
cafeExportRegister("sysapp", SYSSwitchToEManual, LogType::Placeholder);
}
}

Some files were not shown because too many files have changed in this diff Show More