2020-12-26 14:17:50 +01:00
# include <wums.h>
2020-05-28 20:49:52 +02:00
# include <coreinit/debug.h>
2020-04-29 18:02:36 +02:00
# include <coreinit/cache.h>
2022-01-30 13:31:58 +01:00
# include <coreinit/ios.h>
2021-04-01 00:37:22 +02:00
# include <coreinit/dynload.h>
# include <coreinit/memdefaultheap.h>
2021-12-15 17:09:30 +01:00
# include <memory>
2020-12-26 14:17:50 +01:00
# include "plugin/PluginContainer.h"
# include "globals.h"
2020-04-29 18:02:36 +02:00
# include "plugin/PluginDataFactory.h"
2020-12-26 14:17:50 +01:00
# include "plugin/PluginDataPersistence.h"
2020-04-29 18:02:36 +02:00
# include "plugin/PluginContainerPersistence.h"
2020-05-03 10:21:05 +02:00
# include "PluginManagement.h"
2020-12-28 14:38:08 +01:00
# include "hooks.h"
2020-12-28 14:38:49 +01:00
# include "patcher/hooks_patcher_static.h"
2020-04-29 18:02:36 +02:00
2020-05-17 21:08:13 +02:00
WUMS_MODULE_EXPORT_NAME ( " homebrew_wupsbackend " ) ;
2020-04-29 18:02:36 +02:00
2021-04-07 00:23:23 +02:00
WUMS_USE_WUT_DEVOPTAB ( ) ;
2021-09-17 16:45:11 +02:00
2020-06-06 22:10:41 +02:00
WUMS_INITIALIZE ( args ) {
2022-01-23 21:43:54 +01:00
initLogging ( ) ;
2020-12-26 14:17:50 +01:00
2020-06-06 22:10:41 +02:00
gModuleData = args . module_information ;
2020-12-26 14:17:50 +01:00
if ( gModuleData = = nullptr ) {
2020-06-07 14:10:31 +02:00
OSFatal ( " WUPS-Backend: Failed to get gModuleData pointer. " ) ;
}
2020-12-26 14:17:50 +01:00
if ( gModuleData - > version ! = MODULE_INFORMATION_VERSION ) {
2020-06-07 14:10:31 +02:00
OSFatal ( " WUPS-Backend: The module information struct version does not match. " ) ;
}
2022-01-23 21:43:54 +01:00
DEBUG_FUNCTION_LINE ( " Init successful " ) ;
deinitLogging ( ) ;
2020-12-28 14:38:08 +01:00
}
2021-03-16 17:55:32 +01:00
WUMS_APPLICATION_REQUESTS_EXIT ( ) {
CallHook ( gPluginInformation , WUPS_LOADER_HOOK_APPLICATION_REQUESTS_EXIT ) ;
2022-01-23 21:43:54 +01:00
deinitLogging ( ) ;
2021-03-16 17:55:32 +01:00
}
2020-12-28 14:38:08 +01:00
WUMS_APPLICATION_ENDS ( ) {
2021-03-16 17:55:32 +01:00
CallHook ( gPluginInformation , WUPS_LOADER_HOOK_APPLICATION_ENDS ) ;
2022-01-23 21:16:38 +01:00
CallHook ( gPluginInformation , WUPS_LOADER_HOOK_FINI_WRAPPER ) ;
2021-04-17 14:05:39 +02:00
CallHook ( gPluginInformation , WUPS_LOADER_HOOK_FINI_WUT_SOCKETS ) ;
2021-03-16 17:55:32 +01:00
CallHook ( gPluginInformation , WUPS_LOADER_HOOK_FINI_WUT_DEVOPTAB ) ;
CallHook ( gPluginInformation , WUPS_LOADER_HOOK_FINI_WUT_STDCPP ) ;
CallHook ( gPluginInformation , WUPS_LOADER_HOOK_FINI_WUT_NEWLIB ) ;
CallHook ( gPluginInformation , WUPS_LOADER_HOOK_FINI_WUT_MALLOC ) ;
2020-12-28 14:38:49 +01:00
auto pluginInformation = gPluginInformation ;
for ( int32_t plugin_index = pluginInformation - > number_used_plugins - 1 ; plugin_index > = 0 ; plugin_index - - ) {
FunctionPatcherRestoreDynamicFunctions ( pluginInformation - > plugin_data [ plugin_index ] . info . functions , pluginInformation - > plugin_data [ plugin_index ] . info . number_used_functions ) ;
}
FunctionPatcherRestoreDynamicFunctions ( method_hooks_hooks_static , method_hooks_size_hooks_static ) ;
2020-04-29 18:02:36 +02:00
}
2021-04-01 00:37:22 +02:00
void * allocOnCustomHeap ( int alignment , int size ) ;
2022-01-30 13:31:58 +01:00
std : : string getPluginPath ( ) {
char environmentPath [ 0x100 ] ;
memset ( environmentPath , 0 , sizeof ( environmentPath ) ) ;
auto handle = IOS_Open ( " /dev/mcp " , IOS_OPEN_READ ) ;
if ( handle > = 0 ) {
int in = 0xF9 ; // IPC_CUSTOM_COPY_ENVIRONMENT_PATH
if ( IOS_Ioctl ( handle , 100 , & in , sizeof ( in ) , environmentPath , sizeof ( environmentPath ) ) ! = IOS_ERROR_OK ) {
return " fs:/vol/external01/wiiu/plugins " ;
}
IOS_Close ( handle ) ;
}
return std : : string ( environmentPath ) + " /plugins " ;
}
2022-01-23 21:43:54 +01: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-01-23 21:43:54 +01:00
initLogging ( ) ;
2020-05-03 10:21:05 +02:00
bool initNeeded = false ;
2021-04-01 00:37:22 +02:00
if ( gPluginDataHeap = = nullptr ) {
2020-06-06 22:10:41 +02:00
DCFlushRange ( ( void * ) gModuleData , sizeof ( module_information_t ) ) ;
2020-04-29 18:02:36 +02:00
uint32_t endAddress = 0 ;
2020-05-03 10:21:05 +02:00
for ( int i = 0 ; i < gModuleData - > number_used_modules ; i + + ) {
2020-04-29 18:02:36 +02:00
uint32_t curEndAddr = gModuleData - > module_data [ i ] . endAddress ;
2020-05-03 10:21:05 +02:00
if ( curEndAddr > endAddress ) {
2020-04-29 18:02:36 +02:00
endAddress = curEndAddr ;
}
}
2020-05-17 20:49:31 +02:00
memset ( ( void * ) & gLinkOnReload , 0 , sizeof ( gLinkOnReload ) ) ;
2020-04-29 18:02:36 +02:00
// If this address is 0, make sure the header common match the one
2020-05-03 10:21:05 +02:00
// in the SetupPayload repo. (I know that's a bad idea)
2020-04-29 18:02:36 +02:00
endAddress = ( endAddress + 0x100 ) & 0xFFFFFF00 ;
2021-04-01 00:37:22 +02:00
gPluginInformationHeapSize = 0x00FFF000 - endAddress ;
DEBUG_FUNCTION_LINE ( " Create heap for plugins information " ) ;
gPluginInformationHeap = MEMCreateExpHeapEx ( ( void * ) ( endAddress ) , gPluginInformationHeapSize , 0 ) ;
2021-01-10 13:17:47 +01:00
2021-04-01 00:37:22 +02:00
if ( gPluginInformationHeap = = nullptr ) {
OSFatal ( " PluginBackend: Failed to allocate memory for plugin information " ) ;
}
2020-04-29 18:02:36 +02:00
2021-04-01 00:37:22 +02:00
void * pluginHeapMemory = allocOnCustomHeap ( 0x1000 , PLUGIN_DATA_HEAP_SIZE ) ;
if ( pluginHeapMemory = = nullptr ) {
DEBUG_FUNCTION_LINE ( " Use plugins information heap as fallback " ) ;
gPluginDataHeap = gPluginInformationHeap ;
gPluginDataHeapSize = gPluginInformationHeapSize ;
} else {
gPluginDataHeap = MEMCreateExpHeapEx ( pluginHeapMemory , PLUGIN_DATA_HEAP_SIZE , 0 ) ;
gPluginDataHeapSize = PLUGIN_DATA_HEAP_SIZE ;
}
if ( gPluginDataHeap ! = nullptr ) {
2021-01-10 13:17:47 +01:00
if ( gPluginInformation = = nullptr ) {
2021-04-01 00:37:22 +02:00
DEBUG_FUNCTION_LINE_VERBOSE ( " Allocate gPluginInformation on heap %08X (size: %d bytes) " , gPluginInformationHeap , sizeof ( plugin_information_t ) ) ;
gPluginInformation = ( plugin_information_t * ) MEMAllocFromExpHeapEx ( gPluginInformationHeap , sizeof ( plugin_information_t ) , 4 ) ;
2021-01-10 13:17:47 +01:00
if ( gPluginInformation = = nullptr ) {
2021-04-01 00:37:22 +02:00
OSFatal ( " PluginBackend: Failed to allocate global plugin information " ) ;
2020-06-03 18:21:43 +02:00
return ;
2020-04-29 18:02:36 +02:00
}
2020-05-03 10:21:05 +02:00
memset ( ( void * ) gPluginInformation , 0 , sizeof ( plugin_information_t ) ) ;
2020-04-29 18:02:36 +02:00
}
2021-04-01 00:37:22 +02:00
if ( gTrampolineData = = nullptr ) {
2022-01-27 12:47:33 +01:00
DEBUG_FUNCTION_LINE_VERBOSE ( " Allocate gTrampolineData on heap %08X (size: %d bytes) " , gPluginDataHeap , sizeof ( relocation_trampoline_entry_t ) * NUMBER_OF_TRAMPS ) ;
gTrampolineData = ( relocation_trampoline_entry_t * ) MEMAllocFromExpHeapEx ( gPluginDataHeap , sizeof ( relocation_trampoline_entry_t ) * NUMBER_OF_TRAMPS , 4 ) ;
2021-04-01 00:37:22 +02:00
if ( gTrampolineData = = nullptr ) {
OSFatal ( " PluginBackend: Failed to allocate gTrampolineData " ) ;
return ;
}
gTrampolineDataSize = NUMBER_OF_TRAMPS ;
2022-01-27 12:47:33 +01:00
memset ( ( void * ) gTrampolineData , 0 , sizeof ( relocation_trampoline_entry_t ) * NUMBER_OF_TRAMPS ) ;
2021-04-01 00:37:22 +02:00
}
DEBUG_FUNCTION_LINE ( " Available memory for storing plugins: %d kb " , MEMGetAllocatableSizeForExpHeapEx ( gPluginDataHeap , 4 ) / 1024 ) ;
2020-05-03 11:13:55 +02:00
2022-01-30 13:31:58 +01:00
auto pluginPath = getPluginPath ( ) ;
DEBUG_FUNCTION_LINE ( " Load plugins from %s " , pluginPath . c_str ( ) ) ;
std : : vector < std : : shared_ptr < PluginData > > pluginList = PluginDataFactory : : loadDir ( pluginPath , gPluginDataHeap ) ;
DEBUG_FUNCTION_LINE ( " Loaded data for %d plugins. " , pluginList . size ( ) ) ;
2020-04-29 18:02:36 +02:00
2022-01-23 21:43:54 +01:00
auto plugins = PluginManagement : : loadPlugins ( pluginList , gPluginDataHeap , gTrampolineData , gTrampolineDataSize ) ;
2021-09-25 14:26:18 +02:00
for ( auto & pluginContainer : plugins ) {
2022-01-23 21:43:54 +01:00
# ifdef DEBUG
2021-12-15 17:09:30 +01:00
for ( const auto & kv : pluginContainer - > getPluginInformation ( ) - > getSectionInfoList ( ) ) {
DEBUG_FUNCTION_LINE_VERBOSE ( " %s = %s %08X %d " , kv . first . c_str ( ) , kv . second - > getName ( ) . c_str ( ) , kv . second - > getAddress ( ) , kv . second - > getSize ( ) ) ;
2020-04-29 18:02:36 +02:00
}
2022-01-23 21:43:54 +01:00
# endif
2021-12-15 17:04:30 +01:00
if ( ! PluginContainerPersistence : : savePlugin ( gPluginInformation , pluginContainer , gPluginDataHeap ) ) {
2020-05-03 10:21:05 +02:00
DEBUG_FUNCTION_LINE ( " Failed to save plugin " ) ;
}
2020-04-29 18:02:36 +02:00
}
2022-01-23 21:43:54 +01:00
2020-05-03 10:21:05 +02:00
initNeeded = true ;
2020-04-29 18:02:36 +02:00
}
}
2020-05-17 20:49:31 +02:00
if ( gLinkOnReload . loadOnReload ) {
2021-01-10 13:17:47 +01:00
DEBUG_FUNCTION_LINE ( " Reload with new plugin list. " ) ;
2021-12-15 17:09:30 +01:00
std : : vector < std : : shared_ptr < PluginData > > pluginDataList ;
2020-05-17 20:49:31 +02:00
for ( int32_t i = 0 ; i < gLinkOnReload . number_used_plugins ; i + + ) {
auto pluginData = PluginDataPersistence : : load ( & gLinkOnReload . plugin_data [ i ] ) ;
pluginDataList . push_back ( pluginData ) ;
}
for ( int32_t plugin_index = 0 ; plugin_index < gPluginInformation - > number_used_plugins ; plugin_index + + ) {
plugin_information_single_t * plugin = & ( gPluginInformation - > plugin_data [ plugin_index ] ) ;
BOOL doDelete = true ;
for ( auto & pluginData : pluginDataList ) {
2021-12-15 17:09:30 +01:00
if ( pluginData - > buffer = = plugin - > data . buffer ) {
2020-05-17 20:49:31 +02:00
doDelete = false ;
break ;
}
}
if ( doDelete ) {
2021-01-10 13:17:47 +01:00
DEBUG_FUNCTION_LINE ( " We need to delete the plugin data for plugin %s " , plugin - > meta . name ) ;
2020-05-17 20:49:31 +02:00
if ( plugin - > data . buffer ! = nullptr ) {
if ( plugin - > data . memoryType = = eMemTypeMEM2 ) {
2021-02-19 19:41:04 +01:00
DEBUG_FUNCTION_LINE_VERBOSE ( " Free plugin data buffer for %s [%08X] " , plugin - > meta . name , plugin - > data . buffer ) ;
2020-05-17 20:49:31 +02:00
free ( plugin - > data . buffer ) ;
} else if ( plugin - > data . memoryType = = eMemTypeExpHeap ) {
2021-02-19 19:41:04 +01:00
DEBUG_FUNCTION_LINE_VERBOSE ( " Free plugin data buffer for %s [%08X on heap %08X] " , plugin - > meta . name , plugin - > data . buffer , plugin - > data . heapHandle ) ;
2020-05-17 20:49:31 +02:00
MEMFreeToExpHeap ( ( MEMHeapHandle ) plugin - > data . heapHandle , plugin - > data . buffer ) ;
} else {
DEBUG_FUNCTION_LINE ( " ######################## " ) ;
DEBUG_FUNCTION_LINE ( " Failed to free memory from plugin " ) ;
DEBUG_FUNCTION_LINE ( " ######################## " ) ;
}
2021-01-10 13:17:47 +01:00
plugin - > data . buffer = nullptr ;
2020-05-17 20:49:31 +02:00
plugin - > data . bufferLength = 0 ;
} else {
2021-01-10 13:17:47 +01:00
DEBUG_FUNCTION_LINE ( " Plugin %s has no copy of elf saved in memory, can't free it " , plugin - > meta . name ) ;
2020-05-17 20:49:31 +02:00
}
}
}
2021-04-01 00:37:22 +02:00
PluginManagement : : unloadPlugins ( gPluginInformation , gPluginDataHeap , false ) ;
2020-05-17 20:49:31 +02:00
2021-12-15 17:09:30 +01:00
auto plugins = PluginManagement : : loadPlugins ( pluginDataList , gPluginDataHeap , gTrampolineData , gTrampolineDataSize ) ;
2020-05-17 20:49:31 +02:00
2021-09-25 14:26:18 +02:00
for ( auto & pluginContainer : plugins ) {
2021-12-15 17:09:30 +01:00
DEBUG_FUNCTION_LINE ( " Stored information for plugin %s ; %s " , pluginContainer - > getMetaInformation ( ) - > getName ( ) . c_str ( ) , pluginContainer - > getMetaInformation ( ) - > getAuthor ( ) . c_str ( ) ) ;
2021-12-15 17:04:30 +01:00
if ( ! PluginContainerPersistence : : savePlugin ( gPluginInformation , pluginContainer , gPluginDataHeap ) ) {
2020-05-17 20:49:31 +02:00
DEBUG_FUNCTION_LINE ( " Failed to save plugin " ) ;
}
}
gLinkOnReload . loadOnReload = false ;
initNeeded = true ;
}
2020-04-29 18:02:36 +02:00
2021-04-01 00:37:22 +02:00
if ( gPluginDataHeap ! = nullptr ) {
2022-01-23 21:16:38 +01:00
auto plugins = PluginContainerPersistence : : loadPlugins ( gPluginInformation ) ;
2022-01-27 12:47:33 +01:00
PluginManagement : : doRelocations ( plugins , gTrampolineData , DYN_LINK_TRAMPOLINE_LIST_LENGTH ) ;
2020-06-03 19:33:09 +02:00
// PluginManagement::memsetBSS(plugins);
2020-04-29 18:02:36 +02:00
2021-04-01 00:37:22 +02:00
DCFlushRange ( ( void * ) gPluginDataHeap , gPluginDataHeapSize ) ;
ICInvalidateRange ( ( void * ) gPluginDataHeap , gPluginDataHeapSize ) ;
DCFlushRange ( ( void * ) gPluginInformation , sizeof ( plugin_information_t ) ) ;
ICInvalidateRange ( ( void * ) gPluginInformation , sizeof ( plugin_information_t ) ) ;
2020-04-29 18:02:36 +02:00
2021-03-16 17:55:32 +01:00
CallHook ( gPluginInformation , WUPS_LOADER_HOOK_INIT_WUT_MALLOC ) ;
CallHook ( gPluginInformation , WUPS_LOADER_HOOK_INIT_WUT_NEWLIB ) ;
CallHook ( gPluginInformation , WUPS_LOADER_HOOK_INIT_WUT_STDCPP ) ;
CallHook ( gPluginInformation , WUPS_LOADER_HOOK_INIT_WUT_DEVOPTAB ) ;
2021-04-17 14:05:39 +02:00
CallHook ( gPluginInformation , WUPS_LOADER_HOOK_INIT_WUT_SOCKETS ) ;
2021-03-16 17:55:32 +01:00
2022-01-23 21:16:38 +01:00
CallHook ( gPluginInformation , WUPS_LOADER_HOOK_INIT_WRAPPER ) ;
2020-05-03 10:21:05 +02:00
if ( initNeeded ) {
PluginManagement : : callInitHooks ( gPluginInformation ) ;
2020-04-29 18:02:36 +02:00
}
2020-05-03 10:21:05 +02:00
PluginManagement : : PatchFunctionsAndCallHooks ( gPluginInformation ) ;
2020-04-29 18:02:36 +02:00
}
}
2021-04-01 00:37:22 +02:00
void * allocOnCustomHeap ( int alignment , int size ) {
OSDynLoad_Module module ;
OSDynLoad_Error dyn_res = OSDynLoad_Acquire ( " homebrew_memorymapping " , & module ) ;
if ( dyn_res ! = OS_DYNLOAD_OK ) {
return nullptr ;
}
uint32_t * custom_memalign ;
dyn_res = OSDynLoad_FindExport ( module , true , " MEMAllocFromMappedMemoryEx " , reinterpret_cast < void * * > ( & custom_memalign ) ) ;
2021-12-15 17:04:30 +01:00
auto * customMEMAllocFromDefaultHeapEx = ( void * ( * ) ( uint32_t , int ) ) * custom_memalign ;
2021-04-01 00:37:22 +02:00
if ( dyn_res ! = OS_DYNLOAD_OK ) {
return nullptr ;
}
return customMEMAllocFromDefaultHeapEx ( size , alignment ) ;
}