diff --git a/source/PluginManagement.cpp b/source/PluginManagement.cpp index 0cf20e9..928239b 100644 --- a/source/PluginManagement.cpp +++ b/source/PluginManagement.cpp @@ -11,6 +11,7 @@ #include "utils/ElfUtils.h" #include "PluginManagement.h" #include "hooks.h" +#include "globals.h" bool PluginManagement::doRelocation(const std::vector &relocData, relocation_trampolin_entry_t *tramp_data, uint32_t tramp_length, uint32_t trampolinID) { std::map moduleHandleCache; @@ -139,10 +140,11 @@ void PluginManagement::unloadPlugins(plugin_information_t *gPluginInformation, M DEBUG_FUNCTION_LINE_VERBOSE("Deleted allocated .data section for plugin %s [%08X]", plugin->meta.name, plugin->info.allocatedDataMemoryAddress); } - for (auto &trampoline : gPluginInformation->trampolines) { - if (trampoline.id == plugin->info.trampolinId) { - trampoline.id = 0; - trampoline.status = RELOC_TRAMP_FREE; + for (uint32_t i = 0; i < gTrampolineDataSize; i++) { + auto trampoline = &(gTrampolineData[i]); + if (trampoline->id == plugin->info.trampolinId) { + trampoline->id = 0; + trampoline->status = RELOC_TRAMP_FREE; } } } diff --git a/source/common/plugin_defines.h b/source/common/plugin_defines.h index 3d3f825..56ff17c 100644 --- a/source/common/plugin_defines.h +++ b/source/common/plugin_defines.h @@ -40,13 +40,13 @@ extern "C" { #define PLUGIN_DYN_LINK_RELOCATION_LIST_LENGTH 1000 -#define MAXIMUM_HOOKS_PER_PLUGIN 25 -#define MAXIMUM_FUNCTION_PER_PLUGIN 100 +#define MAXIMUM_HOOKS_PER_PLUGIN 25 +#define MAXIMUM_FUNCTION_PER_PLUGIN 100 struct plugin_section_info_t { - char name[MAXIMUM_PLUGIN_SECTION_NAME_LENGTH] = ""; - uint32_t addr; - uint32_t size; + char name[MAXIMUM_PLUGIN_SECTION_NAME_LENGTH] = ""; + uint32_t addr; + uint32_t size; }; struct plugin_meta_info_t { @@ -95,7 +95,6 @@ struct plugin_information_single_t { struct plugin_information_t { int32_t number_used_plugins = 0; // Number of used plugins. Maximum is MAXIMUM_PLUGINS plugin_information_single_t plugin_data[MAXIMUM_PLUGINS]; - relocation_trampolin_entry_t trampolines[DYN_LINK_TRAMPOLIN_LIST_LENGTH]; dyn_linking_relocation_data_t linking_data; // RPL and function name list }; diff --git a/source/globals.cpp b/source/globals.cpp index 5274d93..05559fe 100644 --- a/source/globals.cpp +++ b/source/globals.cpp @@ -1,8 +1,12 @@ #include "globals.h" -MEMHeapHandle pluginDataHeap __attribute__((section(".data"))) = nullptr; +MEMHeapHandle gPluginDataHeap __attribute__((section(".data"))) = nullptr; +MEMHeapHandle gPluginInformationHeap __attribute__((section(".data"))) = nullptr; plugin_information_t *gPluginInformation __attribute__((section(".data"))) = nullptr; plugin_information_on_reload_t gLinkOnReload __attribute__((section(".data"))); module_information_t *gModuleData __attribute__((section(".data"))) = nullptr; +relocation_trampolin_entry_t *gTrampolineData __attribute__((section(".data"))) = nullptr; -uint32_t gPluginDataHeapSize = 0; \ No newline at end of file +uint32_t gPluginDataHeapSize = 0; +uint32_t gPluginInformationHeapSize = 0; +uint32_t gTrampolineDataSize = 0; \ No newline at end of file diff --git a/source/globals.h b/source/globals.h index e3313af..957fa1b 100644 --- a/source/globals.h +++ b/source/globals.h @@ -6,7 +6,14 @@ #include "common/plugin_defines.h" extern plugin_information_t *gPluginInformation; -extern MEMHeapHandle pluginDataHeap; +extern MEMHeapHandle gPluginDataHeap; +extern MEMHeapHandle gPluginInformationHeap; extern uint32_t gPluginDataHeapSize; +extern uint32_t gPluginInformationHeapSize; extern plugin_information_on_reload_t gLinkOnReload; -extern module_information_t *gModuleData; \ No newline at end of file +extern module_information_t *gModuleData; +extern relocation_trampolin_entry_t *gTrampolineData; +extern uint32_t gTrampolineDataSize; + +#define PLUGIN_DATA_HEAP_SIZE (8 * 1024 * 1024) +#define NUMBER_OF_TRAMPS 1024 \ No newline at end of file diff --git a/source/main.cpp b/source/main.cpp index 50efd07..f53c17c 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -2,6 +2,8 @@ #include #include #include +#include +#include #include "plugin/PluginContainer.h" #include "globals.h" #include "plugin/PluginDataFactory.h" @@ -43,6 +45,8 @@ WUMS_APPLICATION_ENDS() { FunctionPatcherRestoreDynamicFunctions(method_hooks_hooks_static, method_hooks_size_hooks_static); } +void *allocOnCustomHeap(int alignment, int size); + WUMS_APPLICATION_STARTS() { WHBLogUdpInit(); uint32_t upid = OSGetUPID(); @@ -50,11 +54,9 @@ WUMS_APPLICATION_STARTS() { return; } bool initNeeded = false; - if (pluginDataHeap == nullptr) { - DEBUG_FUNCTION_LINE_VERBOSE("gModuleData = %08X", gModuleData); + if (gPluginDataHeap == nullptr) { DCFlushRange((void *) gModuleData, sizeof(module_information_t)); uint32_t endAddress = 0; - DEBUG_FUNCTION_LINE_VERBOSE("Using %d modules", gModuleData->number_used_modules); for (int i = 0; i < gModuleData->number_used_modules; i++) { uint32_t curEndAddr = gModuleData->module_data[i].endAddress; if (curEndAddr > endAddress) { @@ -67,26 +69,50 @@ WUMS_APPLICATION_STARTS() { // in the SetupPayload repo. (I know that's a bad idea) endAddress = (endAddress + 0x100) & 0xFFFFFF00; - gPluginDataHeapSize = 0x00FFF000 - endAddress; + gPluginInformationHeapSize = 0x00FFF000 - endAddress; - DEBUG_FUNCTION_LINE("Create heap to store plugins"); - pluginDataHeap = MEMCreateExpHeapEx((void *) (endAddress), gPluginDataHeapSize, 0); + DEBUG_FUNCTION_LINE("Create heap for plugins information"); + gPluginInformationHeap = MEMCreateExpHeapEx((void *) (endAddress), gPluginInformationHeapSize, 0); - if (pluginDataHeap != nullptr) { + if (gPluginInformationHeap == nullptr) { + OSFatal("PluginBackend: Failed to allocate memory for plugin information"); + } + + 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) { if (gPluginInformation == nullptr) { - DEBUG_FUNCTION_LINE_VERBOSE("Allocate gPluginInformation on heap %08X (size: %d bytes)", pluginDataHeap, sizeof(plugin_information_t)); - gPluginInformation = (plugin_information_t *) MEMAllocFromExpHeapEx(pluginDataHeap, sizeof(plugin_information_t), 4); + 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); if (gPluginInformation == nullptr) { - DEBUG_FUNCTION_LINE("Failed to allocate global plugin information"); + OSFatal("PluginBackend: Failed to allocate global plugin information"); return; } memset((void *) gPluginInformation, 0, sizeof(plugin_information_t)); } - DEBUG_FUNCTION_LINE("Available memory for storing plugins: %d kb", MEMGetAllocatableSizeForExpHeapEx(pluginDataHeap, 4) / 1024); - std::vector pluginList = PluginDataFactory::loadDir("fs:/vol/external01/wiiu/plugins/", pluginDataHeap); + if (gTrampolineData == nullptr) { + DEBUG_FUNCTION_LINE_VERBOSE("Allocate gTrampolineData on heap %08X (size: %d bytes)", gPluginDataHeap, sizeof(relocation_trampolin_entry_t) * NUMBER_OF_TRAMPS); + gTrampolineData = (relocation_trampolin_entry_t *) MEMAllocFromExpHeapEx(gPluginDataHeap, sizeof(relocation_trampolin_entry_t) * NUMBER_OF_TRAMPS, 4); + if (gTrampolineData == nullptr) { + OSFatal("PluginBackend: Failed to allocate gTrampolineData"); + return; + } + gTrampolineDataSize = NUMBER_OF_TRAMPS; + memset((void *) gTrampolineData, 0, sizeof(relocation_trampolin_entry_t) * NUMBER_OF_TRAMPS); + } + DEBUG_FUNCTION_LINE("Available memory for storing plugins: %d kb", MEMGetAllocatableSizeForExpHeapEx(gPluginDataHeap, 4) / 1024); + std::vector pluginList = PluginDataFactory::loadDir("fs:/vol/external01/wiiu/plugins/", gPluginDataHeap); DEBUG_FUNCTION_LINE("Loaded data for %d plugins.", pluginList.size()); - std::vector plugins = PluginManagement::loadPlugins(pluginList, pluginDataHeap, gPluginInformation->trampolines, DYN_LINK_TRAMPOLIN_LIST_LENGTH); + std::vector plugins = PluginManagement::loadPlugins(pluginList, gPluginDataHeap, gTrampolineData, gTrampolineDataSize); for (auto &pluginContainer : plugins) { for (const auto &kv : pluginContainer.getPluginInformation().getSectionInfoList()) { @@ -138,9 +164,9 @@ WUMS_APPLICATION_STARTS() { } } - PluginManagement::unloadPlugins(gPluginInformation, pluginDataHeap, false); + PluginManagement::unloadPlugins(gPluginInformation, gPluginDataHeap, false); - std::vector plugins = PluginManagement::loadPlugins(pluginDataList, pluginDataHeap, gPluginInformation->trampolines, DYN_LINK_TRAMPOLIN_LIST_LENGTH); + std::vector plugins = PluginManagement::loadPlugins(pluginDataList, gPluginDataHeap, gTrampolineData, gTrampolineDataSize); for (auto &pluginContainer : plugins) { DEBUG_FUNCTION_LINE("Stored information for plugin %s ; %s", pluginContainer.getMetaInformation().getName().c_str(), pluginContainer.getMetaInformation().getAuthor().c_str()); @@ -152,13 +178,15 @@ WUMS_APPLICATION_STARTS() { initNeeded = true; } - if (pluginDataHeap != nullptr) { + if (gPluginDataHeap != nullptr) { std::vector plugins = PluginContainerPersistence::loadPlugins(gPluginInformation); - PluginManagement::doRelocations(plugins, gPluginInformation->trampolines, DYN_LINK_TRAMPOLIN_LIST_LENGTH); + PluginManagement::doRelocations(plugins, gTrampolineData, DYN_LINK_TRAMPOLIN_LIST_LENGTH); // PluginManagement::memsetBSS(plugins); - DCFlushRange((void *) pluginDataHeap, gPluginDataHeapSize); - ICInvalidateRange((void *) pluginDataHeap, gPluginDataHeapSize); + DCFlushRange((void *) gPluginDataHeap, gPluginDataHeapSize); + ICInvalidateRange((void *) gPluginDataHeap, gPluginDataHeapSize); + DCFlushRange((void *) gPluginInformation, sizeof(plugin_information_t)); + ICInvalidateRange((void *) gPluginInformation, sizeof(plugin_information_t)); CallHook(gPluginInformation, WUPS_LOADER_HOOK_INIT_WUT_MALLOC); CallHook(gPluginInformation, WUPS_LOADER_HOOK_INIT_WUT_NEWLIB); @@ -172,3 +200,19 @@ WUMS_APPLICATION_STARTS() { PluginManagement::PatchFunctionsAndCallHooks(gPluginInformation); } } + +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(&custom_memalign)); + void *(*customMEMAllocFromDefaultHeapEx)(uint32_t size, int align) = (void *(*)(uint32_t, int)) *custom_memalign; + + if (dyn_res != OS_DYNLOAD_OK) { + return nullptr; + } + return customMEMAllocFromDefaultHeapEx(size, alignment); +} diff --git a/source/utils/ElfUtils.cpp b/source/utils/ElfUtils.cpp index 0522eaf..a12f68d 100644 --- a/source/utils/ElfUtils.cpp +++ b/source/utils/ElfUtils.cpp @@ -96,19 +96,17 @@ bool ElfUtils::elfLinkOne(char type, size_t offset, int32_t addend, uint32_t des break; } } - if (freeSlot != NULL) { + if (freeSlot == NULL) { DEBUG_FUNCTION_LINE("***24-bit relative branch cannot hit target. Trampolin data list is full"); - DEBUG_FUNCTION_LINE("***value %08X - target %08X = distance %08X", value, target, distance); + DEBUG_FUNCTION_LINE("***value %08X - target %08X = distance %08X", value, target, target - (uint32_t) &(freeSlot->trampolin[0])); return false; } if (target - (uint32_t) &(freeSlot->trampolin[0]) > 0x1FFFFFC) { DEBUG_FUNCTION_LINE("**Cannot link 24-bit jump (too far to tramp buffer)."); - DEBUG_FUNCTION_LINE("***value %08X - target %08X = distance %08X", value, target, distance); + DEBUG_FUNCTION_LINE("***value %08X - target %08X = distance %08X", value, target, (target - (uint32_t) &(freeSlot->trampolin[0]))); return false; } - DEBUG_FUNCTION_LINE("freeSlot = %08X", freeSlot); - freeSlot->trampolin[0] = 0x3D600000 | ((((uint32_t) value) >> 16) & 0x0000FFFF); // lis r11, real_addr@h freeSlot->trampolin[1] = 0x616B0000 | (((uint32_t) value) & 0x0000ffff); // ori r11, r11, real_addr@l freeSlot->trampolin[2] = 0x7D6903A6; // mtctr r11 @@ -124,12 +122,11 @@ bool ElfUtils::elfLinkOne(char type, size_t offset, int32_t addend, uint32_t des freeSlot->status = RELOC_TRAMP_FIXED; } else { // Relocations for the imports may be overridden - freeSlot->status = RELOC_TRAMP_IMPORT_IN_PROGRESS; + freeSlot->status = RELOC_TRAMP_IMPORT_DONE; } uint32_t symbolValue = (uint32_t) &(freeSlot->trampolin[0]); value = symbolValue + addend; distance = static_cast(value) - static_cast(target); - DEBUG_FUNCTION_LINE("Created tramp"); } } diff --git a/source/utils/exports.cpp b/source/utils/exports.cpp index 8468ccb..9073139 100644 --- a/source/utils/exports.cpp +++ b/source/utils/exports.cpp @@ -67,11 +67,11 @@ extern "C" int32_t WUPSDeletePluginData(const plugin_data_handle *plugin_data_ha extern "C" int32_t WUPSLoadPluginAsData(GetPluginInformationInputType inputType, const char *path, char *buffer, size_t size, plugin_data_handle *out) { std::optional pluginData; if (inputType == PLUGIN_INFORMATION_INPUT_TYPE_PATH && path != nullptr) { - pluginData = PluginDataFactory::load(path, pluginDataHeap); + pluginData = PluginDataFactory::load(path, gPluginDataHeap); } else if (inputType == PLUGIN_INFORMATION_INPUT_TYPE_BUFFER && buffer != nullptr && size > 0) { std::vector data(size); memcpy(&data[0], buffer, size); - pluginData = PluginDataFactory::load(data, pluginDataHeap); + pluginData = PluginDataFactory::load(data, gPluginDataHeap); } else { return ERROR_INVALID_ARG; }