From f04c7575d7aa206489668a8493cac993e41c51ae Mon Sep 17 00:00:00 2001 From: Exzap <13877693+Exzap@users.noreply.github.com> Date: Sat, 9 Sep 2023 14:33:31 +0200 Subject: [PATCH] coreinit: Handle non-existing modules in OSDynLoad_Acquire Fixes Togabito crashing on boot coreinit: Handle non-existing modules in OSDynLoad_Acquire --- src/Cafe/CafeSystem.cpp | 2 +- .../HW/Espresso/Recompiler/PPCRecompiler.cpp | 2 + src/Cafe/OS/RPL/rpl.cpp | 152 ++++++++++-------- src/Cafe/OS/RPL/rpl.h | 5 +- src/Cafe/OS/RPL/rpl_structs.h | 8 +- .../OS/libs/coreinit/coreinit_DynLoad.cpp | 6 +- src/Cafe/OS/libs/swkbd/swkbd.cpp | 2 - 7 files changed, 102 insertions(+), 75 deletions(-) diff --git a/src/Cafe/CafeSystem.cpp b/src/Cafe/CafeSystem.cpp index 93ced948..dd761f6e 100644 --- a/src/Cafe/CafeSystem.cpp +++ b/src/Cafe/CafeSystem.cpp @@ -165,7 +165,7 @@ void LoadMainExecutable() { // RPX RPLLoader_AddDependency(_pathToExecutable.c_str()); - applicationRPX = rpl_loadFromMem(rpxData, rpxSize, (char*)_pathToExecutable.c_str()); + applicationRPX = RPLLoader_LoadFromMemory(rpxData, rpxSize, (char*)_pathToExecutable.c_str()); if (!applicationRPX) { wxMessageBox(_("Failed to run this title because the executable is damaged")); diff --git a/src/Cafe/HW/Espresso/Recompiler/PPCRecompiler.cpp b/src/Cafe/HW/Espresso/Recompiler/PPCRecompiler.cpp index 6b830563..f4d063fa 100644 --- a/src/Cafe/HW/Espresso/Recompiler/PPCRecompiler.cpp +++ b/src/Cafe/HW/Espresso/Recompiler/PPCRecompiler.cpp @@ -325,6 +325,8 @@ void PPCRecompiler_thread() PPCRecompilerState.recompilerSpinlock.unlock(); PPCRecompiler_recompileAtAddress(enterAddress); + if(s_recompilerThreadStopSignal) + return; } } } diff --git a/src/Cafe/OS/RPL/rpl.cpp b/src/Cafe/OS/RPL/rpl.cpp index c9683683..48c7acc4 100644 --- a/src/Cafe/OS/RPL/rpl.cpp +++ b/src/Cafe/OS/RPL/rpl.cpp @@ -39,20 +39,22 @@ VHeap rplLoaderHeap_workarea(nullptr, MEMORY_RPLLOADER_AREA_SIZE); PPCCodeHeap rplLoaderHeap_lowerAreaCodeMem2(nullptr, MEMORY_CODE_TRAMPOLINE_AREA_SIZE); PPCCodeHeap rplLoaderHeap_codeArea2(nullptr, MEMORY_CODEAREA_SIZE); -bool rplLoader_applicationHasMemoryControl = false; -uint32 rplLoader_maxCodeAddress = 0; // highest used code address - ChunkedFlatAllocator<64 * 1024> g_heapTrampolineArea; -std::vector rplDependencyList = std::vector(); +std::vector rplDependencyList; RPLModule* rplModuleList[256]; sint32 rplModuleCount = 0; -uint32 _currentTLSModuleIndex = 1; // value 0 is reserved - +bool rplLoader_applicationHasMemoryControl = false; +uint32 rplLoader_maxCodeAddress = 0; // highest used code address +uint32 rplLoader_currentTLSModuleIndex = 1; // value 0 is reserved +uint32 rplLoader_currentHandleCounter = 0x00001000; +sint16 rplLoader_currentTlsModuleIndex = 0x0001; +RPLModule* rplLoader_mainModule = nullptr; uint32 rplLoader_sdataAddr = MPTR_NULL; // r13 uint32 rplLoader_sdata2Addr = MPTR_NULL; // r2 +uint32 rplLoader_currentDataAllocatorAddr = 0x10000000; std::map g_map_callableExports; @@ -110,8 +112,6 @@ MPTR RPLLoader_AllocateCodeSpace(uint32 size, uint32 alignment) return codeAddr; } -uint32 rpl3_currentDataAllocatorAddr = 0x10000000; - uint32 RPLLoader_AllocateDataSpace(RPLModule* rpl, uint32 size, uint32 alignment) { if (rplLoader_applicationHasMemoryControl) @@ -121,9 +121,9 @@ uint32 RPLLoader_AllocateDataSpace(RPLModule* rpl, uint32 size, uint32 alignment PPCCoreCallback(rpl->funcAlloc.value(), size, alignment, memPtr.GetPointer()); return (uint32)*(memPtr.GetPointer()); } - rpl3_currentDataAllocatorAddr = (rpl3_currentDataAllocatorAddr + alignment - 1)&~(alignment-1); - uint32 mem = rpl3_currentDataAllocatorAddr; - rpl3_currentDataAllocatorAddr += size; + rplLoader_currentDataAllocatorAddr = (rplLoader_currentDataAllocatorAddr + alignment - 1) & ~(alignment - 1); + uint32 mem = rplLoader_currentDataAllocatorAddr; + rplLoader_currentDataAllocatorAddr += size; return mem; } @@ -134,7 +134,7 @@ void RPLLoader_FreeData(RPLModule* rpl, void* ptr) uint32 RPLLoader_GetDataAllocatorAddr() { - return (rpl3_currentDataAllocatorAddr + 0xFFF)&(~0xFFF); + return (rplLoader_currentDataAllocatorAddr + 0xFFF) & (~0xFFF); } uint32 RPLLoader_GetMaxCodeOffset() @@ -1385,12 +1385,11 @@ bool RPLLoader_HandleRelocs(RPLModule* rplLoaderContext, std::span 0); - sint32 startIndex = inputLen - 1; + cemu_assert(!input.empty()); + size_t startIndex = input.size() - 1; while (startIndex > 0) { if (input[startIndex] == '/') @@ -1401,23 +1400,20 @@ void _RPLLoader_ExtractModuleNameFromPath(char* output, const char* input) startIndex--; } // cut off after '.' - sint32 endIndex = startIndex; - while (endIndex <= inputLen) + size_t endIndex = startIndex; + while (endIndex < input.size()) { if (input[endIndex] == '.') break; endIndex++; } - sint32 nameLen = endIndex - startIndex; + size_t nameLen = endIndex - startIndex; cemu_assert(nameLen != 0); - nameLen = std::min(nameLen, RPL_MODULE_NAME_LENGTH-1); - memcpy(output, input + startIndex, nameLen); + nameLen = std::min(nameLen, RPL_MODULE_NAME_LENGTH-1); + memcpy(output, input.data() + startIndex, nameLen); output[nameLen] = '\0'; // convert to lower case - for (sint32 i = 0; i < nameLen; i++) - { - output[i] = _ansiToLower(output[i]); - } + std::for_each(output, output + nameLen, [](char& c) {c = _ansiToLower(c);}); } void RPLLoader_InitState() @@ -1432,27 +1428,6 @@ void RPLLoader_InitState() RPLLoader_ResetState(); } -void RPLLoader_ResetState() -{ - // unload all RPL modules - while (rplModuleCount > 0) - RPLLoader_UnloadModule(rplModuleList[0]); - rplDependencyList.clear(); - // unload all remaining symbols - rplSymbolStorage_unloadAll(); - // free all code imports - g_heapTrampolineArea.releaseAll(); - list_mappedFunctionImports.clear(); - g_map_callableExports.clear(); - - rplLoader_applicationHasMemoryControl = false; - rplLoader_maxCodeAddress = 0; - rpl3_currentDataAllocatorAddr = 0x10000000; - _currentTLSModuleIndex = 1; - rplLoader_sdataAddr = MPTR_NULL; - rplLoader_sdata2Addr = MPTR_NULL; -} - void RPLLoader_BeginCemuhookCRC(RPLModule* rpl) { // calculate some values required for CRC @@ -1610,7 +1585,7 @@ void RPLLoader_InitModuleAllocator(RPLModule* rpl) } // map rpl into memory, but do not resolve relocs and imports yet -RPLModule* rpl_loadFromMem(uint8* rplData, sint32 size, char* name) +RPLModule* RPLLoader_LoadFromMemory(uint8* rplData, sint32 size, char* name) { char moduleName[RPL_MODULE_NAME_LENGTH]; _RPLLoader_ExtractModuleNameFromPath(moduleName, name); @@ -1699,7 +1674,7 @@ RPLModule* rpl_loadFromMem(uint8* rplData, sint32 size, char* name) return rpl; } -void RPLLoader_flushMemory(RPLModule* rpl) +void RPLLoader_FlushMemory(RPLModule* rpl) { // invalidate recompiler cache PPCRecompiler_invalidateRange(rpl->regionMappingBase_text.GetMPTR(), rpl->regionMappingBase_text.GetMPTR() + rpl->regionSize_text); @@ -1755,7 +1730,7 @@ void RPLLoader_LinkSingleModule(RPLModule* rplLoaderContext, bool resolveOnlyExp else RPLLoader_HandleRelocs(rplLoaderContext, sharedImportTracking, 0); - RPLLoader_flushMemory(rplLoaderContext); + RPLLoader_FlushMemory(rplLoaderContext); } void RPLLoader_LoadSectionDebugSymbols(RPLModule* rplLoaderContext, rplSectionEntryNew_t* section, int symtabSectionIndex) @@ -1919,8 +1894,24 @@ uint32 RPLLoader_GetModuleEntrypoint(RPLModule* rplLoaderContext) return rplLoaderContext->entrypoint; } -uint32 rplLoader_currentHandleCounter = 0x00001000; -sint16 rplLoader_currentTlsModuleIndex = 0x0001; +// takes a module name without extension, returns true if the RPL module is a known Cafe OS module +bool RPLLoader_IsKnownCafeOSModule(std::string_view name) +{ + static std::unordered_set s_systemModules556 = { + "avm","camera","coreinit","dc","dmae","drmapp","erreula", + "gx2","h264","lzma920","mic","nfc","nio_prof","nlibcurl", + "nlibnss","nlibnss2","nn_ac","nn_acp","nn_act","nn_aoc","nn_boss", + "nn_ccr","nn_cmpt","nn_dlp","nn_ec","nn_fp","nn_hai","nn_hpad", + "nn_idbe","nn_ndm","nn_nets2","nn_nfp","nn_nim","nn_olv","nn_pdm", + "nn_save","nn_sl","nn_spm","nn_temp","nn_uds","nn_vctl","nsysccr", + "nsyshid","nsyskbd","nsysnet","nsysuhs","nsysuvd","ntag","padscore", + "proc_ui","sndcore2","snduser2","snd_core","snd_user","swkbd","sysapp", + "tcl","tve","uac","uac_rpl","usb_mic","uvc","uvd","vpad","vpadbase", + "zlib125"}; + std::string nameLower{name}; + std::transform(nameLower.begin(), nameLower.end(), nameLower.begin(), _ansiToLower); + return s_systemModules556.contains(nameLower); +} // increment reference counter for module void RPLLoader_AddDependency(const char* name) @@ -1946,18 +1937,18 @@ void RPLLoader_AddDependency(const char* name) { if (strcmp(moduleName, dep->modulename) == 0) { - // entry already exists, increment reference counter dep->referenceCount++; return; } } // add new entry - rplDependency_t* newDependency = new rplDependency_t(); + RPLDependency* newDependency = new RPLDependency(); strcpy(newDependency->modulename, moduleName); newDependency->referenceCount = 1; newDependency->coreinitHandle = rplLoader_currentHandleCounter; newDependency->tlsModuleIndex = rplLoader_currentTlsModuleIndex; - rplLoader_currentTlsModuleIndex++; + newDependency->isCafeOSModule = RPLLoader_IsKnownCafeOSModule(moduleName); + rplLoader_currentTlsModuleIndex++; // todo - delay handle and tls allocation until the module is actually loaded. It may not exist rplLoader_currentHandleCounter++; if (rplLoader_currentTlsModuleIndex == 0x7FFF) cemuLog_log(LogType::Force, "RPLLoader: Exhausted TLS module indices pool"); @@ -2005,6 +1996,18 @@ void RPLLoader_RemoveDependency(const char* name) } } +bool RPLLoader_HasDependency(std::string_view name) +{ + char moduleName[RPL_MODULE_NAME_LENGTH]; + _RPLLoader_ExtractModuleNameFromPath(moduleName, name); + for (const auto& dep : rplDependencyList) + { + if (strcmp(moduleName, dep->modulename) == 0) + return true; + } + return false; +} + // decrement reference counter for dependency by module handle void RPLLoader_RemoveDependency(uint32 handle) { @@ -2030,6 +2033,9 @@ uint32 RPLLoader_GetHandleByModuleName(const char* name) { if (strcmp(moduleName, dep->modulename) == 0) { + cemu_assert_debug(dep->loadAttempted); + if (!dep->isCafeOSModule && !dep->rplLoaderContext) + return RPL_INVALID_HANDLE; // module not found return dep->coreinitHandle; } } @@ -2062,21 +2068,21 @@ bool RPLLoader_GetTLSDataByTLSIndex(sint16 tlsModuleIndex, uint8** tlsData, sint return true; } -bool RPLLoader_LoadFromVirtualPath(rplDependency_t* dependency, char* filePath) +bool RPLLoader_LoadFromVirtualPath(RPLDependency* dependency, char* filePath) { uint32 rplSize = 0; uint8* rplData = fsc_extractFile(filePath, &rplSize); if (rplData) { cemuLog_logDebug(LogType::Force, "Loading: {}", filePath); - dependency->rplLoaderContext = rpl_loadFromMem(rplData, rplSize, filePath); + dependency->rplLoaderContext = RPLLoader_LoadFromMemory(rplData, rplSize, filePath); free(rplData); return true; } return false; } -void RPLLoader_LoadDependency(rplDependency_t* dependency) +void RPLLoader_LoadDependency(RPLDependency* dependency) { dependency->loadAttempted = true; // check if module is already loaded @@ -2084,11 +2090,9 @@ void RPLLoader_LoadDependency(rplDependency_t* dependency) { if(!boost::iequals(rplModuleList[i]->moduleName2, dependency->modulename)) continue; - // already loaded dependency->rplLoaderContext = rplModuleList[i]; return; } - // attempt to load rpl from various locations char filePath[RPL_MODULE_PATH_LENGTH]; // check if path is absolute if (dependency->filepath[0] == '/') @@ -2097,7 +2101,7 @@ void RPLLoader_LoadDependency(rplDependency_t* dependency) RPLLoader_LoadFromVirtualPath(dependency, filePath); return; } - // attempt to load rpl from internal folder + // attempt to load rpl from code directory of current title strcpy_s(filePath, "/internal/current_title/code/"); strcat_s(filePath, dependency->filepath); // except if it is blacklisted @@ -2119,7 +2123,8 @@ void RPLLoader_LoadDependency(rplDependency_t* dependency) if (fileData) { cemuLog_log(LogType::Force, "Loading RPL: /cafeLibs/{}", dependency->filepath); - dependency->rplLoaderContext = rpl_loadFromMem(fileData->data(), fileData->size(), dependency->filepath); + dependency->rplLoaderContext = RPLLoader_LoadFromMemory(fileData->data(), fileData->size(), + dependency->filepath); return; } } @@ -2168,8 +2173,6 @@ void RPLLoader_UpdateDependencies() RPLLoader_Link(); } -RPLModule* rplLoader_mainModule = nullptr; - void RPLLoader_SetMainModule(RPLModule* rplLoaderContext) { rplLoaderContext->entrypointCalled = true; @@ -2250,7 +2253,7 @@ uint32 RPLLoader_FindModuleOrHLEExport(uint32 moduleHandle, bool isData, const c { // find dependency from handle RPLModule* rplLoaderContext = nullptr; - rplDependency_t* dependency = nullptr; + RPLDependency* dependency = nullptr; for (auto& dep : rplDependencyList) { if (dep->coreinitHandle == moduleHandle) @@ -2379,3 +2382,24 @@ void RPLLoader_ReleaseCodeCaveMem(MEMPTR addr) { heapCodeCaveArea.free(addr.GetMPTR()); } + +void RPLLoader_ResetState() +{ + // unload all RPL modules + while (rplModuleCount > 0) + RPLLoader_UnloadModule(rplModuleList[0]); + rplDependencyList.clear(); + // unload all remaining symbols + rplSymbolStorage_unloadAll(); + // free all code imports + g_heapTrampolineArea.releaseAll(); + list_mappedFunctionImports.clear(); + g_map_callableExports.clear(); + rplLoader_applicationHasMemoryControl = false; + rplLoader_maxCodeAddress = 0; + rplLoader_currentDataAllocatorAddr = 0x10000000; + rplLoader_currentTLSModuleIndex = 1; + rplLoader_sdataAddr = MPTR_NULL; + rplLoader_sdata2Addr = MPTR_NULL; + rplLoader_mainModule = nullptr; +} diff --git a/src/Cafe/OS/RPL/rpl.h b/src/Cafe/OS/RPL/rpl.h index ced7e83c..1075ee58 100644 --- a/src/Cafe/OS/RPL/rpl.h +++ b/src/Cafe/OS/RPL/rpl.h @@ -2,7 +2,7 @@ struct RPLModule; -#define RPL_INVALID_HANDLE (0xFFFFFFFF) +#define RPL_INVALID_HANDLE 0xFFFFFFFF void RPLLoader_InitState(); void RPLLoader_ResetState(); @@ -14,7 +14,7 @@ MPTR RPLLoader_AllocateCodeSpace(uint32 size, uint32 alignment); uint32 RPLLoader_GetMaxCodeOffset(); uint32 RPLLoader_GetDataAllocatorAddr(); -RPLModule* rpl_loadFromMem(uint8* rplData, sint32 size, char* name); +RPLModule* RPLLoader_LoadFromMemory(uint8* rplData, sint32 size, char* name); uint32 rpl_mapHLEImport(RPLModule* rplLoaderContext, const char* rplName, const char* funcName, bool functionMustExist); void RPLLoader_Link(); @@ -29,6 +29,7 @@ void RPLLoader_NotifyControlPassedToApplication(); void RPLLoader_AddDependency(const char* name); void RPLLoader_RemoveDependency(uint32 handle); +bool RPLLoader_HasDependency(std::string_view name); void RPLLoader_UpdateDependencies(); uint32 RPLLoader_GetHandleByModuleName(const char* name); diff --git a/src/Cafe/OS/RPL/rpl_structs.h b/src/Cafe/OS/RPL/rpl_structs.h index 71be960c..998ec8d7 100644 --- a/src/Cafe/OS/RPL/rpl_structs.h +++ b/src/Cafe/OS/RPL/rpl_structs.h @@ -225,17 +225,17 @@ struct RPLModule }; -typedef struct +struct RPLDependency { char modulename[RPL_MODULE_NAME_LENGTH]; char filepath[RPL_MODULE_PATH_LENGTH]; bool loadAttempted; - //bool isHLEModule; // determined to be a HLE module - RPLModule* rplLoaderContext; // context of loaded module + bool isCafeOSModule; // name is a known Cafe OS RPL + RPLModule* rplLoaderContext; // context of loaded module, can be nullptr for HLE COS modules sint32 referenceCount; uint32 coreinitHandle; // fake handle for coreinit sint16 tlsModuleIndex; // tls module index assigned to this dependency -}rplDependency_t; +}; RPLModule* RPLLoader_FindModuleByCodeAddr(uint32 addr); RPLModule* RPLLoader_FindModuleByDataAddr(uint32 addr); diff --git a/src/Cafe/OS/libs/coreinit/coreinit_DynLoad.cpp b/src/Cafe/OS/libs/coreinit/coreinit_DynLoad.cpp index c8b05124..546501b6 100644 --- a/src/Cafe/OS/libs/coreinit/coreinit_DynLoad.cpp +++ b/src/Cafe/OS/libs/coreinit/coreinit_DynLoad.cpp @@ -86,8 +86,7 @@ namespace coreinit } // search for loaded modules with matching name uint32 rplHandle = RPLLoader_GetHandleByModuleName(libName); - - if (rplHandle == RPL_INVALID_HANDLE) + if (rplHandle == RPL_INVALID_HANDLE && !RPLLoader_HasDependency(libName)) { RPLLoader_AddDependency(libName); RPLLoader_UpdateDependencies(); @@ -100,7 +99,10 @@ namespace coreinit else *moduleHandleOut = rplHandle; if (rplHandle == RPL_INVALID_HANDLE) + { + cemuLog_logDebug(LogType::Force, "OSDynLoad_Acquire() failed to load module '{}'", libName); return 0xFFFCFFE9; // module not found + } return 0; } diff --git a/src/Cafe/OS/libs/swkbd/swkbd.cpp b/src/Cafe/OS/libs/swkbd/swkbd.cpp index 6cc88874..d30992b0 100644 --- a/src/Cafe/OS/libs/swkbd/swkbd.cpp +++ b/src/Cafe/OS/libs/swkbd/swkbd.cpp @@ -276,7 +276,6 @@ void swkbdExport_SwkbdDisappearKeyboard(PPCInterpreter_t* hCPU) void swkbdExport_SwkbdGetInputFormString(PPCInterpreter_t* hCPU) { - debug_printf("SwkbdGetInputFormString__3RplFv LR: %08x\n", hCPU->spr.LR); for(sint32 i=0; iformStringLength; i++) { swkbdInternalState->formStringBufferBE[i] = _swapEndianU16(swkbdInternalState->formStringBuffer[i]); @@ -287,7 +286,6 @@ void swkbdExport_SwkbdGetInputFormString(PPCInterpreter_t* hCPU) void swkbdExport_SwkbdIsDecideOkButton(PPCInterpreter_t* hCPU) { - debug_printf("SwkbdIsDecideOkButton__3RplFPb LR: %08x\n", hCPU->spr.LR); if (swkbdInternalState->decideButtonWasPressed) osLib_returnFromFunction(hCPU, 1); else