Try to allocate memory for the plugins via the memory mapping module

This commit is contained in:
Maschell 2021-04-01 00:37:22 +02:00
parent f11649bc36
commit b48a53b63d
7 changed files with 95 additions and 42 deletions

View File

@ -11,6 +11,7 @@
#include "utils/ElfUtils.h" #include "utils/ElfUtils.h"
#include "PluginManagement.h" #include "PluginManagement.h"
#include "hooks.h" #include "hooks.h"
#include "globals.h"
bool PluginManagement::doRelocation(const std::vector<RelocationData> &relocData, relocation_trampolin_entry_t *tramp_data, uint32_t tramp_length, uint32_t trampolinID) { bool PluginManagement::doRelocation(const std::vector<RelocationData> &relocData, relocation_trampolin_entry_t *tramp_data, uint32_t tramp_length, uint32_t trampolinID) {
std::map<std::string, OSDynLoad_Module> moduleHandleCache; std::map<std::string, OSDynLoad_Module> 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); DEBUG_FUNCTION_LINE_VERBOSE("Deleted allocated .data section for plugin %s [%08X]", plugin->meta.name, plugin->info.allocatedDataMemoryAddress);
} }
for (auto &trampoline : gPluginInformation->trampolines) { for (uint32_t i = 0; i < gTrampolineDataSize; i++) {
if (trampoline.id == plugin->info.trampolinId) { auto trampoline = &(gTrampolineData[i]);
trampoline.id = 0; if (trampoline->id == plugin->info.trampolinId) {
trampoline.status = RELOC_TRAMP_FREE; trampoline->id = 0;
trampoline->status = RELOC_TRAMP_FREE;
} }
} }
} }

View File

@ -40,13 +40,13 @@ extern "C" {
#define PLUGIN_DYN_LINK_RELOCATION_LIST_LENGTH 1000 #define PLUGIN_DYN_LINK_RELOCATION_LIST_LENGTH 1000
#define MAXIMUM_HOOKS_PER_PLUGIN 25 #define MAXIMUM_HOOKS_PER_PLUGIN 25
#define MAXIMUM_FUNCTION_PER_PLUGIN 100 #define MAXIMUM_FUNCTION_PER_PLUGIN 100
struct plugin_section_info_t { struct plugin_section_info_t {
char name[MAXIMUM_PLUGIN_SECTION_NAME_LENGTH] = ""; char name[MAXIMUM_PLUGIN_SECTION_NAME_LENGTH] = "";
uint32_t addr; uint32_t addr;
uint32_t size; uint32_t size;
}; };
struct plugin_meta_info_t { struct plugin_meta_info_t {
@ -95,7 +95,6 @@ struct plugin_information_single_t {
struct plugin_information_t { struct plugin_information_t {
int32_t number_used_plugins = 0; // Number of used plugins. Maximum is MAXIMUM_PLUGINS int32_t number_used_plugins = 0; // Number of used plugins. Maximum is MAXIMUM_PLUGINS
plugin_information_single_t plugin_data[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 dyn_linking_relocation_data_t linking_data; // RPL and function name list
}; };

View File

@ -1,8 +1,12 @@
#include "globals.h" #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_t *gPluginInformation __attribute__((section(".data"))) = nullptr;
plugin_information_on_reload_t gLinkOnReload __attribute__((section(".data"))); plugin_information_on_reload_t gLinkOnReload __attribute__((section(".data")));
module_information_t *gModuleData __attribute__((section(".data"))) = nullptr; module_information_t *gModuleData __attribute__((section(".data"))) = nullptr;
relocation_trampolin_entry_t *gTrampolineData __attribute__((section(".data"))) = nullptr;
uint32_t gPluginDataHeapSize = 0; uint32_t gPluginDataHeapSize = 0;
uint32_t gPluginInformationHeapSize = 0;
uint32_t gTrampolineDataSize = 0;

View File

@ -6,7 +6,14 @@
#include "common/plugin_defines.h" #include "common/plugin_defines.h"
extern plugin_information_t *gPluginInformation; extern plugin_information_t *gPluginInformation;
extern MEMHeapHandle pluginDataHeap; extern MEMHeapHandle gPluginDataHeap;
extern MEMHeapHandle gPluginInformationHeap;
extern uint32_t gPluginDataHeapSize; extern uint32_t gPluginDataHeapSize;
extern uint32_t gPluginInformationHeapSize;
extern plugin_information_on_reload_t gLinkOnReload; extern plugin_information_on_reload_t gLinkOnReload;
extern module_information_t *gModuleData; 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

View File

@ -2,6 +2,8 @@
#include <wums.h> #include <wums.h>
#include <coreinit/debug.h> #include <coreinit/debug.h>
#include <coreinit/cache.h> #include <coreinit/cache.h>
#include <coreinit/dynload.h>
#include <coreinit/memdefaultheap.h>
#include "plugin/PluginContainer.h" #include "plugin/PluginContainer.h"
#include "globals.h" #include "globals.h"
#include "plugin/PluginDataFactory.h" #include "plugin/PluginDataFactory.h"
@ -43,6 +45,8 @@ WUMS_APPLICATION_ENDS() {
FunctionPatcherRestoreDynamicFunctions(method_hooks_hooks_static, method_hooks_size_hooks_static); FunctionPatcherRestoreDynamicFunctions(method_hooks_hooks_static, method_hooks_size_hooks_static);
} }
void *allocOnCustomHeap(int alignment, int size);
WUMS_APPLICATION_STARTS() { WUMS_APPLICATION_STARTS() {
WHBLogUdpInit(); WHBLogUdpInit();
uint32_t upid = OSGetUPID(); uint32_t upid = OSGetUPID();
@ -50,11 +54,9 @@ WUMS_APPLICATION_STARTS() {
return; return;
} }
bool initNeeded = false; bool initNeeded = false;
if (pluginDataHeap == nullptr) { if (gPluginDataHeap == nullptr) {
DEBUG_FUNCTION_LINE_VERBOSE("gModuleData = %08X", gModuleData);
DCFlushRange((void *) gModuleData, sizeof(module_information_t)); DCFlushRange((void *) gModuleData, sizeof(module_information_t));
uint32_t endAddress = 0; 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++) { for (int i = 0; i < gModuleData->number_used_modules; i++) {
uint32_t curEndAddr = gModuleData->module_data[i].endAddress; uint32_t curEndAddr = gModuleData->module_data[i].endAddress;
if (curEndAddr > endAddress) { if (curEndAddr > endAddress) {
@ -67,26 +69,50 @@ WUMS_APPLICATION_STARTS() {
// in the SetupPayload repo. (I know that's a bad idea) // in the SetupPayload repo. (I know that's a bad idea)
endAddress = (endAddress + 0x100) & 0xFFFFFF00; endAddress = (endAddress + 0x100) & 0xFFFFFF00;
gPluginDataHeapSize = 0x00FFF000 - endAddress; gPluginInformationHeapSize = 0x00FFF000 - endAddress;
DEBUG_FUNCTION_LINE("Create heap to store plugins"); DEBUG_FUNCTION_LINE("Create heap for plugins information");
pluginDataHeap = MEMCreateExpHeapEx((void *) (endAddress), gPluginDataHeapSize, 0); 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) { if (gPluginInformation == nullptr) {
DEBUG_FUNCTION_LINE_VERBOSE("Allocate gPluginInformation on heap %08X (size: %d bytes)", pluginDataHeap, sizeof(plugin_information_t)); DEBUG_FUNCTION_LINE_VERBOSE("Allocate gPluginInformation on heap %08X (size: %d bytes)", gPluginInformationHeap, sizeof(plugin_information_t));
gPluginInformation = (plugin_information_t *) MEMAllocFromExpHeapEx(pluginDataHeap, sizeof(plugin_information_t), 4); gPluginInformation = (plugin_information_t *) MEMAllocFromExpHeapEx(gPluginInformationHeap, sizeof(plugin_information_t), 4);
if (gPluginInformation == nullptr) { if (gPluginInformation == nullptr) {
DEBUG_FUNCTION_LINE("Failed to allocate global plugin information"); OSFatal("PluginBackend: Failed to allocate global plugin information");
return; return;
} }
memset((void *) gPluginInformation, 0, sizeof(plugin_information_t)); memset((void *) gPluginInformation, 0, sizeof(plugin_information_t));
} }
DEBUG_FUNCTION_LINE("Available memory for storing plugins: %d kb", MEMGetAllocatableSizeForExpHeapEx(pluginDataHeap, 4) / 1024); if (gTrampolineData == nullptr) {
std::vector<PluginData> pluginList = PluginDataFactory::loadDir("fs:/vol/external01/wiiu/plugins/", pluginDataHeap); 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<PluginData> pluginList = PluginDataFactory::loadDir("fs:/vol/external01/wiiu/plugins/", gPluginDataHeap);
DEBUG_FUNCTION_LINE("Loaded data for %d plugins.", pluginList.size()); DEBUG_FUNCTION_LINE("Loaded data for %d plugins.", pluginList.size());
std::vector<PluginContainer> plugins = PluginManagement::loadPlugins(pluginList, pluginDataHeap, gPluginInformation->trampolines, DYN_LINK_TRAMPOLIN_LIST_LENGTH); std::vector<PluginContainer> plugins = PluginManagement::loadPlugins(pluginList, gPluginDataHeap, gTrampolineData, gTrampolineDataSize);
for (auto &pluginContainer : plugins) { for (auto &pluginContainer : plugins) {
for (const auto &kv : pluginContainer.getPluginInformation().getSectionInfoList()) { 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<PluginContainer> plugins = PluginManagement::loadPlugins(pluginDataList, pluginDataHeap, gPluginInformation->trampolines, DYN_LINK_TRAMPOLIN_LIST_LENGTH); std::vector<PluginContainer> plugins = PluginManagement::loadPlugins(pluginDataList, gPluginDataHeap, gTrampolineData, gTrampolineDataSize);
for (auto &pluginContainer : plugins) { for (auto &pluginContainer : plugins) {
DEBUG_FUNCTION_LINE("Stored information for plugin %s ; %s", pluginContainer.getMetaInformation().getName().c_str(), pluginContainer.getMetaInformation().getAuthor().c_str()); 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; initNeeded = true;
} }
if (pluginDataHeap != nullptr) { if (gPluginDataHeap != nullptr) {
std::vector<PluginContainer> plugins = PluginContainerPersistence::loadPlugins(gPluginInformation); std::vector<PluginContainer> 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); // PluginManagement::memsetBSS(plugins);
DCFlushRange((void *) pluginDataHeap, gPluginDataHeapSize); DCFlushRange((void *) gPluginDataHeap, gPluginDataHeapSize);
ICInvalidateRange((void *) pluginDataHeap, 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_MALLOC);
CallHook(gPluginInformation, WUPS_LOADER_HOOK_INIT_WUT_NEWLIB); CallHook(gPluginInformation, WUPS_LOADER_HOOK_INIT_WUT_NEWLIB);
@ -172,3 +200,19 @@ WUMS_APPLICATION_STARTS() {
PluginManagement::PatchFunctionsAndCallHooks(gPluginInformation); 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<void **>(&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);
}

View File

@ -96,19 +96,17 @@ bool ElfUtils::elfLinkOne(char type, size_t offset, int32_t addend, uint32_t des
break; 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("***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; return false;
} }
if (target - (uint32_t) &(freeSlot->trampolin[0]) > 0x1FFFFFC) { if (target - (uint32_t) &(freeSlot->trampolin[0]) > 0x1FFFFFC) {
DEBUG_FUNCTION_LINE("**Cannot link 24-bit jump (too far to tramp buffer)."); 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; return false;
} }
DEBUG_FUNCTION_LINE("freeSlot = %08X", freeSlot);
freeSlot->trampolin[0] = 0x3D600000 | ((((uint32_t) value) >> 16) & 0x0000FFFF); // lis r11, real_addr@h 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[1] = 0x616B0000 | (((uint32_t) value) & 0x0000ffff); // ori r11, r11, real_addr@l
freeSlot->trampolin[2] = 0x7D6903A6; // mtctr r11 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; freeSlot->status = RELOC_TRAMP_FIXED;
} else { } else {
// Relocations for the imports may be overridden // 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]); uint32_t symbolValue = (uint32_t) &(freeSlot->trampolin[0]);
value = symbolValue + addend; value = symbolValue + addend;
distance = static_cast<int32_t>(value) - static_cast<int32_t>(target); distance = static_cast<int32_t>(value) - static_cast<int32_t>(target);
DEBUG_FUNCTION_LINE("Created tramp");
} }
} }

View File

@ -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) { extern "C" int32_t WUPSLoadPluginAsData(GetPluginInformationInputType inputType, const char *path, char *buffer, size_t size, plugin_data_handle *out) {
std::optional<PluginData> pluginData; std::optional<PluginData> pluginData;
if (inputType == PLUGIN_INFORMATION_INPUT_TYPE_PATH && path != nullptr) { 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) { } else if (inputType == PLUGIN_INFORMATION_INPUT_TYPE_BUFFER && buffer != nullptr && size > 0) {
std::vector<uint8_t> data(size); std::vector<uint8_t> data(size);
memcpy(&data[0], buffer, size); memcpy(&data[0], buffer, size);
pluginData = PluginDataFactory::load(data, pluginDataHeap); pluginData = PluginDataFactory::load(data, gPluginDataHeap);
} else { } else {
return ERROR_INVALID_ARG; return ERROR_INVALID_ARG;
} }