diff --git a/src/Cafe/OS/RPL/rpl.cpp b/src/Cafe/OS/RPL/rpl.cpp index b2eb4d0ee2..384a54a2e1 100644 --- a/src/Cafe/OS/RPL/rpl.cpp +++ b/src/Cafe/OS/RPL/rpl.cpp @@ -2400,6 +2400,20 @@ RPLModule** RPLLoader_GetModuleList() return rplModuleList; } +RPLModule* RPLLoader_GetModuleByName(std::string_view name) +{ + std::string normalizedName = _RPLLoader_ExtractModuleNameFromPath(name); + RPLModule** modules = RPLLoader_GetModuleList(); + + for (uint32 i = 0; i < RPLLoader_GetModuleCount(); i++) + { + if (modules[i]->moduleName == normalizedName) + return modules[i]; + } + + return nullptr; +} + sint32 RPLLoader_GetModuleCount() { return rplModuleCount; diff --git a/src/Cafe/OS/RPL/rpl.h b/src/Cafe/OS/RPL/rpl.h index 4d670444a5..1d9f872cdd 100644 --- a/src/Cafe/OS/RPL/rpl.h +++ b/src/Cafe/OS/RPL/rpl.h @@ -47,6 +47,7 @@ uint32 RPLLoader_GetSDA2Base(); sint32 RPLLoader_GetModuleCount(); RPLModule** RPLLoader_GetModuleList(); +RPLModule* RPLLoader_GetModuleByName(std::string_view name); MEMPTR RPLLoader_AllocateCodeCaveMem(uint32 alignment, uint32 size); void RPLLoader_ReleaseCodeCaveMem(MEMPTR addr); diff --git a/src/Cafe/OS/libs/coreinit/coreinit_DynLoad.cpp b/src/Cafe/OS/libs/coreinit/coreinit_DynLoad.cpp index 45a2b71ffe..86a28e5750 100644 --- a/src/Cafe/OS/libs/coreinit/coreinit_DynLoad.cpp +++ b/src/Cafe/OS/libs/coreinit/coreinit_DynLoad.cpp @@ -12,6 +12,8 @@ namespace coreinit MPTR _osDynLoadTLSFuncAlloc = MPTR_NULL; MPTR _osDynLoadTLSFuncFree = MPTR_NULL; + static std::vector notifyCallbacks; + uint32 OSDynLoad_SetAllocator(MPTR allocFunc, MPTR freeFunc) { _osDynLoadFuncAlloc = allocFunc; @@ -109,6 +111,34 @@ namespace coreinit cemuLog_logDebug(LogType::Force, "OSDynLoad_Acquire() failed to load module '{}'", libName); return 0xFFFCFFE9; // module not found } + + for (const auto& cb : notifyCallbacks) + { + MEMPTR notifyData; + notifyData = (OSDynLoad_NotifyData*)OSDynLoad_AllocatorAlloc(sizeof(OSDynLoad_NotifyData), 4); + RPLModule* module = RPLLoader_GetModuleByName(tempLibName); + + if (!module) + break; + + notifyData->name = module->ppcName.GetMPTR(); + + notifyData->textAddr = module->regionMappingBase_text.GetBEValue(); + notifyData->textOffset = module->regionMappingBase_text.GetMPTR() - module->regionOrigAddr_text; + notifyData->textSize = module->regionSize_text; + + notifyData->dataAddr = module->regionMappingBase_data; + notifyData->dataOffset = module->regionMappingBase_data - module->regionOrigAddr_data; + notifyData->dataSize = module->regionSize_data; + + notifyData->readAddr = module->regionMappingBase_data; + notifyData->readOffset = module->regionMappingBase_data - module->regionOrigAddr_data; + notifyData->readSize = module->regionSize_data; + + PPCCoreCallback(cb.callback, moduleHandleOut, cb.userContext.GetMPTR(), 1, notifyData.GetMPTR()); + OSDynLoad_AllocatorFree(notifyData); + + } return 0; } @@ -121,6 +151,35 @@ namespace coreinit { if (moduleHandle == RPL_INVALID_HANDLE) return; + + for (const auto& cb : notifyCallbacks) + { + MEMPTR notifyData; + notifyData = (OSDynLoad_NotifyData*)OSDynLoad_AllocatorAlloc(sizeof(OSDynLoad_NotifyData), 4); + RPLModule* module = RPLLoader_GetModuleByName(RPLLoader_GetModuleNameByHandle(moduleHandle)); + + if (!module) + break; + + notifyData->name = module->ppcName.GetMPTR(); + + notifyData->textAddr = module->regionMappingBase_text.GetBEValue(); + notifyData->textOffset = module->regionMappingBase_text.GetMPTR() - module->regionOrigAddr_text; + notifyData->textSize = module->regionSize_text; + + notifyData->dataAddr = module->regionMappingBase_data; + notifyData->dataOffset = module->regionMappingBase_data - module->regionOrigAddr_data; + notifyData->dataSize = module->regionSize_data; + + notifyData->readAddr = module->regionMappingBase_data; + notifyData->readOffset = module->regionMappingBase_data - module->regionOrigAddr_data; + notifyData->readSize = module->regionSize_data; + + PPCCoreCallback(cb.callback, moduleHandle, cb.userContext.GetMPTR(), 2, notifyData.GetMPTR()); + OSDynLoad_AllocatorFree(notifyData); + + } + RPLLoader_RemoveDependency(moduleHandle); RPLLoader_UpdateDependencies(); } @@ -195,6 +254,25 @@ namespace coreinit return 1; } + uint32 OSDynLoad_AddNotifyCallback(MEMPTR notifyFn, MEMPTR userContext) + { + if (!notifyFn) + return 0xBAD1000E; // notify function pointer is null + + notifyCallbacks.emplace_back(notifyFn, userContext); + return 0; + } + + uint32 OSDynLoad_DelNotifyCallback(MEMPTR notifyFn, MEMPTR userContext) + { + std::erase_if(notifyCallbacks, [&](const NotifyCallbackEntry& entry) + { + return entry.callback.GetMPTR() == notifyFn.GetMPTR() && entry.userContext == userContext; + }); + + return 0; + } + void InitializeDynLoad() { cafeExportRegister("coreinit", OSDynLoad_SetAllocator, LogType::Placeholder); @@ -209,5 +287,8 @@ namespace coreinit cafeExportRegister("coreinit", OSDynLoad_GetModuleName, LogType::Placeholder); cafeExportRegister("coreinit", OSDynLoad_GetNumberOfRPLs, LogType::Placeholder); cafeExportRegister("coreinit", OSDynLoad_GetRPLInfo, LogType::Placeholder); + + cafeExportRegister("coreinit", OSDynLoad_AddNotifyCallback, LogType::Placeholder); + cafeExportRegister("coreinit", OSDynLoad_DelNotifyCallback, LogType::Placeholder); } } diff --git a/src/Cafe/OS/libs/coreinit/coreinit_DynLoad.h b/src/Cafe/OS/libs/coreinit/coreinit_DynLoad.h index ad1662e084..2789d3ae57 100644 --- a/src/Cafe/OS/libs/coreinit/coreinit_DynLoad.h +++ b/src/Cafe/OS/libs/coreinit/coreinit_DynLoad.h @@ -19,6 +19,16 @@ namespace coreinit uint32be readSize; }; + using OSDynLoadNotifyFunc = void (*)(uint32be* module, void *userContext, sint32 notifyReason, OSDynLoad_NotifyData *infos); + + struct NotifyCallbackEntry + { + MEMPTR callback; + MEMPTR userContext; + + NotifyCallbackEntry(MEMPTR func, MEMPTR context) : callback(func), userContext(context) {} + }; + uint32 OSDynLoad_SetAllocator(MPTR allocFunc, MPTR freeFunc); void OSDynLoad_SetTLSAllocator(MPTR allocFunc, MPTR freeFunc); uint32 OSDynLoad_GetAllocator(betype* funcAlloc, betype* funcFree); @@ -35,5 +45,8 @@ namespace coreinit sint32 OSDynLoad_GetNumberOfRPLs(); uint32 OSDynLoad_GetRPLInfo(uint32 first, uint32 count, OSDynLoad_NotifyData* outInfos); + uint32 OSDynLoad_AddNotifyCallback(MEMPTR notifyFn, MEMPTR userContext); + uint32 OSDynLoad_DelNotifyCallback(MEMPTR notifyFn, MEMPTR userContext); + void InitializeDynLoad(); -} \ No newline at end of file +}