Skip to content

Commit

Permalink
Implement proc_ui.rpl + stub SYSSwitchToEManual() to avoid softlocks
Browse files Browse the repository at this point in the history
- 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
  • Loading branch information
Exzap committed Apr 30, 2024
1 parent c038e75 commit 1c73dc9
Show file tree
Hide file tree
Showing 21 changed files with 1,139 additions and 88 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ bin/sdcard/*
bin/screenshots/*
bin/dump/*
bin/cafeLibs/*
bin/portable/*
bin/keys.txt

!bin/shaderCache/info.txt
Expand Down
2 changes: 1 addition & 1 deletion src/Cafe/OS/common/OSCommon.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -221,5 +221,5 @@ void osLib_load()
nsyskbd::nsyskbd_load();
swkbd::load();
camera::load();
procui_load();
proc_ui::load();
}
22 changes: 0 additions & 22 deletions src/Cafe/OS/libs/coreinit/coreinit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -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();
Expand Down
6 changes: 6 additions & 0 deletions src/Cafe/OS/libs/coreinit/coreinit_DynLoad.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion src/Cafe/OS/libs/coreinit/coreinit_FS.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion src/Cafe/OS/libs/coreinit/coreinit_Memory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ namespace coreinit
return physicalAddr;
}

void OSMemoryBarrier(PPCInterpreter_t* hCPU)
void OSMemoryBarrier()
{
// no-op
}
Expand Down
5 changes: 5 additions & 0 deletions src/Cafe/OS/libs/coreinit/coreinit_Memory.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
7 changes: 7 additions & 0 deletions src/Cafe/OS/libs/coreinit/coreinit_MessageQueue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@

namespace coreinit
{
void UpdateSystemMessageQueue();
void HandleReceivedSystemMessage(OSMessage* msg);

SysAllocator<OSMessageQueue> g_systemMessageQueue;
SysAllocator<OSMessage, 16> _systemMessageQueueArray;
Expand All @@ -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)
{
Expand All @@ -50,6 +55,8 @@ namespace coreinit
if (!msgQueue->threadQueueSend.isEmpty())
msgQueue->threadQueueSend.wakeupSingleThreadWaitQueue(true);
__OSUnlockScheduler(msgQueue);
if(isSystemMessageQueue)
HandleReceivedSystemMessage(msg);
return true;
}

Expand Down
19 changes: 15 additions & 4 deletions src/Cafe/OS/libs/coreinit/coreinit_MessageQueue.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -36,5 +45,7 @@ namespace coreinit
bool OSPeekMessage(OSMessageQueue* msgQueue, OSMessage* msg);
sint32 OSSendMessage(OSMessageQueue* msgQueue, OSMessage* msg, uint32 flags);

OSMessageQueue* OSGetSystemMessageQueue();

void InitializeMessageQueue();
};
96 changes: 96 additions & 0 deletions src/Cafe/OS/libs/coreinit/coreinit_Misc.cpp
Original file line number Diff line number Diff line change
@@ -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>
Expand Down Expand Up @@ -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()
Expand Down Expand Up @@ -470,16 +488,89 @@ 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);
cafeExportRegister("coreinit", OSVReport, LogType::Placeholder);
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
Expand All @@ -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 changes: 20 additions & 0 deletions src/Cafe/OS/libs/coreinit/coreinit_Misc.h
Original file line number Diff line number Diff line change
Expand Up @@ -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();
};
19 changes: 13 additions & 6 deletions src/Cafe/OS/libs/coreinit/coreinit_Thread.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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)
Expand Down Expand Up @@ -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();
}
Expand Down Expand Up @@ -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);
Expand Down

0 comments on commit 1c73dc9

Please sign in to comment.