coreinit_Dynload: Implement notify callbacks

Implements the following coreinit functions:
- OSDynLoad_AddNotifyCallback
- OSDynLoad_DelNotifyCallback
This commit is contained in:
techmuse
2026-07-22 16:08:40 -04:00
parent 50b9e4ba1d
commit 09728c8cb4
4 changed files with 107 additions and 0 deletions

View File

@@ -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;

View File

@@ -47,6 +47,7 @@ uint32 RPLLoader_GetSDA2Base();
sint32 RPLLoader_GetModuleCount();
RPLModule** RPLLoader_GetModuleList();
RPLModule* RPLLoader_GetModuleByName(std::string_view name);
MEMPTR<void> RPLLoader_AllocateCodeCaveMem(uint32 alignment, uint32 size);
void RPLLoader_ReleaseCodeCaveMem(MEMPTR<void> addr);

View File

@@ -12,6 +12,8 @@ namespace coreinit
MPTR _osDynLoadTLSFuncAlloc = MPTR_NULL;
MPTR _osDynLoadTLSFuncFree = MPTR_NULL;
static std::vector<NotifyCallbackEntry> 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<OSDynLoad_NotifyData> 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<OSDynLoad_NotifyData> 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<OSDynLoadNotifyFunc> notifyFn, MEMPTR<void> userContext)
{
if (!notifyFn)
return 0xBAD1000E; // notify function pointer is null
notifyCallbacks.emplace_back(notifyFn, userContext);
return 0;
}
uint32 OSDynLoad_DelNotifyCallback(MEMPTR<OSDynLoadNotifyFunc> notifyFn, MEMPTR<void> 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);
}
}

View File

@@ -19,6 +19,14 @@ namespace coreinit
uint32be readSize;
};
using OSDynLoadNotifyFunc = void (*)(uint32be* module, void *userContext, sint32 notifyReason, OSDynLoad_NotifyData *infos);
struct NotifyCallbackEntry
{
MEMPTR<OSDynLoadNotifyFunc> callback;
MEMPTR<void> userContext;
};
uint32 OSDynLoad_SetAllocator(MPTR allocFunc, MPTR freeFunc);
void OSDynLoad_SetTLSAllocator(MPTR allocFunc, MPTR freeFunc);
uint32 OSDynLoad_GetAllocator(betype<MPTR>* funcAlloc, betype<MPTR>* funcFree);
@@ -35,5 +43,8 @@ namespace coreinit
sint32 OSDynLoad_GetNumberOfRPLs();
uint32 OSDynLoad_GetRPLInfo(uint32 first, uint32 count, OSDynLoad_NotifyData* outInfos);
uint32 OSDynLoad_AddNotifyCallback(MEMPTR<OSDynLoadNotifyFunc> notifyFn, MEMPTR<void> userContext);
uint32 OSDynLoad_DelNotifyCallback(MEMPTR<OSDynLoadNotifyFunc> notifyFn, MEMPTR<void> userContext);
void InitializeDynLoad();
}