From a867320a87f7e7406327581b24528eeb5ac376be Mon Sep 17 00:00:00 2001 From: Hyper <34012267+hyperbx@users.noreply.github.com> Date: Mon, 26 Aug 2024 22:13:27 +0100 Subject: [PATCH] [Kernel] Implemented XexLoadImageFromMemory --- src/xenia/kernel/kernel_state.cc | 35 ++++++++++++++- src/xenia/kernel/kernel_state.h | 3 ++ src/xenia/kernel/user_module.cc | 7 +++ src/xenia/kernel/user_module.h | 2 + src/xenia/kernel/xboxkrnl/xboxkrnl_modules.cc | 44 ++++++++++++++++--- 5 files changed, 84 insertions(+), 7 deletions(-) diff --git a/src/xenia/kernel/kernel_state.cc b/src/xenia/kernel/kernel_state.cc index c2bf03e5d..7e582daee 100644 --- a/src/xenia/kernel/kernel_state.cc +++ b/src/xenia/kernel/kernel_state.cc @@ -443,7 +443,7 @@ object_ref KernelState::LoadUserModule( // See if we've already loaded it for (auto& existing_module : user_modules_) { - if (existing_module->path() == path) { + if (existing_module->Matches(path)) { return existing_module; } } @@ -466,6 +466,39 @@ object_ref KernelState::LoadUserModule( return module; } +object_ref KernelState::LoadUserModuleFromMemory( + const std::string_view raw_name, const void* addr, const size_t length) { + auto name = xe::utf8::find_base_name_from_guest_path(raw_name); + + object_ref module; + { + auto global_lock = global_critical_region_.Acquire(); + + // See if we've already loaded it + for (auto& existing_module : user_modules_) { + if (existing_module->Matches(name)) { + return existing_module; + } + } + + global_lock.unlock(); + + // Module wasn't loaded, so load it. + module = object_ref(new UserModule(this)); + X_STATUS status = module->LoadFromMemoryNamed(name, addr, length); + if (XFAILED(status)) { + object_table()->ReleaseHandle(module->handle()); + return nullptr; + } + + global_lock.lock(); + + // Putting into the listing automatically retains. + user_modules_.push_back(module); + } + return module; +} + X_RESULT KernelState::FinishLoadingUserModule( const object_ref module, bool call_entry) { // TODO(Gliniak): Apply custom patches here diff --git a/src/xenia/kernel/kernel_state.h b/src/xenia/kernel/kernel_state.h index 5777714ab..691155756 100644 --- a/src/xenia/kernel/kernel_state.h +++ b/src/xenia/kernel/kernel_state.h @@ -258,6 +258,9 @@ class KernelState { void SetExecutableModule(object_ref module); object_ref LoadUserModule(const std::string_view name, bool call_entry = true); + object_ref LoadUserModuleFromMemory(const std::string_view name, + const void* addr, + const size_t length); X_RESULT FinishLoadingUserModule(const object_ref module, bool call_entry = true); void UnloadUserModule(const object_ref& module, diff --git a/src/xenia/kernel/user_module.cc b/src/xenia/kernel/user_module.cc index 61e088f8c..474068482 100644 --- a/src/xenia/kernel/user_module.cc +++ b/src/xenia/kernel/user_module.cc @@ -182,6 +182,13 @@ X_STATUS UserModule::LoadFromMemory(const void* addr, const size_t length) { return X_STATUS_SUCCESS; } +X_STATUS UserModule::LoadFromMemoryNamed(const std::string_view raw_name, + const void* addr, + const size_t length) { + name_ = std::string(raw_name); + return LoadFromMemory(addr, length); +} + X_STATUS UserModule::LoadContinue() { // LoadXexContinue: finishes loading XEX after a patch has been applied (or // patch wasn't found) diff --git a/src/xenia/kernel/user_module.h b/src/xenia/kernel/user_module.h index 8d2b2d2f2..02dbc3e7d 100644 --- a/src/xenia/kernel/user_module.h +++ b/src/xenia/kernel/user_module.h @@ -76,6 +76,8 @@ class UserModule : public XModule { X_STATUS LoadFromFile(const std::string_view path); X_STATUS LoadFromMemory(const void* addr, const size_t length); + X_STATUS LoadFromMemoryNamed(const std::string_view name, const void* addr, + const size_t length); X_STATUS LoadContinue(); X_STATUS Unload(); diff --git a/src/xenia/kernel/xboxkrnl/xboxkrnl_modules.cc b/src/xenia/kernel/xboxkrnl/xboxkrnl_modules.cc index 607d81c8e..95878e90f 100644 --- a/src/xenia/kernel/xboxkrnl/xboxkrnl_modules.cc +++ b/src/xenia/kernel/xboxkrnl/xboxkrnl_modules.cc @@ -91,19 +91,28 @@ dword_result_t XexGetModuleSection_entry(lpvoid_t hmodule, lpstring_t name, } DECLARE_XBOXKRNL_EXPORT1(XexGetModuleSection, kModules, kImplemented); -dword_result_t XexLoadImage_entry(lpstring_t module_name, dword_t module_flags, - dword_t min_version, lpdword_t hmodule_ptr) { +dword_result_t xeXexLoadImage( + lpstring_t module_name, dword_t module_flags, dword_t min_version, + lpdword_t hmodule_ptr, + const std::function()>& load_callback, + bool isFromMemory) { X_STATUS result = X_STATUS_NO_SUCH_FILE; uint32_t hmodule = 0; auto module = kernel_state()->GetModule(module_name.value()); if (module) { - // Existing module found. - hmodule = module->hmodule_ptr(); - result = X_STATUS_SUCCESS; + if (isFromMemory) { + // Existing module found; return error status. + *hmodule_ptr = hmodule; + return X_STATUS_OBJECT_NAME_COLLISION; + } else { + // Existing module found. + hmodule = module->hmodule_ptr(); + result = X_STATUS_SUCCESS; + } } else { // Not found; attempt to load as a user module. - auto user_module = kernel_state()->LoadUserModule(module_name.value()); + auto user_module = load_callback(); if (user_module) { kernel_state()->FinishLoadingUserModule(user_module); // Give up object ownership, this reference will be released by the last @@ -125,8 +134,31 @@ dword_result_t XexLoadImage_entry(lpstring_t module_name, dword_t module_flags, return result; } + +dword_result_t XexLoadImage_entry(lpstring_t module_name, dword_t module_flags, + dword_t min_version, lpdword_t hmodule_ptr) { + auto load_callback = [module_name] { + return kernel_state()->LoadUserModule(module_name.value()); + }; + return xeXexLoadImage(module_name, module_flags, min_version, hmodule_ptr, + load_callback, false); +} DECLARE_XBOXKRNL_EXPORT1(XexLoadImage, kModules, kImplemented); +dword_result_t XexLoadImageFromMemory_entry(lpdword_t buffer, dword_t size, + lpstring_t module_name, + dword_t module_flags, + dword_t min_version, + lpdword_t hmodule_ptr) { + auto load_callback = [module_name, buffer, size] { + return kernel_state()->LoadUserModuleFromMemory(module_name.value(), buffer, + size); + }; + return xeXexLoadImage(module_name, module_flags, min_version, hmodule_ptr, + load_callback, true); +} +DECLARE_XBOXKRNL_EXPORT1(XexLoadImageFromMemory, kModules, kImplemented); + dword_result_t XexLoadExecutable_entry(lpstring_t module_name, dword_t module_flags, dword_t min_version,