diff --git a/src/kernel/module.h b/src/kernel/module.h new file mode 100644 index 000000000..541f4472a --- /dev/null +++ b/src/kernel/module.h @@ -0,0 +1,24 @@ +#ifndef EMULATOR_SRC_KERNEL_MODULE_H_ +#define EMULATOR_SRC_KERNEL_MODULE_H_ + +#include "common/abi.h" + +#include +#include + +namespace Libs::LibKernel { + +using KernelModule = int32_t; +struct KernelLoadModuleOpt; +struct KernelUnloadModuleOpt; + +KernelModule KYTY_SYSV_ABI KernelLoadStartModule(const char* module_file_name, size_t args, + const void* argp, uint32_t flags, + const KernelLoadModuleOpt* opt, int* res); +int KYTY_SYSV_ABI KernelStopUnloadModule(KernelModule handle, size_t args, const void* argp, + uint32_t flags, const KernelUnloadModuleOpt* opt, + int* res); + +} // namespace Libs::LibKernel + +#endif // EMULATOR_SRC_KERNEL_MODULE_H_ diff --git a/src/libs/libKernel.cpp b/src/libs/libKernel.cpp index dcdd5d2e1..b8b60624c 100644 --- a/src/libs/libKernel.cpp +++ b/src/libs/libKernel.cpp @@ -11,6 +11,7 @@ #include "kernel/eventQueue.h" #include "kernel/fileSystem.h" #include "kernel/memory.h" +#include "kernel/module.h" #include "kernel/pthread.h" #include "kernel/semaphore.h" #include "kernel/syncOnAddress.h" @@ -65,7 +66,6 @@ LIB_DEFINE(InitLibKernel_1_Apr); namespace LibKernel { -using KernelModule = int32_t; using get_thread_atexit_count_func_t = KYTY_SYSV_ABI int (*)(KernelModule); using thread_atexit_report_func_t = KYTY_SYSV_ABI void (*)(KernelModule); @@ -1201,9 +1201,9 @@ static int KYTY_SYSV_ABI KernelRaiseException(Pthread thread, int signum) { return OK; } -static KYTY_SYSV_ABI KernelModule KernelLoadStartModule(const char* module_file_name, size_t args, - const void* argp, uint32_t flags, - const KernelLoadModuleOpt* opt, int* res) { +KernelModule KYTY_SYSV_ABI KernelLoadStartModule(const char* module_file_name, size_t args, + const void* argp, uint32_t flags, + const KernelLoadModuleOpt* opt, int* res) { PRINT_NAME(); // EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread()); @@ -1255,9 +1255,9 @@ static KYTY_SYSV_ABI KernelModule KernelLoadStartModule(const char* module_file_ return static_cast(handle); } -static int KYTY_SYSV_ABI KernelStopUnloadModule(KernelModule handle, size_t args, const void* argp, - uint32_t flags, const KernelUnloadModuleOpt* opt, - int* res) { +int KYTY_SYSV_ABI KernelStopUnloadModule(KernelModule handle, size_t args, const void* argp, + uint32_t flags, const KernelUnloadModuleOpt* opt, + int* res) { PRINT_NAME(); // EXIT_NOT_IMPLEMENTED(!Common::Thread::IsMainThread()); diff --git a/src/libs/libSysmodule.cpp b/src/libs/libSysmodule.cpp index e6589b6d8..a8c3609e4 100644 --- a/src/libs/libSysmodule.cpp +++ b/src/libs/libSysmodule.cpp @@ -3,6 +3,7 @@ #include "common/common.h" #include "common/logging/log.h" #include "common/stringUtils.h" +#include "kernel/module.h" #include "libs/libs.h" #include "loader/symbolDatabase.h" @@ -20,14 +21,40 @@ int KYTY_SYSV_ABI KernelGetModuleInfoForUnwind(uint64_t addr, int flags, ModuleI namespace Sysmodule { -constexpr int SYSMODULE_ERROR_UNLOADED = static_cast(0x805a1001u); +constexpr int SYSMODULE_ERROR_UNLOADED = static_cast(0x805a1001u); +constexpr int SYSMODULE_ERROR_FATAL = static_cast(0x805a10ffu); -static std::mutex g_module_mutex; -static std::unordered_map g_module_refs; +static constexpr struct NativeModule { + uint16_t id; + const char* path; +} g_native_modules[] = {{0x0115, "/app0/sce_module/libSceNpCppWebApi.prx"}}; -static void LoadModule(uint16_t id) { +struct Module { + uint32_t references = 0; + LibKernel::KernelModule handle = -1; +}; + +static std::mutex g_module_mutex; +static std::unordered_map g_modules; + +static int LoadModule(uint16_t id) { std::scoped_lock lock(g_module_mutex); - ++g_module_refs[id]; + if (const auto module = g_modules.find(id); module != g_modules.end()) { + ++module->second.references; + return 0; + } + + LibKernel::KernelModule handle = -1; + for (const auto& module: g_native_modules) { + if (module.id != id) continue; + handle = LibKernel::KernelLoadStartModule(module.path, 0, nullptr, 0, nullptr, nullptr); + if (handle < 0) { + return handle; + } + break; + } + g_modules.emplace(id, Module {1, handle}); + return 0; } static KYTY_SYSV_ABI int SysmoduleGetModuleInfoForUnwind(uint64_t addr, int flags, @@ -40,8 +67,7 @@ static KYTY_SYSV_ABI int SysmoduleLoadModule(uint16_t id) { LOGF("\t id = %d\n", static_cast(id)); - LoadModule(id); - return 0; + return LoadModule(id); } static KYTY_SYSV_ABI int SysmoduleUnloadModule(uint16_t id) { @@ -50,12 +76,19 @@ static KYTY_SYSV_ABI int SysmoduleUnloadModule(uint16_t id) { LOGF("\t id = %d\n", static_cast(id)); std::scoped_lock lock(g_module_mutex); - const auto module = g_module_refs.find(id); - if (module == g_module_refs.end()) { + const auto module = g_modules.find(id); + if (module == g_modules.end()) { return SYSMODULE_ERROR_UNLOADED; } - if (--module->second == 0) { - g_module_refs.erase(module); + if (module->second.references == 1) { + if (module->second.handle >= 0 && + LibKernel::KernelStopUnloadModule(module->second.handle, 0, nullptr, 0, nullptr, + nullptr) < 0) { + return SYSMODULE_ERROR_FATAL; + } + g_modules.erase(id); + } else { + --module->second.references; } return 0; } @@ -71,10 +104,8 @@ static KYTY_SYSV_ABI int SysmoduleLoadModuleInternalWithArg(uint16_t id, int arg EXIT_IF(arg3 != 0); EXIT_IF(ret == nullptr); - LoadModule(id); - *ret = 0; - - return 0; + *ret = LoadModule(id); + return *ret; } static KYTY_SYSV_ABI int SysmoduleIsLoaded(uint16_t id) { @@ -83,7 +114,7 @@ static KYTY_SYSV_ABI int SysmoduleIsLoaded(uint16_t id) { LOGF("\t id = %d\n", static_cast(id)); std::scoped_lock lock(g_module_mutex); - return g_module_refs.contains(id) ? 0 : SYSMODULE_ERROR_UNLOADED; + return g_modules.contains(id) ? 0 : SYSMODULE_ERROR_UNLOADED; } } // namespace Sysmodule diff --git a/tests/KernelFileSystemTests.cpp b/tests/KernelFileSystemTests.cpp index 4d0ee396c..67dd32ffa 100644 --- a/tests/KernelFileSystemTests.cpp +++ b/tests/KernelFileSystemTests.cpp @@ -235,6 +235,9 @@ void TestSysmoduleReferences() { const auto unload = resolve("eR2bZFAAU0Q"); const auto is_loaded = resolve("fMP5NHUOaMk"); constexpr int unloaded = static_cast(0x805a1001u); + Check(load(0x115) == Libs::LibKernel::KERNEL_ERROR_ENOENT && is_loaded(0x115) == unloaded && + unload(0x115) == unloaded, + "missing packaged NpCppWebApi fails without recording a loaded module"); Check(load(0x113) == OK && is_loaded(0xb4) == unloaded, "loading entitlement access does not mark AppContent loaded"); Check(unload(0x113) == OK, "release independent module reference"); @@ -255,6 +258,9 @@ void TestSysmoduleReferences() { reinterpret_cast( internal_symbol->vaddr); int result = -1; + Check(internal_load(0x115, 0, 0, 0, &result) == Libs::LibKernel::KERNEL_ERROR_ENOENT && + result == Libs::LibKernel::KERNEL_ERROR_ENOENT && is_loaded(0x115) == unloaded, + "internal module loading propagates missing native module failure"); Check(internal_load(0xb4, 0, 0, 0, &result) == OK && result == OK && is_loaded(0xb4) == OK && unload(0xb4) == OK && is_loaded(0xb4) == unloaded, "internal and public module operations share load state");