2022-02-04 16:25:44 +01:00
# include "PluginManagement.h"
2023-07-15 13:11:31 +02:00
# include "coreinit/interrupts.h"
# include "coreinit/scheduler.h"
2022-02-04 16:25:44 +01:00
# include "globals.h"
# include "hooks.h"
# include "patcher/hooks_patcher_static.h"
# include "plugin/PluginDataFactory.h"
2022-02-14 20:26:32 +01:00
# include "utils/utils.h"
2022-02-04 16:25:44 +01:00
# include <coreinit/debug.h>
2023-08-16 10:08:44 +02:00
# include <notifications/notifications.h>
2022-02-04 16:25:44 +01:00
# include <wums.h>
2020-04-29 18:02:36 +02:00
2020-05-17 21:08:13 +02:00
WUMS_MODULE_EXPORT_NAME ( " homebrew_wupsbackend " ) ;
2021-04-07 00:23:23 +02:00
WUMS_USE_WUT_DEVOPTAB ( ) ;
2023-01-07 13:29:53 +01:00
WUMS_DEPENDS_ON ( homebrew_functionpatcher ) ;
WUMS_DEPENDS_ON ( homebrew_memorymapping ) ;
2023-08-16 10:08:44 +02:00
WUMS_DEPENDS_ON ( homebrew_notifications ) ;
2021-09-17 16:45:11 +02:00
2022-05-14 14:00:20 +02:00
WUMS_INITIALIZE ( ) {
2022-01-23 21:43:54 +01:00
initLogging ( ) ;
2023-01-07 13:39:29 +01:00
if ( FunctionPatcher_InitLibrary ( ) ! = FUNCTION_PATCHER_RESULT_SUCCESS ) {
OSFatal ( " homebrew_wupsbackend: FunctionPatcher_InitLibrary failed " ) ;
}
2023-08-16 10:08:44 +02:00
NotificationModuleStatus res ;
if ( ( res = NotificationModule_InitLibrary ( ) ) ! = NOTIFICATION_MODULE_RESULT_SUCCESS ) {
2023-11-04 15:32:45 +01:00
DEBUG_FUNCTION_LINE_ERR ( " Failed to init NotificationModule: %s (%d) " , NotificationModule_GetStatusStr ( res ) , res ) ;
2023-08-16 10:08:44 +02:00
gNotificationModuleLoaded = false ;
} else {
gNotificationModuleLoaded = true ;
}
2022-05-14 14:00:20 +02:00
DEBUG_FUNCTION_LINE ( " Patching functions " ) ;
for ( uint32_t i = 0 ; i < method_hooks_static_size ; i + + ) {
2023-01-07 13:39:29 +01:00
if ( FunctionPatcher_AddFunctionPatch ( & method_hooks_static [ i ] , nullptr , nullptr ) ! = FUNCTION_PATCHER_RESULT_SUCCESS ) {
OSFatal ( " homebrew_wupsbackend: Failed to AddPatch function " ) ;
2022-05-14 14:00:20 +02:00
}
2020-06-07 14:10:31 +02:00
}
2023-11-04 15:32:45 +01:00
2022-01-23 21:43:54 +01:00
deinitLogging ( ) ;
2020-12-28 14:38:08 +01:00
}
2021-03-16 17:55:32 +01:00
WUMS_APPLICATION_REQUESTS_EXIT ( ) {
2022-05-14 14:00:20 +02:00
uint32_t upid = OSGetUPID ( ) ;
if ( upid ! = 2 & & upid ! = 15 ) {
return ;
}
CallHook ( gLoadedPlugins , WUPS_LOADER_HOOK_APPLICATION_REQUESTS_EXIT ) ;
2021-03-16 17:55:32 +01:00
}
2020-12-28 14:38:08 +01:00
WUMS_APPLICATION_ENDS ( ) {
2022-05-14 14:00:20 +02:00
uint32_t upid = OSGetUPID ( ) ;
if ( upid ! = 2 & & upid ! = 15 ) {
return ;
2022-02-11 22:18:56 +01:00
}
2023-08-16 10:08:44 +02:00
2022-05-14 14:00:20 +02:00
CallHook ( gLoadedPlugins , WUPS_LOADER_HOOK_APPLICATION_ENDS ) ;
CallHook ( gLoadedPlugins , WUPS_LOADER_HOOK_FINI_WUT_SOCKETS ) ;
CallHook ( gLoadedPlugins , WUPS_LOADER_HOOK_FINI_WUT_DEVOPTAB ) ;
2022-02-11 22:19:27 +01:00
2023-11-04 15:32:45 +01:00
for ( const auto & pair : gUsedRPLs ) {
2022-10-05 20:08:49 +02:00
OSDynLoad_Release ( pair . second ) ;
}
gUsedRPLs . clear ( ) ;
2022-02-14 20:24:41 +01:00
deinitLogging ( ) ;
2020-04-29 18:02:36 +02:00
}
2023-07-15 13:11:31 +02:00
void CheckCleanupCallbackUsage ( const std : : vector < std : : unique_ptr < PluginContainer > > & plugins ) ;
2021-04-01 00:37:22 +02:00
2020-06-03 18:21:43 +02:00
WUMS_APPLICATION_STARTS ( ) {
2020-05-28 20:49:52 +02:00
uint32_t upid = OSGetUPID ( ) ;
if ( upid ! = 2 & & upid ! = 15 ) {
2020-06-03 18:21:43 +02:00
return ;
2020-05-28 20:49:52 +02:00
}
2022-10-03 21:58:11 +02:00
2022-09-19 16:06:55 +02:00
OSReport ( " Running WiiUPluginLoaderBackend " VERSION_FULL " \n " ) ;
2022-10-05 20:08:49 +02:00
gUsedRPLs . clear ( ) ;
// If an allocated rpl was not released properly (e.g. if something else calls OSDynload_Acquire without releasing it) memory get leaked.
// Let's clean this up!
2023-11-04 15:32:45 +01:00
for ( const auto & addr : gAllocatedAddresses ) {
2022-10-05 20:08:49 +02:00
DEBUG_FUNCTION_LINE_WARN ( " Memory allocated by OSDynload was not freed properly, let's clean it up! (%08X) " , addr ) ;
free ( ( void * ) addr ) ;
}
gAllocatedAddresses . clear ( ) ;
2022-01-23 21:43:54 +01:00
initLogging ( ) ;
2020-05-03 10:21:05 +02:00
bool initNeeded = false ;
2020-05-17 20:49:31 +02:00
2022-05-14 14:00:20 +02:00
std : : lock_guard < std : : mutex > lock ( gLoadedDataMutex ) ;
2020-04-29 18:02:36 +02:00
2023-11-04 15:32:45 +01:00
if ( gTrampData . empty ( ) ) {
gTrampData = std : : vector < relocation_trampoline_entry_t > ( TRAMP_DATA_SIZE ) ;
for ( auto & cur : gTrampData ) {
cur . status = RELOC_TRAMP_FREE ;
2022-05-14 14:00:20 +02:00
}
}
2021-04-01 00:37:22 +02:00
2022-05-14 14:00:20 +02:00
if ( gLoadedPlugins . empty ( ) ) {
auto pluginPath = getPluginPath ( ) ;
2021-01-10 13:17:47 +01:00
2022-05-14 14:00:20 +02:00
DEBUG_FUNCTION_LINE ( " Load plugins from %s " , pluginPath . c_str ( ) ) ;
2020-04-29 18:02:36 +02:00
2022-05-14 14:00:20 +02:00
auto pluginData = PluginDataFactory : : loadDir ( pluginPath ) ;
2023-11-04 15:32:45 +01:00
gLoadedPlugins = PluginManagement : : loadPlugins ( pluginData , gTrampData ) ;
2022-05-14 14:00:20 +02:00
initNeeded = true ;
2020-04-29 18:02:36 +02:00
}
2020-05-17 20:49:31 +02:00
2022-05-14 14:00:20 +02:00
if ( ! gLoadOnNextLaunch . empty ( ) ) {
2023-07-15 13:11:31 +02:00
auto * currentThread = OSGetCurrentThread ( ) ;
auto saved_reent = currentThread - > reserved [ 4 ] ;
auto saved_cleanupCallback = currentThread - > cleanupCallback ;
currentThread - > reserved [ 4 ] = 0 ;
2022-12-30 21:08:22 +01:00
CallHook ( gLoadedPlugins , WUPS_LOADER_HOOK_DEINIT_PLUGIN ) ;
2023-07-15 13:11:31 +02:00
CheckCleanupCallbackUsage ( gLoadedPlugins ) ;
if ( currentThread - > cleanupCallback ! = saved_cleanupCallback ) {
DEBUG_FUNCTION_LINE_WARN ( " WUPS_LOADER_HOOK_DEINIT_PLUGIN overwrote the ThreadCleanupCallback, we need to restore it! \n " ) ;
OSSetThreadCleanupCallback ( OSGetCurrentThread ( ) , saved_cleanupCallback ) ;
}
currentThread - > reserved [ 4 ] = saved_reent ;
2022-05-14 14:00:20 +02:00
DEBUG_FUNCTION_LINE ( " Restore function patches of currently loaded plugins. " ) ;
PluginManagement : : RestoreFunctionPatches ( gLoadedPlugins ) ;
2023-12-16 12:44:20 +01:00
for ( auto & plugin : gLoadedPlugins ) {
WUPSStorageError err = plugin - > CloseStorage ( ) ;
if ( err ! = WUPS_STORAGE_ERROR_SUCCESS ) {
DEBUG_FUNCTION_LINE_ERR ( " Failed to close storage for plugin: %s " , plugin - > getMetaInformation ( ) . getName ( ) . c_str ( ) ) ;
}
}
2022-05-14 14:00:20 +02:00
DEBUG_FUNCTION_LINE ( " Unload existing plugins. " ) ;
gLoadedPlugins . clear ( ) ;
2023-11-04 15:32:45 +01:00
for ( auto & cur : gTrampData ) {
cur . status = RELOC_TRAMP_FREE ;
}
2020-05-17 20:49:31 +02:00
2022-10-03 21:58:11 +02:00
DEBUG_FUNCTION_LINE ( " Load new plugins " ) ;
2023-11-04 15:32:45 +01:00
gLoadedPlugins = PluginManagement : : loadPlugins ( gLoadOnNextLaunch , gTrampData ) ;
2022-05-14 14:00:20 +02:00
initNeeded = true ;
}
2020-05-17 20:49:31 +02:00
2022-05-14 14:00:20 +02:00
DEBUG_FUNCTION_LINE ( " Clear plugin data lists. " ) ;
gLoadOnNextLaunch . clear ( ) ;
gLoadedData . clear ( ) ;
2020-05-17 20:49:31 +02:00
2022-05-14 14:00:20 +02:00
if ( ! gLoadedPlugins . empty ( ) ) {
2023-11-04 15:32:45 +01:00
if ( ! PluginManagement : : doRelocations ( gLoadedPlugins , gTrampData , gUsedRPLs ) ) {
2022-05-14 14:00:20 +02:00
DEBUG_FUNCTION_LINE_ERR ( " Relocations failed " ) ;
2023-11-04 15:32:45 +01:00
OSFatal ( " WiiUPluginLoaderBackend: Relocations failed. \n See crash logs for more information. " ) ;
2020-05-17 20:49:31 +02:00
}
2020-06-03 19:33:09 +02:00
// PluginManagement::memsetBSS(plugins);
2020-04-29 18:02:36 +02:00
2022-02-11 22:19:27 +01:00
if ( initNeeded ) {
2022-05-14 14:00:20 +02:00
CallHook ( gLoadedPlugins , WUPS_LOADER_HOOK_INIT_WUT_MALLOC ) ;
CallHook ( gLoadedPlugins , WUPS_LOADER_HOOK_INIT_WUT_NEWLIB ) ;
CallHook ( gLoadedPlugins , WUPS_LOADER_HOOK_INIT_WUT_STDCPP ) ;
2022-02-11 22:19:27 +01:00
}
2022-05-14 14:00:20 +02:00
CallHook ( gLoadedPlugins , WUPS_LOADER_HOOK_INIT_WUT_DEVOPTAB ) ;
CallHook ( gLoadedPlugins , WUPS_LOADER_HOOK_INIT_WUT_SOCKETS ) ;
2021-03-16 17:55:32 +01:00
2022-02-11 22:19:27 +01:00
if ( initNeeded ) {
2022-05-14 14:00:20 +02:00
CallHook ( gLoadedPlugins , WUPS_LOADER_HOOK_INIT_WRAPPER ) ;
2022-02-11 22:19:27 +01:00
}
2022-01-23 21:16:38 +01:00
2020-05-03 10:21:05 +02:00
if ( initNeeded ) {
2023-12-16 12:44:20 +01:00
for ( auto & plugin : gLoadedPlugins ) {
WUPSStorageError err = plugin - > OpenStorage ( ) ;
if ( err ! = WUPS_STORAGE_ERROR_SUCCESS ) {
DEBUG_FUNCTION_LINE_ERR ( " Failed to open storage for plugin: %s. (%s) " , plugin - > getMetaInformation ( ) . getName ( ) . c_str ( ) , WUPSStorageAPI_GetStatusStr ( err ) ) ;
}
}
2022-05-14 14:00:20 +02:00
PluginManagement : : callInitHooks ( gLoadedPlugins ) ;
2020-04-29 18:02:36 +02:00
}
2022-05-14 14:00:20 +02:00
CallHook ( gLoadedPlugins , WUPS_LOADER_HOOK_APPLICATION_STARTS ) ;
2021-04-01 00:37:22 +02:00
}
2023-07-15 13:11:31 +02:00
}
void CheckCleanupCallbackUsage ( const std : : vector < std : : unique_ptr < PluginContainer > > & plugins ) {
auto * curThread = OSGetCurrentThread ( ) ;
for ( const auto & cur : plugins ) {
2023-11-04 15:32:45 +01:00
auto textSection = cur - > getPluginInformation ( ) . getSectionInfo ( " .text " ) ;
if ( ! textSection ) {
2023-07-15 13:11:31 +02:00
continue ;
}
2023-11-04 15:32:45 +01:00
uint32_t startAddress = textSection - > getAddress ( ) ;
uint32_t endAddress = textSection - > getAddress ( ) + textSection - > getSize ( ) ;
auto * pluginName = cur - > getMetaInformation ( ) . getName ( ) . c_str ( ) ;
2023-07-15 13:11:31 +02:00
{
__OSLockScheduler ( curThread ) ;
int state = OSDisableInterrupts ( ) ;
OSThread * t = * ( ( OSThread * * ) 0x100567F8 ) ;
while ( t ) {
auto address = reinterpret_cast < uint32_t > ( t - > cleanupCallback ) ;
if ( address ! = 0 & & address > = startAddress & & address < = endAddress ) {
OSReport ( " [WARN] PluginBackend: Thread 0x%08X is using a function from plugin %s for the threadCleanupCallback \n " , t , pluginName ) ;
}
t = t - > activeLink . next ;
}
OSRestoreInterrupts ( state ) ;
__OSUnlockScheduler ( curThread ) ;
}
}
}