mirror of
https://github.com/wiiu-env/WiiUPluginLoaderBackend.git
synced 2024-11-29 08:04:15 +01:00
Try to allocate memory for the plugins via the memory mapping module
This commit is contained in:
parent
f11649bc36
commit
b48a53b63d
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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;
|
@ -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
|
@ -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);
|
||||||
|
}
|
||||||
|
@ -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");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user