From 50d5ce9a8392bce170efca9bb7232c25bb4a8f0d Mon Sep 17 00:00:00 2001 From: georgemoralis Date: Sat, 7 Mar 2026 08:55:17 +0200 Subject: [PATCH 1/7] fixed an issue in sceKernelRemoveExceptionHandler (#4086) * fixed an issue in sceKernelRemoveExceptionHandler * fixed comment --- src/core/libraries/kernel/threads/exception.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/core/libraries/kernel/threads/exception.cpp b/src/core/libraries/kernel/threads/exception.cpp index cf36da0cc..247c387fe 100644 --- a/src/core/libraries/kernel/threads/exception.cpp +++ b/src/core/libraries/kernel/threads/exception.cpp @@ -276,7 +276,10 @@ int PS4_SYSV_ABI sceKernelRemoveExceptionHandler(s32 signum) { return ORBIS_KERNEL_ERROR_EINVAL; } int const native_signum = OrbisToNativeSignal(signum); - ASSERT_MSG(Handlers[native_signum], "Invalid parameters"); + if (!Handlers[native_signum]) { + LOG_WARNING(Lib_Kernel, "removing non-installed handler for signum {}", signum); + return ORBIS_KERNEL_ERROR_EINVAL; + } Handlers[native_signum] = nullptr; #ifndef _WIN64 if (native_signum == SIGSEGV || native_signum == SIGBUS || native_signum == SIGILL) { From 014b11e9da8765b281b331a1edff15d12c365d7f Mon Sep 17 00:00:00 2001 From: Stephen Miller <56742918+StevenMiller123@users.noreply.github.com> Date: Sat, 7 Mar 2026 01:15:32 -0600 Subject: [PATCH 2/7] Return an empty certificate (#4104) This is enough to get past initialization checks in Rise of the Tomb Raider. --- src/core/libraries/network/ssl2.cpp | 26 +++++++++++++------------ src/core/libraries/network/ssl2.h | 12 ++++++++++++ src/core/libraries/network/ssl2_error.h | 8 ++++++++ 3 files changed, 34 insertions(+), 12 deletions(-) create mode 100644 src/core/libraries/network/ssl2_error.h diff --git a/src/core/libraries/network/ssl2.cpp b/src/core/libraries/network/ssl2.cpp index 682095801..0b408d094 100644 --- a/src/core/libraries/network/ssl2.cpp +++ b/src/core/libraries/network/ssl2.cpp @@ -5,6 +5,7 @@ #include "core/libraries/error_codes.h" #include "core/libraries/libs.h" #include "core/libraries/network/ssl2.h" +#include "core/libraries/network/ssl2_error.h" namespace Libraries::Ssl2 { @@ -108,8 +109,13 @@ int PS4_SYSV_ABI sceSslEnableVerifyOption() { return ORBIS_OK; } -int PS4_SYSV_ABI sceSslFreeCaCerts() { - LOG_ERROR(Lib_Ssl2, "(STUBBED) called"); +int PS4_SYSV_ABI sceSslFreeCaCerts(s32 ssl_ctx_id, OrbisSslCaCerts* certs) { + LOG_ERROR(Lib_Ssl2, "(DUMMY) called"); + if (certs == nullptr) { + return ORBIS_SSL_ERROR_INVALID_ARGUMENT; + } + delete (certs->certs); + // delete (certs->pool); return ORBIS_OK; } @@ -128,17 +134,13 @@ int PS4_SYSV_ABI sceSslGetAlpnSelected() { return ORBIS_OK; } -struct OrbisSslCaCerts { - void* certs; - u64 num; - void* pool; -}; - -int PS4_SYSV_ABI sceSslGetCaCerts(int sslCtxId, OrbisSslCaCerts* certs) { - // check if it is same as libSceSsl +int PS4_SYSV_ABI sceSslGetCaCerts(s32 ssl_ctx_id, OrbisSslCaCerts* certs) { LOG_ERROR(Lib_Ssl2, "(DUMMY) called"); - certs->certs = nullptr; - certs->num = 0; + if (certs == nullptr) { + return ORBIS_SSL_ERROR_INVALID_ARGUMENT; + } + certs->certs = new OrbisSslData{nullptr, 0}; + certs->num = 1; certs->pool = nullptr; return ORBIS_OK; } diff --git a/src/core/libraries/network/ssl2.h b/src/core/libraries/network/ssl2.h index 754dda40c..18fb205d3 100644 --- a/src/core/libraries/network/ssl2.h +++ b/src/core/libraries/network/ssl2.h @@ -10,5 +10,17 @@ class SymbolsResolver; } namespace Libraries::Ssl2 { + +struct OrbisSslData { + char* ptr; + u64 size; +}; + +struct OrbisSslCaCerts { + OrbisSslData* certs; + u64 num; + void* pool; +}; + void RegisterLib(Core::Loader::SymbolsResolver* sym); } // namespace Libraries::Ssl2 \ No newline at end of file diff --git a/src/core/libraries/network/ssl2_error.h b/src/core/libraries/network/ssl2_error.h new file mode 100644 index 000000000..03bf94256 --- /dev/null +++ b/src/core/libraries/network/ssl2_error.h @@ -0,0 +1,8 @@ +// SPDX-FileCopyrightText: Copyright 2026 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/libraries/error_codes.h" + +constexpr int ORBIS_SSL_ERROR_INVALID_ARGUMENT = 0x8095F007; \ No newline at end of file From cc6af03adf6208974b0afcd7684358dd83fcfc8b Mon Sep 17 00:00:00 2001 From: Stephen Miller <56742918+StevenMiller123@users.noreply.github.com> Date: Sun, 8 Mar 2026 14:48:03 -0500 Subject: [PATCH 3/7] Lib.SysModule: Proper HLE implementation (#4102) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Replace sysmodule enums with table Dumped this from the 12.52 module, using a script I created. * Better documentation * Separate from system libraries That system folder is going to be getting quite large if I left all the sysmodule stuff in there. * More arrays from library * Found another preload list Ghidra really hates decompiling libSceSysmodule, so I didn't notice this one at first. Also documented specific versions tied to each preload list. * Start work on implementation * Some basic implementations * Initial stub for module loading Just enough to see if the logic functions appropriately. * Clang * sceSysmoduleLoadModule Now I need to get sceSysmodulePreloadModuleForLibkernel done so that we don't have bugs from not loading internal LLEs. * sceSysmoduleLoadModuleInternal * sceSysmodulePreloadModuleForLibkernel I have successfully broken quite literally everything. I shall debug this tomorrow. * Slight fix * Maybe fix? * Change log Enjoy the log spam 😄 * Increased defined stub count Now that libc and libSceLibcInternal loads later, all the auto stubs are getting consumed by it. * sceSysmoduleUnloadModule stub Also a couple fixes. Sysmodule does pass argc and argv to game modules, but only after loading them once to check binaries. Shouldn't matter for the most part. * Clang * Less stubs 2 thousand is seemingly enough. * sceSysmoduleLoadModuleInternalWithArg Doesn't hurt to have, since Apex Legends calls it. * Oops * Oops 2 * Rename isModuleLoaded to getModuleHandle Review comment * Remove debug game module loads These cases only trigger when specific sceRegMgr key values are set, and for our purposes, we can treat that case as false. * Allow preloading to fail For kalaposfos * Clang --- CMakeLists.txt | 9 +- src/common/elf_info.h | 3 + src/core/aerolib/stubs.cpp | 5 +- src/core/libraries/kernel/orbis_error.h | 2 + src/core/libraries/libs.cpp | 2 +- src/core/libraries/sysmodule/sysmodule.cpp | 204 ++++++ src/core/libraries/sysmodule/sysmodule.h | 38 + .../libraries/sysmodule/sysmodule_error.h | 10 + .../sysmodule/sysmodule_internal.cpp | 440 +++++++++++ .../libraries/sysmodule/sysmodule_internal.h | 20 + .../libraries/sysmodule/sysmodule_table.h | 684 ++++++++++++++++++ src/core/libraries/system/sysmodule.cpp | 169 ----- src/core/libraries/system/sysmodule.h | 194 ----- src/core/libraries/system/system_error.h | 8 - src/core/linker.cpp | 8 +- src/emulator.cpp | 67 -- 16 files changed, 1416 insertions(+), 447 deletions(-) create mode 100644 src/core/libraries/sysmodule/sysmodule.cpp create mode 100644 src/core/libraries/sysmodule/sysmodule.h create mode 100644 src/core/libraries/sysmodule/sysmodule_error.h create mode 100644 src/core/libraries/sysmodule/sysmodule_internal.cpp create mode 100644 src/core/libraries/sysmodule/sysmodule_internal.h create mode 100644 src/core/libraries/sysmodule/sysmodule_table.h delete mode 100644 src/core/libraries/system/sysmodule.cpp delete mode 100644 src/core/libraries/system/sysmodule.h delete mode 100644 src/core/libraries/system/system_error.h diff --git a/CMakeLists.txt b/CMakeLists.txt index b07dcea87..dd02a6378 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -414,9 +414,12 @@ set(SYSTEM_LIBS src/core/libraries/system/commondialog.cpp src/core/libraries/save_data/dialog/savedatadialog.h src/core/libraries/save_data/dialog/savedatadialog_ui.cpp src/core/libraries/save_data/dialog/savedatadialog_ui.h - src/core/libraries/system/sysmodule.cpp - src/core/libraries/system/sysmodule.h - src/core/libraries/system/system_error.h + src/core/libraries/sysmodule/sysmodule.cpp + src/core/libraries/sysmodule/sysmodule.h + src/core/libraries/sysmodule/sysmodule_internal.cpp + src/core/libraries/sysmodule/sysmodule_internal.h + src/core/libraries/sysmodule/sysmodule_error.h + src/core/libraries/sysmodule/sysmodule_table.h src/core/libraries/system/systemservice.cpp src/core/libraries/system/systemservice.h src/core/libraries/system/systemservice_error.h diff --git a/src/common/elf_info.h b/src/common/elf_info.h index 0f2311cb0..b84f36ecb 100644 --- a/src/common/elf_info.h +++ b/src/common/elf_info.h @@ -88,7 +88,10 @@ public: static constexpr u32 FW_50 = 0x5000000; static constexpr u32 FW_55 = 0x5500000; static constexpr u32 FW_60 = 0x6000000; + static constexpr u32 FW_70 = 0x7000000; + static constexpr u32 FW_75 = 0x7500000; static constexpr u32 FW_80 = 0x8000000; + static constexpr u32 FW_115 = 0x11500000; static ElfInfo& Instance() { return *Singleton::Instance(); diff --git a/src/core/aerolib/stubs.cpp b/src/core/aerolib/stubs.cpp index 2634fc46a..7023144d7 100644 --- a/src/core/aerolib/stubs.cpp +++ b/src/core/aerolib/stubs.cpp @@ -19,7 +19,7 @@ namespace Core::AeroLib { // and to longer compile / CI times // // Must match STUBS_LIST define -constexpr u32 MAX_STUBS = 1024; +constexpr u32 MAX_STUBS = 2048; u64 UnresolvedStub() { LOG_ERROR(Core, "Returning zero to {}", __builtin_return_address(0)); @@ -61,8 +61,9 @@ static u32 UsedStubEntries; #define XREP_256(x) XREP_128(x) XREP_128(x + 128) #define XREP_512(x) XREP_256(x) XREP_256(x + 256) #define XREP_1024(x) XREP_512(x) XREP_512(x + 512) +#define XREP_2048(x) XREP_1024(x) XREP_1024(x + 1024) -#define STUBS_LIST XREP_1024(0) +#define STUBS_LIST XREP_2048(0) static u64 (*stub_handlers[MAX_STUBS])() = {STUBS_LIST}; diff --git a/src/core/libraries/kernel/orbis_error.h b/src/core/libraries/kernel/orbis_error.h index d19b3f3f1..6ebff0ba3 100644 --- a/src/core/libraries/kernel/orbis_error.h +++ b/src/core/libraries/kernel/orbis_error.h @@ -106,3 +106,5 @@ constexpr int ORBIS_KERNEL_ERROR_ECAPMODE = 0x8002005E; constexpr int ORBIS_KERNEL_ERROR_ENOBLK = 0x8002005F; constexpr int ORBIS_KERNEL_ERROR_EICV = 0x80020060; constexpr int ORBIS_KERNEL_ERROR_ENOPLAYGOENT = 0x80020061; +constexpr int ORBIS_KERNEL_ERROR_ESDKVERSION = 0x80020063; +constexpr int ORBIS_KERNEL_ERROR_ESTART = 0x80020064; \ No newline at end of file diff --git a/src/core/libraries/libs.cpp b/src/core/libraries/libs.cpp index eebb991dc..ac35c4b63 100644 --- a/src/core/libraries/libs.cpp +++ b/src/core/libraries/libs.cpp @@ -57,10 +57,10 @@ #include "core/libraries/screenshot/screenshot.h" #include "core/libraries/share_play/shareplay.h" #include "core/libraries/signin_dialog/signindialog.h" +#include "core/libraries/sysmodule/sysmodule.h" #include "core/libraries/system/commondialog.h" #include "core/libraries/system/msgdialog.h" #include "core/libraries/system/posix.h" -#include "core/libraries/system/sysmodule.h" #include "core/libraries/system/systemservice.h" #include "core/libraries/system/userservice.h" #include "core/libraries/system_gesture/system_gesture.h" diff --git a/src/core/libraries/sysmodule/sysmodule.cpp b/src/core/libraries/sysmodule/sysmodule.cpp new file mode 100644 index 000000000..1ad9075e7 --- /dev/null +++ b/src/core/libraries/sysmodule/sysmodule.cpp @@ -0,0 +1,204 @@ +// SPDX-FileCopyrightText: Copyright 2025-2026 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include + +#include "common/elf_info.h" +#include "common/logging/log.h" +#include "core/libraries/error_codes.h" +#include "core/libraries/kernel/orbis_error.h" +#include "core/libraries/kernel/process.h" +#include "core/libraries/libs.h" +#include "core/libraries/sysmodule/sysmodule.h" +#include "core/libraries/sysmodule/sysmodule_error.h" +#include "core/libraries/sysmodule/sysmodule_internal.h" +#include "core/linker.h" + +namespace Libraries::SysModule { + +static std::mutex g_mutex{}; + +s32 PS4_SYSV_ABI sceSysmoduleGetModuleHandleInternal(OrbisSysModuleInternal id, s32* handle) { + LOG_INFO(Lib_SysModule, "called"); + if ((id & 0x7fffffff) == 0) { + return ORBIS_SYSMODULE_INVALID_ID; + } + + std::scoped_lock lk{g_mutex}; + return getModuleHandle(id, handle); +} + +s32 PS4_SYSV_ABI sceSysmoduleGetModuleInfoForUnwind(VAddr addr, s32 flags, + Kernel::OrbisModuleInfoForUnwind* info) { + LOG_TRACE(Lib_SysModule, "sceSysmoduleGetModuleInfoForUnwind called"); + s32 res = Kernel::sceKernelGetModuleInfoForUnwind(addr, flags, info); + if (res != ORBIS_OK) { + return res; + } + + if (shouldHideName(info->name.data())) { + std::ranges::fill(info->name, '\0'); + } + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceSysmoduleIsCalledFromSysModule() { + LOG_ERROR(Lib_SysModule, "(STUBBED) called"); + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceSysmoduleIsCameraPreloaded() { + LOG_ERROR(Lib_SysModule, "(STUBBED) called"); + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceSysmoduleIsLoaded(OrbisSysModule id) { + if (id == 0) { + return ORBIS_SYSMODULE_INVALID_ID; + } + + std::scoped_lock lk{g_mutex}; + return getModuleHandle(id, nullptr); +} + +s32 PS4_SYSV_ABI sceSysmoduleIsLoadedInternal(OrbisSysModuleInternal id) { + if ((id & 0x7fffffff) == 0) { + return ORBIS_SYSMODULE_INVALID_ID; + } + + std::scoped_lock lk{g_mutex}; + return getModuleHandle(id, nullptr); +} + +s32 PS4_SYSV_ABI sceSysmoduleLoadModule(OrbisSysModule id) { + LOG_INFO(Lib_SysModule, "called, id = {:#x}", id); + s32 result = validateModuleId(id); + if (result < ORBIS_OK) { + return result; + } + + // Only locks for internal loadModule call. + { + std::scoped_lock lk{g_mutex}; + result = loadModule(id, 0, nullptr, nullptr); + } + + if (result == ORBIS_KERNEL_ERROR_ESTART) { + s32 sdk_ver = 0; + result = Kernel::sceKernelGetCompiledSdkVersion(&sdk_ver); + if (sdk_ver < Common::ElfInfo::FW_115 || result != ORBIS_OK) { + return ORBIS_KERNEL_ERROR_EINVAL; + } else { + return ORBIS_KERNEL_ERROR_ESTART; + } + } + + // The real library has some weird workaround for CUSA01478 and CUSA01495 here. + // Unless this is proven necessary, I don't plan to handle this. + return result; +} + +s32 PS4_SYSV_ABI sceSysmoduleLoadModuleByNameInternal() { + LOG_ERROR(Lib_SysModule, "(STUBBED) called"); + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceSysmoduleLoadModuleInternal(OrbisSysModuleInternal id) { + LOG_INFO(Lib_SysModule, "called, id = {:#x}", id); + s32 result = validateModuleId(id); + if (result < ORBIS_OK) { + return result; + } + + // This specific module ID is loaded unlocked. + if (id == 0x80000039) { + return loadModule(id, 0, nullptr, nullptr); + } + std::scoped_lock lk{g_mutex}; + return loadModule(id, 0, nullptr, nullptr); +} + +s32 PS4_SYSV_ABI sceSysmoduleLoadModuleInternalWithArg(OrbisSysModuleInternal id, s32 argc, + const void* argv, u64 unk, s32* res_out) { + LOG_INFO(Lib_SysModule, "called, id = {:#x}", id); + s32 result = validateModuleId(id); + if (result < ORBIS_OK) { + return result; + } + + if (unk != 0) { + return ORBIS_SYSMODULE_INVALID_ID; + } + + std::scoped_lock lk{g_mutex}; + return loadModule(id, argc, argv, res_out); +} + +s32 PS4_SYSV_ABI sceSysmoduleMapLibcForLibkernel() { + LOG_ERROR(Lib_SysModule, "(STUBBED) called"); + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceSysmodulePreloadModuleForLibkernel() { + LOG_DEBUG(Lib_SysModule, "called"); + return preloadModulesForLibkernel(); +} + +s32 PS4_SYSV_ABI sceSysmoduleUnloadModule(OrbisSysModule id) { + LOG_ERROR(Lib_SysModule, "(STUBBED) called, id = {:#x}", id); + if (id == 0) { + return ORBIS_SYSMODULE_INVALID_ID; + } + + std::scoped_lock lk{g_mutex}; + return unloadModule(id, 0, nullptr, nullptr, false); +} + +s32 PS4_SYSV_ABI sceSysmoduleUnloadModuleByNameInternal() { + LOG_ERROR(Lib_SysModule, "(STUBBED) called"); + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceSysmoduleUnloadModuleInternal() { + LOG_ERROR(Lib_SysModule, "(STUBBED) called"); + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceSysmoduleUnloadModuleInternalWithArg() { + LOG_ERROR(Lib_SysModule, "(STUBBED) called"); + return ORBIS_OK; +} + +void RegisterLib(Core::Loader::SymbolsResolver* sym) { + LIB_FUNCTION("D8cuU4d72xM", "libSceSysmodule", 1, "libSceSysmodule", + sceSysmoduleGetModuleHandleInternal); + LIB_FUNCTION("4fU5yvOkVG4", "libSceSysmodule", 1, "libSceSysmodule", + sceSysmoduleGetModuleInfoForUnwind); + LIB_FUNCTION("ctfO7dQ7geg", "libSceSysmodule", 1, "libSceSysmodule", + sceSysmoduleIsCalledFromSysModule); + LIB_FUNCTION("no6T3EfiS3E", "libSceSysmodule", 1, "libSceSysmodule", + sceSysmoduleIsCameraPreloaded); + LIB_FUNCTION("fMP5NHUOaMk", "libSceSysmodule", 1, "libSceSysmodule", sceSysmoduleIsLoaded); + LIB_FUNCTION("ynFKQ5bfGks", "libSceSysmodule", 1, "libSceSysmodule", + sceSysmoduleIsLoadedInternal); + LIB_FUNCTION("g8cM39EUZ6o", "libSceSysmodule", 1, "libSceSysmodule", sceSysmoduleLoadModule); + LIB_FUNCTION("CU8m+Qs+HN4", "libSceSysmodule", 1, "libSceSysmodule", + sceSysmoduleLoadModuleByNameInternal); + LIB_FUNCTION("39iV5E1HoCk", "libSceSysmodule", 1, "libSceSysmodule", + sceSysmoduleLoadModuleInternal); + LIB_FUNCTION("hHrGoGoNf+s", "libSceSysmodule", 1, "libSceSysmodule", + sceSysmoduleLoadModuleInternalWithArg); + LIB_FUNCTION("lZ6RvVl0vo0", "libSceSysmodule", 1, "libSceSysmodule", + sceSysmoduleMapLibcForLibkernel); + LIB_FUNCTION("DOO+zuW1lrE", "libSceSysmodule", 1, "libSceSysmodule", + sceSysmodulePreloadModuleForLibkernel); + LIB_FUNCTION("eR2bZFAAU0Q", "libSceSysmodule", 1, "libSceSysmodule", sceSysmoduleUnloadModule); + LIB_FUNCTION("vpTHmA6Knvg", "libSceSysmodule", 1, "libSceSysmodule", + sceSysmoduleUnloadModuleByNameInternal); + LIB_FUNCTION("vXZhrtJxkGc", "libSceSysmodule", 1, "libSceSysmodule", + sceSysmoduleUnloadModuleInternal); + LIB_FUNCTION("aKa6YfBKZs4", "libSceSysmodule", 1, "libSceSysmodule", + sceSysmoduleUnloadModuleInternalWithArg); +}; + +} // namespace Libraries::SysModule diff --git a/src/core/libraries/sysmodule/sysmodule.h b/src/core/libraries/sysmodule/sysmodule.h new file mode 100644 index 000000000..17ac3188f --- /dev/null +++ b/src/core/libraries/sysmodule/sysmodule.h @@ -0,0 +1,38 @@ +// SPDX-FileCopyrightText: Copyright 2025-2026 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/types.h" +#include "core/libraries/kernel/process.h" + +namespace Core::Loader { +class SymbolsResolver; +} + +namespace Libraries::SysModule { + +using OrbisSysModule = u16; +using OrbisSysModuleInternal = u32; + +s32 PS4_SYSV_ABI sceSysmoduleGetModuleHandleInternal(OrbisSysModuleInternal id, s32* handle); +s32 PS4_SYSV_ABI sceSysmoduleGetModuleInfoForUnwind(VAddr addr, s32 flags, + Kernel::OrbisModuleInfoForUnwind* info); +s32 PS4_SYSV_ABI sceSysmoduleIsCalledFromSysModule(); +s32 PS4_SYSV_ABI sceSysmoduleIsCameraPreloaded(); +s32 PS4_SYSV_ABI sceSysmoduleIsLoaded(OrbisSysModule id); +s32 PS4_SYSV_ABI sceSysmoduleIsLoadedInternal(OrbisSysModuleInternal id); +s32 PS4_SYSV_ABI sceSysmoduleLoadModule(OrbisSysModule id); +s32 PS4_SYSV_ABI sceSysmoduleLoadModuleByNameInternal(); +s32 PS4_SYSV_ABI sceSysmoduleLoadModuleInternal(OrbisSysModuleInternal id); +s32 PS4_SYSV_ABI sceSysmoduleLoadModuleInternalWithArg(OrbisSysModuleInternal id, s32 argc, + const void* argv, u64 unk, s32* res_out); +s32 PS4_SYSV_ABI sceSysmoduleMapLibcForLibkernel(); +s32 PS4_SYSV_ABI sceSysmodulePreloadModuleForLibkernel(); +s32 PS4_SYSV_ABI sceSysmoduleUnloadModule(OrbisSysModule id); +s32 PS4_SYSV_ABI sceSysmoduleUnloadModuleByNameInternal(); +s32 PS4_SYSV_ABI sceSysmoduleUnloadModuleInternal(); +s32 PS4_SYSV_ABI sceSysmoduleUnloadModuleInternalWithArg(); + +void RegisterLib(Core::Loader::SymbolsResolver* sym); +} // namespace Libraries::SysModule diff --git a/src/core/libraries/sysmodule/sysmodule_error.h b/src/core/libraries/sysmodule/sysmodule_error.h new file mode 100644 index 000000000..aee14b9df --- /dev/null +++ b/src/core/libraries/sysmodule/sysmodule_error.h @@ -0,0 +1,10 @@ +// SPDX-FileCopyrightText: Copyright 2024-2026 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/types.h" + +constexpr s32 ORBIS_SYSMODULE_INVALID_ID = 0x805A1000; +constexpr s32 ORBIS_SYSMODULE_NOT_LOADED = 0x805A1001; +constexpr s32 ORBIS_SYSMODULE_LOCK_FAILED = 0x805A10FF; \ No newline at end of file diff --git a/src/core/libraries/sysmodule/sysmodule_internal.cpp b/src/core/libraries/sysmodule/sysmodule_internal.cpp new file mode 100644 index 000000000..55acded94 --- /dev/null +++ b/src/core/libraries/sysmodule/sysmodule_internal.cpp @@ -0,0 +1,440 @@ +// SPDX-FileCopyrightText: Copyright 2026 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/assert.h" +#include "common/config.h" +#include "common/elf_info.h" +#include "common/logging/log.h" +#include "core/file_sys/fs.h" +#include "core/libraries/disc_map/disc_map.h" +#include "core/libraries/font/font.h" +#include "core/libraries/font/fontft.h" +#include "core/libraries/jpeg/jpegenc.h" +#include "core/libraries/kernel/kernel.h" +#include "core/libraries/kernel/orbis_error.h" +#include "core/libraries/libc_internal/libc_internal.h" +#include "core/libraries/libpng/pngenc.h" +#include "core/libraries/libs.h" +#include "core/libraries/ngs2/ngs2.h" +#include "core/libraries/rtc/rtc.h" +#include "core/libraries/sysmodule/sysmodule_error.h" +#include "core/libraries/sysmodule/sysmodule_internal.h" +#include "core/libraries/sysmodule/sysmodule_table.h" +#include "core/linker.h" +#include "emulator.h" + +namespace Libraries::SysModule { + +s32 getModuleHandle(s32 id, s32* handle) { + if (id == 0) { + return ORBIS_SYSMODULE_INVALID_ID; + } + for (OrbisSysmoduleModuleInternal mod : g_modules_array) { + if (mod.id != id) { + continue; + } + if (mod.is_loaded < 1) { + return ORBIS_SYSMODULE_NOT_LOADED; + } + if (handle != nullptr) { + *handle = mod.handle; + } + return ORBIS_OK; + } + return ORBIS_SYSMODULE_INVALID_ID; +} + +bool shouldHideName(const char* module_name) { + for (u64 i = 0; i < g_num_modules; i++) { + OrbisSysmoduleModuleInternal mod = g_modules_array[i]; + if ((mod.flags & OrbisSysmoduleModuleInternalFlags::IsGame) == 0) { + continue; + } + u64 name_length = std::strlen(mod.name); + char name_copy[0x100]; + std::strncpy(name_copy, mod.name, sizeof(name_copy)); + // Module table stores names without extensions, so check with .prx appended to the name. + std::strncpy(&name_copy[name_length], ".prx", 4); + s32 result = std::strncmp(module_name, name_copy, sizeof(name_copy)); + if (result == 0) { + return true; + } + + // libSceFios2 and libc are checked as both sprx or prx modules. + if (i == 3) { + result = std::strncmp(module_name, "libSceFios2.sprx", sizeof(name_copy)); + } else if (i == 4) { + result = std::strncmp(module_name, "libc.sprx", sizeof(name_copy)); + } + + if (result == 0) { + return true; + } + } + return false; +} + +bool isDebugModule(s32 id) { + for (OrbisSysmoduleModuleInternal mod : g_modules_array) { + if (mod.id == id && (mod.flags & OrbisSysmoduleModuleInternalFlags::IsDebug) != 0) { + return true; + } + } + return false; +} + +bool validateModuleId(s32 id) { + if ((id & 0x7fffffff) == 0) { + return ORBIS_SYSMODULE_INVALID_ID; + } + + s32 sdk_ver = 0; + ASSERT_MSG(!Kernel::sceKernelGetCompiledSdkVersion(&sdk_ver), + "Failed to retrieve compiled SDK version"); + + // libSceGameCustomDialog isn't loadable on SDK >= 7.50 + if (id == 0xb8 && sdk_ver >= Common::ElfInfo::FW_75) { + return ORBIS_SYSMODULE_INVALID_ID; + } + + // libSceNpSnsFacebookDialog isn't loadable on SDK >= 7.00 + if (id == 0xb0 && sdk_ver >= Common::ElfInfo::FW_70) { + return ORBIS_SYSMODULE_INVALID_ID; + } + + // libSceJson isn't loadable on SDK >= 3.00 + if (id == 0x80 && sdk_ver >= Common::ElfInfo::FW_30) { + return ORBIS_SYSMODULE_INVALID_ID; + } + + // Cannot load debug modules on retail hardware. + if (isDebugModule(id) && !Config::isDevKitConsole()) { + return ORBIS_SYSMODULE_INVALID_ID; + } + + return ORBIS_OK; +} + +s32 loadModuleInternal(s32 index, s32 argc, const void* argv, s32* res_out) { + auto* mnt = Common::Singleton::Instance(); + auto* linker = Common::Singleton::Instance(); + auto* game_info = Common::Singleton::Instance(); + + // If the module is already loaded, increment is_loaded and return ORBIS_OK. + OrbisSysmoduleModuleInternal& mod = g_modules_array[index]; + if (mod.is_loaded > 0) { + mod.is_loaded++; + return ORBIS_OK; + } + + s32 start_result = 0; + // Most of the logic the actual module has here is to get the correct location of this module. + // Since we only care about a small subset of LLEs, we can simplify this logic. + if ((mod.flags & OrbisSysmoduleModuleInternalFlags::IsGame) != 0) { + std::string guest_path = std::string("/app0/sce_module/").append(mod.name); + guest_path.append(".prx"); + const auto& host_path = mnt->GetHostPath(guest_path); + + // For convenience, load through linker directly instead of loading through libkernel calls. + s32 result = linker->LoadAndStartModule(host_path, argc, argv, &start_result); + // If the module is missing, the library prints a very helpful message for developers. + // We'll just log an error. + if (result < 0) { + LOG_ERROR(Lib_SysModule, "Failed to load game library {}", guest_path); + return result; + } else { + // On success, the library validates module params and the module SDK version. + // We don't store the information this uses, so skip the proper checks. + mod.handle = result; + mod.is_loaded++; + } + } else { + // This is not a game library. We'll need to perform some checks, + // but we don't need to perform the path resolution logic the actual library has. + std::string mod_name = std::string(mod.name); + + // libSceGnmDriver case + if (index == 0xd && Config::isDevKitConsole()) { + // There are some other checks involved here that I am not familiar with. + // Since we're not exactly running libSceGnmDriver LLE, this shouldn't matter too much. + mod_name.append("_padebug"); + } + + // libSceSsl2 case + if (index == 0x27 && false /*needs legacy ssl*/) { + // Replaces module name with libSceSsl (index 0x15) + mod_name.clear(); + mod_name.append(g_modules_array[0x15].name); + } + + // libSceVrTracker case + if (index == 0xb3 && Config::isDevKitConsole()) { + mod_name.append("_debug"); + } + + if ((mod.flags & OrbisSysmoduleModuleInternalFlags::IsNeo) == 0 && + (mod.flags & OrbisSysmoduleModuleInternalFlags::IsNeoMode) != 0 && + Kernel::sceKernelIsNeoMode() == 1) { + // PS4 Pro running in enhanced mode + mod_name.append("ForNeoMode"); + } else if ((mod.flags & OrbisSysmoduleModuleInternalFlags::IsNeo) != 0 && + Config::isNeoModeConsole()) { + // PS4 Pro running in base mode + mod_name.append("ForNeo"); + } + + // Append .sprx extension. + mod_name.append(".sprx"); + + // Now we need to check if the requested library is allowed to LLE. + // First, we allow all modules from game-specific sys_modules + const auto& sys_module_path = Config::getSysModulesPath(); + const auto& game_specific_module_path = + sys_module_path / game_info->GameSerial() / mod_name; + if (std::filesystem::exists(game_specific_module_path)) { + // The requested module is present in the game-specific sys_modules, load it. + LOG_INFO(Loader, "Loading {} from game serial file {}", mod_name, + game_info->GameSerial()); + s32 handle = + linker->LoadAndStartModule(game_specific_module_path, argc, argv, &start_result); + ASSERT_MSG(handle >= 0, "Failed to load module {}", mod_name); + mod.handle = handle; + mod.is_loaded++; + if (res_out != nullptr) { + *res_out = start_result; + } + return ORBIS_OK; + } + + // We need to check a few things here. + // First, check if this is a module we allow LLE for. + static s32 stub_handle = 100; + constexpr auto ModulesToLoad = std::to_array( + {{"libSceNgs2.sprx", &Libraries::Ngs2::RegisterLib}, + {"libSceUlt.sprx", nullptr}, + {"libSceRtc.sprx", &Libraries::Rtc::RegisterLib}, + {"libSceJpegDec.sprx", nullptr}, + {"libSceJpegEnc.sprx", &Libraries::JpegEnc::RegisterLib}, + {"libScePngEnc.sprx", &Libraries::PngEnc::RegisterLib}, + {"libSceJson.sprx", nullptr}, + {"libSceJson2.sprx", nullptr}, + {"libSceLibcInternal.sprx", &Libraries::LibcInternal::RegisterLib}, + {"libSceCesCs.sprx", nullptr}, + {"libSceAudiodec.sprx", nullptr}, + {"libSceFont.sprx", &Libraries::Font::RegisterlibSceFont}, + {"libSceFontFt.sprx", &Libraries::FontFt::RegisterlibSceFontFt}, + {"libSceFreeTypeOt.sprx", nullptr}}); + + // Iterate through the allowed array + const auto it = std::ranges::find_if( + ModulesToLoad, [&](Core::SysModules module) { return mod_name == module.module_name; }); + if (it == ModulesToLoad.end()) { + // Not an allowed LLE, stub success without warning. + mod.is_loaded++; + // Some internal checks rely on a handle, stub a valid one. + mod.handle = stub_handle++; + if (res_out != nullptr) { + *res_out = ORBIS_OK; + } + return ORBIS_OK; + } + + // Allowed module, check if it exists + const auto& module_path = sys_module_path / mod_name; + if (std::filesystem::exists(module_path)) { + LOG_INFO(Loader, "Loading {}", mod_name); + s32 handle = linker->LoadAndStartModule(module_path, argc, argv, &start_result); + ASSERT_MSG(handle >= 0, "Failed to load module {}", mod_name); + mod.handle = handle; + } else { + // Allowed LLE that isn't present, log message + auto& [name, init_func] = *it; + if (init_func) { + LOG_INFO(Loader, "Can't Load {} switching to HLE", mod_name); + init_func(&linker->GetHLESymbols()); + } else { + LOG_INFO(Loader, "No HLE available for {} module", mod_name); + } + mod.handle = stub_handle++; + } + + // Mark module as loaded. + mod.is_loaded++; + } + + // Only successful loads will reach here + if (res_out != nullptr) { + *res_out = start_result; + } + + return ORBIS_OK; +} + +s32 loadModule(s32 id, s32 argc, const void* argv, s32* res_out) { + // Retrieve the module to load from the table + OrbisSysmoduleModuleInternal requested_module{}; + for (OrbisSysmoduleModuleInternal mod : g_modules_array) { + if (mod.id == id) { + requested_module = mod; + break; + } + } + if (requested_module.id != id || requested_module.id == 0) { + return ORBIS_SYSMODULE_INVALID_ID; + } + + // Every module has a pointer to an array of indexes to modules that need loading. + if (requested_module.to_load == nullptr) { + // Seems like ORBIS_SYSMODULE_LOCK_FAILED is a generic internal error. + return ORBIS_SYSMODULE_LOCK_FAILED; + } + + LOG_INFO(Lib_SysModule, "Loading {}", requested_module.name); + + // Loop through every module that requires loading, in reverse order + for (s64 i = requested_module.num_to_load - 1; i >= 0; i--) { + // Modules flagged as debug modules only load for devkits + u32 mod_index = requested_module.to_load[i]; + if ((!Config::isDevKitConsole() && + g_modules_array[mod_index].flags & OrbisSysmoduleModuleInternalFlags::IsDebug) != 0) { + continue; + } + + // Arguments and result should only be applied to the requested module + // Dependencies don't receive these values. + s32 result = 0; + if (i != 0) { + result = loadModuleInternal(mod_index, 0, nullptr, nullptr); + } else { + result = loadModuleInternal(mod_index, argc, argv, res_out); + } + + // If loading any module fails, abort there. + if (result != ORBIS_OK) { + return result; + } + } + return ORBIS_OK; +} + +s32 unloadModule(s32 id, s32 argc, const void* argv, s32* res_out, bool is_internal) { + OrbisSysmoduleModuleInternal mod{}; + for (s32 i = 0; i < g_modules_array.size(); i++) { + mod = g_modules_array[i]; + if (mod.id != id) { + continue; + } + + // Skips checking libSceDiscMap + if (i == 0x22) { + continue; + } + + // If the module is loaded once, and is part of the second preload list, + // then return OK and do nothing. + for (s32 index : g_preload_list_2) { + if (index == i && mod.is_loaded == 1) { + return ORBIS_OK; + } + } + + // Found the correct module. + break; + } + + // If we failed to locate the module, return invalid id. + if (mod.id != id || mod.id == 0) { + return ORBIS_SYSMODULE_INVALID_ID; + } + + // If the module has no dependencies, then return an internal error. + if (mod.num_to_load == 0 || mod.to_load == nullptr) { + return ORBIS_SYSMODULE_LOCK_FAILED; + } + + // Unload the module and it's dependencies + for (s64 i = 0; i < mod.num_to_load; i++) { + OrbisSysmoduleModuleInternal dep_mod = g_modules_array[mod.to_load[i]]; + // If this is a debug module and we're not emulating a devkit, skip it. + if ((dep_mod.flags & OrbisSysmoduleModuleInternalFlags::IsDebug) != 0 && + !Config::isDevKitConsole()) { + continue; + } + + // If the module to unload is marked as unloaded, then return not loaded + if (dep_mod.is_loaded == 0) { + return ORBIS_SYSMODULE_NOT_LOADED; + } + + // By this point, all necessary checks are performed, decrement the load count. + dep_mod.is_loaded--; + + // Normally, this is where the real library would actually unload the module, + // through a call to sceKernelStopUnloadModule. + // As we don't implement module unloading, this behavior is skipped. + + // Stub success during requested module unload. + if (i == 0 && res_out != nullptr) { + *res_out = ORBIS_OK; + } + } + return ORBIS_OK; +} + +s32 preloadModulesForLibkernel() { + // For now, default to loading g_preload_list_3. + // As far as I can tell, g_preload_list_1 seems to be some sort of list with libs + // that games don't typically use, and g_preload_list_2 is just a reorganized version of 3. + s32 sdk_ver = 0; + ASSERT_MSG(Kernel::sceKernelGetCompiledSdkVersion(&sdk_ver) == 0, + "Failed to get compiled SDK version"); + for (u32 module_index : g_preload_list_3) { + // As per usual, these are arrays of indexes for g_modules_array + // libSceDbg, libScePerf, libSceMat, and libSceRazorCpu_debug. + // These are skipped unless this console is a devkit. + if ((module_index == 0x12 || module_index == 0x1e || module_index == 0x24 || + module_index == 0x26) && + !Config::isDevKitConsole()) { + continue; + } + + // libSceDiscMap case, skipped on newer SDK versions. + if (module_index == 0x22 && sdk_ver >= Common::ElfInfo::FW_20) { + continue; + } + + // libSceDbgAssist is skipped on non-testkit consoles. + // For now, stub check to non-devkit. + if (module_index == 0x23 && !Config::isDevKitConsole()) { + continue; + } + + // libSceRazorCpu, skipped for old non-devkit consoles. + if (module_index == 0x25 && sdk_ver < Common::ElfInfo::FW_45 && + !Config::isDevKitConsole()) { + continue; + } + + // libSceHttp2, skipped for SDK versions below 7.00. + if (module_index == 0x28 && sdk_ver < Common::ElfInfo::FW_70) { + continue; + } + + // libSceNpWebApi2 and libSceNpGameIntent, skipped for SDK versions below 7.50 + if ((module_index == 0x29 || module_index == 0x2a) && sdk_ver < Common::ElfInfo::FW_75) { + continue; + } + + // Load the actual module + s32 result = loadModuleInternal(module_index, 0, nullptr, nullptr); + if (result != ORBIS_OK) { + // On real hardware, module preloading must succeed or the game will abort. + // To enable users to test homebrew easier, we'll log a critical error instead. + LOG_CRITICAL(Lib_SysModule, "Failed to preload {}, expect crashes", + g_modules_array[module_index].name); + } + } + return ORBIS_OK; +} + +} // namespace Libraries::SysModule diff --git a/src/core/libraries/sysmodule/sysmodule_internal.h b/src/core/libraries/sysmodule/sysmodule_internal.h new file mode 100644 index 000000000..8f88f85ea --- /dev/null +++ b/src/core/libraries/sysmodule/sysmodule_internal.h @@ -0,0 +1,20 @@ +// SPDX-FileCopyrightText: Copyright 2026 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/types.h" +#include "core/libraries/kernel/process.h" + +namespace Libraries::SysModule { + +s32 getModuleHandle(s32 id, s32* handle); +bool shouldHideName(const char* module_name); +bool isDebugModule(s32 id); +bool validateModuleId(s32 id); +s32 loadModuleInternal(s32 index, s32 argc, const void* argv, s32* res_out); +s32 loadModule(s32 id, s32 argc, const void* argv, s32* res_out); +s32 unloadModule(s32 id, s32 argc, const void* argv, s32* res_out, bool is_internal); +s32 preloadModulesForLibkernel(); + +} // namespace Libraries::SysModule \ No newline at end of file diff --git a/src/core/libraries/sysmodule/sysmodule_table.h b/src/core/libraries/sysmodule/sysmodule_table.h new file mode 100644 index 000000000..bd27a8aae --- /dev/null +++ b/src/core/libraries/sysmodule/sysmodule_table.h @@ -0,0 +1,684 @@ +// SPDX-FileCopyrightText: Copyright 2026 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/types.h" + +namespace Libraries::SysModule { + +/** + * libSceSysmodule hardcodes an array of valuable data about loading each PS4 module. + * This header stores the contents of this array, as dumped from 12.52's libSceSysmodule, + * and altered to fit within my simplified internal module struct. + */ + +// This is an internal struct. Doesn't match the real one exactly. +struct OrbisSysmoduleModuleInternal { + u32 id; // User requested ID + s32 handle; // Handle of the module, once loaded + s32 is_loaded; // 0 by default, set to 1 once loaded. + s32 flags; // Miscellaneous details about the module + const char* name; // Name of the actual SPRX/PRX library + const u16* to_load; // Pointer to an array of modules to load + s32 num_to_load; // Number of indicies in the array of modules +}; + +// This enum contains helpful identifiers for some bits used in the flags of a module. +enum OrbisSysmoduleModuleInternalFlags : s32 { + IsCommon = 1, // Module is located in /system/common/lib + IsPriv = 2, // Module is located in /system/priv/lib + IsGame = 4, // Module is located in /app0/sce_module + IsDebug = 8, // Module should only be loaded on devkit/testkit consoles + IsNeo = 0x200, // Module should only be loaded on PS4 Pro consoles + IsNeoMode = 0x400, // Module should only be loaded for PS4 Pro running in enhanced mode + IsCommonEx = 0x1000, // Module is located in /system_ex/common_ex/lib + IsPrivEx = 0x2000, // Module is located in /system_ex/priv_ex/lib +}; + +// Array of module indexes to load in sceSysmodulePreloadModuleForLibkernel. +// The library has three versions of this array +u32 g_preload_list_1[36] = {0x24, 3, 4, 5, 6, 7, 8, 9, 0x25, 0xb, 0xc, 0xd, + 0xe, 0xf, 0x10, 0x11, 0x1f, 0x12, 0x13, 0x14, 0x27, 0x28, 0x16, 0x17, + 0x2a, 0x18, 0x29, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x26, 0x1e, 0x20, 0x21}; +u32 g_preload_list_2[38] = {1, 2, 0x24, 0x22, 3, 4, 5, 6, 7, 8, + 9, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x1f, 0x12, + 0x23, 0x13, 0x14, 0x27, 0x28, 0x16, 0x17, 0x2a, 0x18, 0x29, + 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x25, 0x26, 0x1e}; +u32 g_preload_list_3[38] = {1, 2, 0x24, 0x22, 3, 4, 5, 6, 7, 8, + 9, 0x25, 0xb, 0xc, 0xd, 0xe, 0xf, 0x10, 0x11, 0x1f, + 0x12, 0x23, 0x13, 0x14, 0x27, 0x28, 0x16, 0x17, 0x2a, 0x18, + 0x29, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x26, 0x1e}; + +// Arrays of modules to load for each module. +// The stored values are valid indices to modules in g_modules_array. +u16 g_libSceNet_modules[1] = {5}; +u16 g_libSceIpmi_modules[1] = {6}; +u16 g_libSceMbus_modules[2] = {7, 6}; +u16 g_libSceRegMgr_modules[1] = {8}; +u16 g_libSceRtc_modules[1] = {9}; +u16 g_libSceAvSetting_modules[3] = {11, 7, 6}; +u16 g_libSceVideoOut_modules[3] = {12, 11, 7}; +u16 g_libSceGnmDriver_modules[4] = {13, 12, 8, 37}; +u16 g_libSceAudioOut_modules[4] = {14, 11, 7, 6}; +u16 g_libSceAudioIn_modules[4] = {15, 14, 7, 6}; +u16 g_libSceAjm_modules[1] = {16}; +u16 g_libScePad_modules[2] = {17, 7}; +u16 g_libSceDbg_debug_modules[1] = {18}; +u16 g_libSceNetCtl_modules[2] = {19, 6}; +u16 g_libSceHttp_modules[5] = {20, 39, 9, 19, 5}; +u16 g_libSceSsl_modules[3] = {21, 9, 5}; +u16 g_libSceNpCommon_modules[8] = {22, 20, 39, 19, 9, 8, 6, 5}; +u16 g_libSceNpManager_modules[7] = {23, 22, 20, 39, 19, 9, 5}; +u16 g_libSceNpWebApi_modules[7] = {24, 23, 22, 20, 39, 9, 5}; +u16 g_libSceSaveData_modules[4] = {25, 27, 9, 6}; +u16 g_libSceSystemService_modules[3] = {26, 8, 6}; +u16 g_libSceUserService_modules[2] = {27, 6}; +u16 g_libSceCommonDialog_modules[1] = {28}; +u16 g_libSceSysUtil_modules[2] = {29, 8}; +u16 g_libScePerf_debug_modules[3] = {30, 38, 37}; +u16 g_libSceCamera_modules[2] = {31, 7}; +u16 g_libSceDiscMap_modules[1] = {34}; +u16 g_libSceDbgAssist_modules[1] = {35}; +u16 g_libSceMat_debug_modules[1] = {36}; +u16 g_libSceRazorCpu_modules[1] = {37}; +u16 g_libSceRazorCpu_debug_debug_modules[2] = {38, 37}; +u16 g_libSceSsl2_modules[3] = {39, 9, 5}; +u16 g_libSceHttp2_modules[13] = {40, 20, 39, 9, 19, 5, 39, 9, 5, 9, 19, 6, 5}; +u16 g_libSceNpWebApi2_modules[39] = {41, 23, 22, 20, 39, 19, 9, 5, 22, 20, 39, 19, 9, + 8, 6, 5, 40, 20, 39, 9, 19, 5, 39, 9, 5, 9, + 19, 6, 5, 20, 39, 9, 19, 5, 39, 9, 5, 9, 5}; +u16 g_libSceNpGameIntent_modules[10] = {42, 22, 20, 39, 19, 9, 8, 6, 5, 6}; +u16 g_libSceFiber_modules[5] = {49, 114, 30, 38, 37}; +u16 g_libSceUlt_modules[6] = {50, 49, 114, 30, 38, 37}; +u16 g_libSceNgs2_modules[2] = {51, 16}; +u16 g_libSceXml_modules[1] = {52}; +u16 g_libSceNpUtility_modules[5] = {53, 22, 20, 19, 5}; +u16 g_libSceVoice_modules[4] = {54, 16, 15, 14}; +u16 g_libSceNpMatching2_modules[7] = {55, 23, 22, 20, 39, 19, 5}; +u16 g_libSceNpScoreRanking_modules[3] = {56, 23, 22}; +u16 g_libSceRudp_modules[1] = {57}; +u16 g_libSceNpTus_modules[3] = {58, 23, 22}; +u16 g_libSceFace_modules[1] = {59}; +u16 g_libSceSmart_modules[1] = {60}; +u16 g_libSceJson_modules[1] = {61}; +u16 g_libSceGameLiveStreaming_modules[2] = {62, 6}; +u16 g_libSceCompanionUtil_modules[3] = {63, 7, 6}; +u16 g_libScePlayGo_modules[1] = {64}; +u16 g_libSceFont_modules[1] = {65}; +u16 g_libSceVideoRecording_modules[2] = {66, 82}; +u16 g_libSceAudiodec_modules[2] = {67, 16}; +u16 g_libSceJpegDec_modules[1] = {68}; +u16 g_libSceJpegEnc_modules[1] = {69}; +u16 g_libScePngDec_modules[1] = {70}; +u16 g_libScePngEnc_modules[1] = {71}; +u16 g_libSceVideodec_modules[3] = {72, 80, 161}; +u16 g_libSceMove_modules[1] = {73}; +u16 g_libScePadTracker_modules[2] = {75, 17}; +u16 g_libSceDepth_modules[2] = {76, 31}; +u16 g_libSceHand_modules[1] = {77}; +u16 g_libSceIme_modules[2] = {78, 6}; +u16 g_libSceImeDialog_modules[2] = {79, 6}; +u16 g_libSceVdecCore_modules[1] = {80}; +u16 g_libSceNpParty_modules[2] = {81, 6}; +u16 g_libSceAvcap_modules[2] = {82, 6}; +u16 g_libSceFontFt_modules[1] = {83}; +u16 g_libSceFreeTypeOt_modules[1] = {84}; +u16 g_libSceFreeTypeOl_modules[1] = {85}; +u16 g_libSceFreeTypeOptOl_modules[1] = {86}; +u16 g_libSceScreenShot_modules[3] = {87, 29, 6}; +u16 g_libSceNpAuth_modules[3] = {88, 22, 23}; +u16 g_libSceVoiceQos_modules[5] = {89, 54, 16, 15, 14}; +u16 g_libSceSysCore_modules[2] = {90, 6}; +u16 g_libSceM4aacEnc_modules[2] = {91, 16}; +u16 g_libSceAudiodecCpu_modules[1] = {92}; +u16 g_libSceCdlgUtilServer_modules[2] = {93, 26}; +u16 g_libSceSulpha_debug_modules[1] = {94}; +u16 g_libSceSaveDataDialog_modules[4] = {95, 9, 28, 26}; +u16 g_libSceInvitationDialog_modules[1] = {96}; +u16 g_libSceKeyboard_debug_modules[1] = {97}; +u16 g_libSceKeyboard_modules[1] = {98}; +u16 g_libSceMsgDialog_modules[1] = {99}; +u16 g_libSceAvPlayer_modules[1] = {100}; +u16 g_libSceContentExport_modules[1] = {101}; +u16 g_libSceVisionManager_modules[1] = {102}; +u16 g_libSceAc3Enc_modules[2] = {103, 16}; +u16 g_libSceAppInstUtil_modules[1] = {104}; +u16 g_libSceVencCore_modules[1] = {105}; +u16 g_libSceAudio3d_modules[1] = {106}; +u16 g_libSceNpCommerce_modules[1] = {107}; +u16 g_libSceHidControl_modules[1] = {108}; +u16 g_libSceMouse_modules[1] = {109}; +u16 g_libSceCompanionHttpd_modules[1] = {110}; +u16 g_libSceWebBrowserDialog_modules[1] = {111}; +u16 g_libSceErrorDialog_modules[1] = {112}; +u16 g_libSceNpTrophy_modules[1] = {113}; +u16 g_ulobjmgr_modules[1] = {114}; +u16 g_libSceVideoCoreInterface_modules[1] = {115}; +u16 g_libSceVideoCoreServerInterface_modules[1] = {116}; +u16 g_libSceNpSns_modules[1] = {117}; +u16 g_libSceNpSnsFacebookDialog_modules[2] = {118, 117}; +u16 g_libSceMoveTracker_modules[1] = {119}; +u16 g_libSceNpProfileDialog_modules[1] = {120}; +u16 g_libSceNpFriendListDialog_modules[1] = {121}; +u16 g_libSceAppContent_modules[1] = {122}; +u16 g_libSceMarlin_modules[1] = {123}; +u16 g_libSceDtsEnc_modules[2] = {124, 16}; +u16 g_libSceNpSignaling_modules[1] = {125}; +u16 g_libSceRemoteplay_modules[1] = {126}; +u16 g_libSceUsbd_modules[1] = {127}; +u16 g_libSceGameCustomDataDialog_modules[1] = {128}; +u16 g_libSceNpEulaDialog_modules[1] = {129}; +u16 g_libSceRandom_modules[1] = {130}; +u16 g_libSceDipsw_modules[1] = {131}; +u16 g_libSceS3DConversion_modules[1] = {132}; +u16 g_libSceOttvCapture_debug_modules[1] = {133}; +u16 g_libSceBgft_modules[1] = {134}; +u16 g_libSceAudiodecCpuDdp_modules[1] = {135}; +u16 g_libSceAudiodecCpuM4aac_modules[1] = {136}; +u16 g_libSceAudiodecCpuDts_modules[1] = {137}; +u16 g_libSceAudiodecCpuDtsHdLbr_modules[1] = {138}; +u16 g_libSceAudiodecCpuDtsHdMa_modules[1] = {139}; +u16 g_libSceAudiodecCpuLpcm_modules[1] = {140}; +u16 g_libSceBemp2sys_modules[1] = {141}; +u16 g_libSceBeisobmf_modules[1] = {142}; +u16 g_libScePlayReady_modules[1] = {143}; +u16 g_libSceVideoNativeExtEssential_modules[1] = {144}; +u16 g_libSceZlib_modules[1] = {145}; +u16 g_libSceIduUtil_modules[1] = {146}; +u16 g_libScePsm_modules[1] = {147}; +u16 g_libSceDtcpIp_modules[1] = {148}; +u16 g_libSceKbEmulate_modules[1] = {149}; +u16 g_libSceAppChecker_modules[1] = {150}; +u16 g_libSceNpGriefReport_modules[1] = {151}; +u16 g_libSceContentSearch_modules[1] = {152}; +u16 g_libSceShareUtility_modules[1] = {153}; +u16 g_libSceWeb_modules[6] = {154, 155, 147, 192, 27, 6}; +u16 g_libSceWebKit2_modules[30] = {155, 266, 90, 6, 8, 255, 192, 116, 266, 90, 6, 8, 12, 11, 7, + 17, 7, 26, 8, 6, 257, 130, 39, 9, 5, 19, 6, 5, 8, 9}; +u16 g_libSceDeci4h_debug_modules[1] = {156}; +u16 g_libSceHeadTracker_modules[1] = {157}; +u16 g_libSceGameUpdate_modules[2] = {158, 6}; +u16 g_libSceAutoMounterClient_modules[2] = {159, 6}; +u16 g_libSceSystemGesture_modules[1] = {160}; +u16 g_libSceVdecSavc_modules[1] = {161}; +u16 g_libSceVdecSavc2_modules[1] = {162}; +u16 g_libSceVideodec2_modules[3] = {163, 80, 162}; +u16 g_libSceVdecwrap_modules[2] = {164, 80}; +u16 g_libSceVshctl_modules[1] = {165}; +u16 g_libSceAt9Enc_modules[1] = {166}; +u16 g_libSceConvertKeycode_modules[1] = {167}; +u16 g_libSceGpuException_modules[1] = {168}; +u16 g_libSceSharePlay_modules[1] = {169}; +u16 g_libSceAudiodReport_modules[1] = {170}; +u16 g_libSceSulphaDrv_modules[1] = {171}; +u16 g_libSceHmd_modules[1] = {172}; +u16 g_libSceUsbStorage_modules[2] = {173, 6}; +u16 g_libSceVdecShevc_modules[1] = {174}; +u16 g_libSceUsbStorageDialog_modules[1] = {175}; +u16 g_libSceFaceTracker_modules[2] = {176, 59}; +u16 g_libSceHandTracker_modules[1] = {177}; +u16 g_libSceNpSnsYouTubeDialog_modules[2] = {178, 117}; +u16 g_libSceVrTracker_modules[6] = {179, 6, 172, 31, 17, 73}; +u16 g_libSceProfileCacheExternal_modules[2] = {180, 6}; +u16 g_libSceBackupRestoreUtil_modules[1] = {181}; +u16 g_libSceMusicPlayerService_modules[2] = {182, 183}; +u16 g_libSceMusicCoreServerClientJsEx_modules[1] = {183}; +u16 g_libSceSpSysCallWrapper_modules[3] = {184, 19, 6}; +u16 g_libScePs2EmuMenuDialog_modules[1] = {185}; +u16 g_libSceNpSnsDailyMotionDialog_modules[1] = {186}; +u16 g_libSceAudiodecCpuHevag_modules[1] = {187}; +u16 g_libSceLoginDialog_modules[2] = {188, 6}; +u16 g_libSceLoginService_modules[2] = {189, 6}; +u16 g_libSceSigninDialog_modules[2] = {190, 6}; +u16 g_libSceVdecsw_modules[3] = {191, 80, 162}; +u16 g_libSceOrbisCompat_modules[24] = {192, 116, 266, 90, 6, 8, 12, 11, 7, 17, 7, 26, + 8, 6, 257, 130, 39, 9, 5, 19, 6, 5, 8, 9}; +u16 g_libSceCoreIPC_modules[1] = {193}; +u16 g_libSceCustomMusicCore_modules[12] = {194, 29, 8, 27, 6, 14, 11, 7, 6, 11, 7, 6}; +u16 g_libSceJson2_modules[1] = {195}; +u16 g_libSceAudioLatencyEstimation_modules[1] = {196}; +u16 g_libSceWkFontConfig_modules[1] = {197}; +u16 g_libSceVorbisDec_modules[3] = {198, 67, 16}; +u16 g_libSceTtsCoreEnUs_modules[1] = {199}; +u16 g_libSceTtsCoreJp_modules[1] = {200}; +u16 g_libSceOpusCeltEnc_modules[2] = {201, 16}; +u16 g_libSceOpusCeltDec_modules[2] = {202, 16}; +u16 g_libSceLoginMgrServer_modules[1] = {203}; +u16 g_libSceHmdSetupDialog_modules[1] = {204}; +u16 g_libSceVideoOutSecondary_modules[6] = {205, 82, 6, 12, 11, 7}; +u16 g_libSceContentDelete_modules[1] = {206}; +u16 g_libSceImeBackend_modules[1] = {207}; +u16 g_libSceNetCtlApDialog_modules[1] = {208}; +u16 g_libSceGnmResourceRegistration_modules[1] = {209}; +u16 g_libScePlayGoDialog_modules[1] = {210}; +u16 g_libSceSocialScreen_modules[7] = {211, 205, 82, 6, 12, 11, 7}; +u16 g_libSceEditMp4_modules[1] = {212}; +u16 g_libScePsmKitSystem_modules[1] = {221}; +u16 g_libSceTextToSpeech_modules[1] = {222}; +u16 g_libSceNpToolkit_modules[1] = {223}; +u16 g_libSceCustomMusicService_modules[2] = {224, 183}; +u16 g_libSceClSysCallWrapper_modules[11] = {225, 20, 39, 9, 19, 5, 39, 9, 5, 67, 16}; +u16 g_libSceScm_modules[1] = {226}; +u16 g_libSceSystemLogger_modules[2] = {227, 6}; +u16 g_libSceBluetoothHid_modules[1] = {228}; +u16 g_libSceAvPlayerStreaming_modules[1] = {229}; +u16 g_libSceAudiodecCpuAlac_modules[1] = {230}; +u16 g_libSceVideoDecoderArbitration_modules[1] = {231}; +u16 g_libSceVrServiceDialog_modules[1] = {232}; +u16 g_libSceJobManager_modules[2] = {233, 114}; +u16 g_libSceAudiodecCpuFlac_modules[1] = {234}; +u16 g_libSceSrcUtl_modules[2] = {235, 16}; +u16 g_libSceS3da_modules[1] = {236}; +u16 g_libSceDseehx_modules[1] = {237}; +u16 g_libSceShareFactoryUtil_modules[1] = {238}; +u16 g_libSceDataTransfer_modules[1] = {239}; +u16 g_libSceSocialScreenDialog_modules[1] = {240}; +u16 g_libSceAbstractStorage_modules[1] = {241}; +u16 g_libSceImageUtil_modules[1] = {242}; +u16 g_libSceMetadataReaderWriter_modules[1] = {243}; +u16 g_libSceJpegParser_modules[1] = {244}; +u16 g_libSceGvMp4Parser_modules[1] = {245}; +u16 g_libScePngParser_modules[1] = {246}; +u16 g_libSceGifParser_modules[1] = {247}; +u16 g_libSceNpSnsDialog_modules[2] = {248, 117}; +u16 g_libSceAbstractLocal_modules[1] = {249}; +u16 g_libSceAbstractFacebook_modules[1] = {250}; +u16 g_libSceAbstractYoutube_modules[1] = {251}; +u16 g_libSceAbstractTwitter_modules[1] = {252}; +u16 g_libSceAbstractDailymotion_modules[1] = {253}; +u16 g_libSceNpToolkit2_modules[1] = {254}; +u16 g_libScePrecompiledShaders_modules[1] = {255}; +u16 g_libSceDiscId_modules[1] = {256}; +u16 g_libSceLibreSsl_modules[2] = {257, 130}; +u16 g_libSceFsInternalForVsh_modules[1] = {258}; +u16 g_libSceNpUniversalDataSystem_modules[1] = {259}; +u16 g_libSceDolbyVision_modules[1] = {260}; +u16 g_libSceOpusSilkEnc_modules[2] = {261, 16}; +u16 g_libSceOpusDec_modules[2] = {262, 16}; +u16 g_libSceWebKit2Secure_modules[34] = {263, 265, 26, 8, 6, 266, 90, 6, 8, 255, 192, 116, + 266, 90, 6, 8, 12, 11, 7, 17, 7, 26, 8, 6, + 257, 130, 39, 9, 5, 19, 6, 5, 8, 9}; +u16 g_libSceJscCompiler_modules[1] = {264}; +u16 g_libSceJitBridge_modules[4] = {265, 26, 8, 6}; +u16 g_libScePigletv2VSH_modules[4] = {266, 90, 6, 8}; +u16 g_libSceJitBridge_common_ex_modules[4] = {267, 26, 8, 6}; +u16 g_libSceJscCompiler_common_ex_modules[1] = {268}; +u16 g_libSceOrbisCompat_common_ex_modules[24] = {269, 116, 266, 90, 6, 8, 12, 11, 7, 17, 7, 26, + 8, 6, 257, 130, 39, 9, 5, 19, 6, 5, 8, 9}; +u16 g_libSceWeb_common_ex_modules[6] = {270, 271, 147, 269, 27, 6}; +u16 g_libSceWebKit2_common_ex_modules[30] = {271, 266, 90, 6, 8, 273, 269, 116, 266, 90, + 6, 8, 12, 11, 7, 17, 7, 26, 8, 6, + 257, 130, 39, 9, 5, 19, 6, 5, 8, 9}; +u16 g_libSceWebKit2Secure_common_ex_modules[34] = { + 272, 267, 26, 8, 6, 266, 90, 6, 8, 273, 269, 116, 266, 90, 6, 8, 12, + 11, 7, 17, 7, 26, 8, 6, 257, 130, 39, 9, 5, 19, 6, 5, 8, 9}; +u16 g_libScePrecompiledShaders_common_ex_modules[1] = {273}; +u16 g_libSceGic_modules[1] = {274}; +u16 g_libSceRnpsAppMgr_modules[1] = {275}; +u16 g_libSceAsyncStorageInternal_modules[1] = {276}; +u16 g_libSceHttpCache_modules[1] = {277}; +u16 g_libScePlayReady2_modules[1] = {278}; +u16 g_libSceHdrScopes_debug_modules[1] = {279}; +u16 g_libSceNKWeb_modules[1] = {280}; +u16 g_libSceNKWebKit_modules[2] = {281, 282}; +u16 g_libSceNKWebKitRequirements_modules[1] = {282}; +u16 g_libSceVnaInternal_modules[1] = {283}; +u16 g_libSceVnaWebsocket_modules[1] = {284}; +u16 g_libSceCesCs_modules[1] = {285}; +u16 g_libSceComposite_modules[1] = {286}; +u16 g_libSceCompositeExt_modules[1] = {287}; +u16 g_libSceHubAppUtil_modules[1] = {288}; +u16 g_libScePosixForWebKit_modules[1] = {289}; +u16 g_libSceNpPartner001_modules[1] = {290}; +u16 g_libSceNpSessionSignaling_modules[75] = { + 291, 41, 23, 22, 20, 39, 19, 9, 5, 22, 20, 39, 19, 9, 8, 6, 5, 40, 20, 39, 9, 19, 5, 39, 9, + 5, 9, 19, 6, 5, 20, 39, 9, 19, 5, 39, 9, 5, 9, 5, 22, 20, 39, 19, 9, 8, 6, 5, 23, 22, + 20, 39, 19, 9, 5, 40, 20, 39, 9, 19, 5, 39, 9, 5, 9, 19, 6, 5, 39, 9, 5, 19, 6, 5, 9}; +u16 g_libScePlayerInvitationDialog_modules[1] = {292}; +u16 g_libSceNpCppWebApi_modules[42] = {293, 195, 41, 23, 22, 20, 39, 19, 9, 5, 22, 20, 39, 19, + 9, 8, 6, 5, 40, 20, 39, 9, 19, 5, 39, 9, 5, 9, + 19, 6, 5, 20, 39, 9, 19, 5, 39, 9, 5, 9, 5, 9}; +u16 g_libSceNpEntitlementAccess_modules[1] = {294}; +u16 g_libSceNpRemotePlaySessionSignaling_modules[76] = { + 295, 291, 41, 23, 22, 20, 39, 19, 9, 5, 22, 20, 39, 19, 9, 8, 6, 5, 40, + 20, 39, 9, 19, 5, 39, 9, 5, 9, 19, 6, 5, 20, 39, 9, 19, 5, 39, 9, + 5, 9, 5, 22, 20, 39, 19, 9, 8, 6, 5, 23, 22, 20, 39, 19, 9, 5, 40, + 20, 39, 9, 19, 5, 39, 9, 5, 9, 19, 6, 5, 39, 9, 5, 19, 6, 5, 9}; +u16 g_libSceLibreSsl3_modules[2] = {296, 130}; +u16 g_libcurl_modules[2] = {297, 289}; +u16 g_libicu_modules[2] = {298, 289}; +u16 g_libcairo_modules[9] = {299, 300, 301, 302, 303, 289, 298, 289, 289}; +u16 g_libfontconfig_modules[1] = {300}; +u16 g_libfreetype_modules[1] = {301}; +u16 g_libharfbuzz_modules[1] = {302}; +u16 g_libpng16_modules[2] = {303, 289}; +u16 g_libSceFontGs_modules[1] = {304}; +u16 g_libSceGLSlimClientVSH_modules[1] = {305}; +u16 g_libSceGLSlimServerVSH_modules[1] = {306}; +u16 g_libSceFontGsm_modules[1] = {307}; +u16 g_libSceNpPartnerSubscription_modules[1] = {308}; +u16 g_libSceNpAuthAuthorizedAppDialog_modules[1] = {309}; + +// This is the actual array of modules. +constexpr u64 g_num_modules = 310; +std::array g_modules_array = std::to_array< + OrbisSysmoduleModuleInternal>( + {{0x0, -1, 0, 0, nullptr, nullptr, 0}, + {0x0, -1, 0, 1, "libkernel", nullptr, 0}, + {0x0, -1, 0, 1, "libSceLibcInternal", nullptr, 0}, + {0x0, -1, 0, 4, "libSceFios2", nullptr, 0}, + {0x0, -1, 0, 4, "libc", nullptr, 0}, + {0x8000001c, -1, 0, 1, "libSceNet", g_libSceNet_modules, 1}, + {0x8000001d, -1, 0, 1, "libSceIpmi", g_libSceIpmi_modules, 1}, + {0x8000001e, -1, 0, 1, "libSceMbus", g_libSceMbus_modules, 2}, + {0x8000001f, -1, 0, 1, "libSceRegMgr", g_libSceRegMgr_modules, 1}, + {0x80000020, -1, 0, 1, "libSceRtc", g_libSceRtc_modules, 1}, + {0x0, -1, 0, 0, nullptr, nullptr, 0}, + {0x80000021, -1, 0, 1, "libSceAvSetting", g_libSceAvSetting_modules, 3}, + {0x80000022, -1, 0, 1, "libSceVideoOut", g_libSceVideoOut_modules, 3}, + {0x80000052, -1, 0, 1025, "libSceGnmDriver", g_libSceGnmDriver_modules, 4}, + {0x80000001, -1, 0, 1, "libSceAudioOut", g_libSceAudioOut_modules, 4}, + {0x80000002, -1, 0, 1, "libSceAudioIn", g_libSceAudioIn_modules, 4}, + {0x80000023, -1, 0, 1, "libSceAjm", g_libSceAjm_modules, 1}, + {0x80000024, -1, 0, 1, "libScePad", g_libScePad_modules, 2}, + {0x80000025, -1, 0, 9, "libSceDbg", g_libSceDbg_debug_modules, 1}, + {0x80000009, -1, 0, 1, "libSceNetCtl", g_libSceNetCtl_modules, 2}, + {0x8000000a, -1, 0, 1, "libSceHttp", g_libSceHttp_modules, 5}, + {0x0, -1, 0, 1, "libSceSsl", g_libSceSsl_modules, 3}, + {0x8000000c, -1, 0, 1, "libSceNpCommon", g_libSceNpCommon_modules, 8}, + {0x8000000d, -1, 0, 1, "libSceNpManager", g_libSceNpManager_modules, 7}, + {0x8000000e, -1, 0, 1, "libSceNpWebApi", g_libSceNpWebApi_modules, 7}, + {0x8000000f, -1, 0, 1, "libSceSaveData", g_libSceSaveData_modules, 4}, + {0x80000010, -1, 0, 1, "libSceSystemService", g_libSceSystemService_modules, 3}, + {0x80000011, -1, 0, 1, "libSceUserService", g_libSceUserService_modules, 2}, + {0x80000018, -1, 0, 1, "libSceCommonDialog", g_libSceCommonDialog_modules, 1}, + {0x80000026, -1, 0, 1, "libSceSysUtil", g_libSceSysUtil_modules, 2}, + {0x80000019, -1, 0, 9, "libScePerf", g_libScePerf_debug_modules, 3}, + {0x8000001a, -1, 0, 1, "libSceCamera", g_libSceCamera_modules, 2}, + {0x0, -1, 0, 1, "libSceWebKit2ForVideoService", nullptr, 0}, + {0x0, -1, 0, 1, "libSceOrbisCompatForVideoService", nullptr, 0}, + {0xd7, -1, 0, 1, "libSceDiscMap", g_libSceDiscMap_modules, 1}, + {0x8000003d, -1, 0, 129, "libSceDbgAssist", g_libSceDbgAssist_modules, 1}, + {0x80000048, -1, 0, 9, "libSceMat", g_libSceMat_debug_modules, 1}, + {0x0, -1, 0, 1, "libSceRazorCpu", g_libSceRazorCpu_modules, 1}, + {0x80000075, -1, 0, 9, "libSceRazorCpu_debug", g_libSceRazorCpu_debug_debug_modules, 2}, + {0x8000000b, -1, 0, 1, "libSceSsl2", g_libSceSsl2_modules, 3}, + {0x8000008c, -1, 0, 1, "libSceHttp2", g_libSceHttp2_modules, 13}, + {0x8000008f, -1, 0, 1, "libSceNpWebApi2", g_libSceNpWebApi2_modules, 39}, + {0x8000008d, -1, 0, 1, "libSceNpGameIntent", g_libSceNpGameIntent_modules, 10}, + {0x0, -1, 0, 0, nullptr, nullptr, 0}, + {0x0, -1, 0, 0, nullptr, nullptr, 0}, + {0x0, -1, 0, 0, nullptr, nullptr, 0}, + {0x0, -1, 0, 0, nullptr, nullptr, 0}, + {0x0, -1, 0, 0, nullptr, nullptr, 0}, + {0x0, -1, 0, 0, nullptr, nullptr, 0}, + {0x6, -1, 0, 1, "libSceFiber", g_libSceFiber_modules, 5}, + {0x7, -1, 0, 1, "libSceUlt", g_libSceUlt_modules, 6}, + {0xb, -1, 0, 1, "libSceNgs2", g_libSceNgs2_modules, 2}, + {0x17, -1, 0, 1, "libSceXml", g_libSceXml_modules, 1}, + {0x19, -1, 0, 1, "libSceNpUtility", g_libSceNpUtility_modules, 5}, + {0x1a, -1, 0, 1, "libSceVoice", g_libSceVoice_modules, 4}, + {0x1c, -1, 0, 1, "libSceNpMatching2", g_libSceNpMatching2_modules, 7}, + {0x1e, -1, 0, 1, "libSceNpScoreRanking", g_libSceNpScoreRanking_modules, 3}, + {0x21, -1, 0, 1, "libSceRudp", g_libSceRudp_modules, 1}, + {0x2c, -1, 0, 1, "libSceNpTus", g_libSceNpTus_modules, 3}, + {0x38, -1, 0, 4, "libSceFace", g_libSceFace_modules, 1}, + {0x39, -1, 0, 4, "libSceSmart", g_libSceSmart_modules, 1}, + {0x80, -1, 0, 1, "libSceJson", g_libSceJson_modules, 1}, + {0x81, -1, 0, 1, "libSceGameLiveStreaming", g_libSceGameLiveStreaming_modules, 2}, + {0x82, -1, 0, 1, "libSceCompanionUtil", g_libSceCompanionUtil_modules, 3}, + {0x83, -1, 0, 1, "libScePlayGo", g_libScePlayGo_modules, 1}, + {0x84, -1, 0, 1, "libSceFont", g_libSceFont_modules, 1}, + {0x85, -1, 0, 1, "libSceVideoRecording", g_libSceVideoRecording_modules, 2}, + {0x88, -1, 0, 1, "libSceAudiodec", g_libSceAudiodec_modules, 2}, + {0x8a, -1, 0, 1, "libSceJpegDec", g_libSceJpegDec_modules, 1}, + {0x8b, -1, 0, 1, "libSceJpegEnc", g_libSceJpegEnc_modules, 1}, + {0x8c, -1, 0, 1, "libScePngDec", g_libScePngDec_modules, 1}, + {0x8d, -1, 0, 1, "libScePngEnc", g_libScePngEnc_modules, 1}, + {0x8e, -1, 0, 2049, "libSceVideodec", g_libSceVideodec_modules, 3}, + {0x8f, -1, 0, 1, "libSceMove", g_libSceMove_modules, 1}, + {0x0, -1, 0, 0, nullptr, nullptr, 0}, + {0x91, -1, 0, 1, "libScePadTracker", g_libScePadTracker_modules, 2}, + {0x92, -1, 0, 1, "libSceDepth", g_libSceDepth_modules, 2}, + {0x93, -1, 0, 4, "libSceHand", g_libSceHand_modules, 1}, + {0x95, -1, 0, 1, "libSceIme", g_libSceIme_modules, 2}, + {0x96, -1, 0, 1, "libSceImeDialog", g_libSceImeDialog_modules, 2}, + {0x80000015, -1, 0, 1, "libSceVdecCore", g_libSceVdecCore_modules, 1}, + {0x97, -1, 0, 1, "libSceNpParty", g_libSceNpParty_modules, 2}, + {0x80000003, -1, 0, 1, "libSceAvcap", g_libSceAvcap_modules, 2}, + {0x98, -1, 0, 1, "libSceFontFt", g_libSceFontFt_modules, 1}, + {0x99, -1, 0, 1, "libSceFreeTypeOt", g_libSceFreeTypeOt_modules, 1}, + {0x9a, -1, 0, 1, "libSceFreeTypeOl", g_libSceFreeTypeOl_modules, 1}, + {0x9b, -1, 0, 1, "libSceFreeTypeOptOl", g_libSceFreeTypeOptOl_modules, 1}, + {0x9c, -1, 0, 1, "libSceScreenShot", g_libSceScreenShot_modules, 3}, + {0x9d, -1, 0, 1, "libSceNpAuth", g_libSceNpAuth_modules, 3}, + {0x1b, -1, 0, 1, "libSceVoiceQos", g_libSceVoiceQos_modules, 5}, + {0x80000004, -1, 0, 1, "libSceSysCore", g_libSceSysCore_modules, 2}, + {0xbc, -1, 0, 1, "libSceM4aacEnc", g_libSceM4aacEnc_modules, 2}, + {0xbd, -1, 0, 1, "libSceAudiodecCpu", g_libSceAudiodecCpu_modules, 1}, + {0x80000007, -1, 0, 1, "libSceCdlgUtilServer", g_libSceCdlgUtilServer_modules, 2}, + {0x9f, -1, 0, 9, "libSceSulpha", g_libSceSulpha_debug_modules, 1}, + {0xa0, -1, 0, 1, "libSceSaveDataDialog", g_libSceSaveDataDialog_modules, 4}, + {0xa2, -1, 0, 1, "libSceInvitationDialog", g_libSceInvitationDialog_modules, 1}, + {0xa3, -1, 0, 2057, "libSceKeyboard", g_libSceKeyboard_debug_modules, 1}, + {0x106, -1, 0, 2049, "libSceKeyboard", g_libSceKeyboard_modules, 1}, + {0xa4, -1, 0, 1, "libSceMsgDialog", g_libSceMsgDialog_modules, 1}, + {0xa5, -1, 0, 1, "libSceAvPlayer", g_libSceAvPlayer_modules, 1}, + {0xa6, -1, 0, 1, "libSceContentExport", g_libSceContentExport_modules, 1}, + {0x80000012, -1, 0, 2, "libSceVisionManager", g_libSceVisionManager_modules, 1}, + {0x80000013, -1, 0, 2, "libSceAc3Enc", g_libSceAc3Enc_modules, 2}, + {0x80000014, -1, 0, 1, "libSceAppInstUtil", g_libSceAppInstUtil_modules, 1}, + {0x80000016, -1, 0, 514, "libSceVencCore", g_libSceVencCore_modules, 1}, + {0xa7, -1, 0, 1, "libSceAudio3d", g_libSceAudio3d_modules, 1}, + {0xa8, -1, 0, 1, "libSceNpCommerce", g_libSceNpCommerce_modules, 1}, + {0x80000017, -1, 0, 1, "libSceHidControl", g_libSceHidControl_modules, 1}, + {0xa9, -1, 0, 1, "libSceMouse", g_libSceMouse_modules, 1}, + {0xaa, -1, 0, 1, "libSceCompanionHttpd", g_libSceCompanionHttpd_modules, 1}, + {0xab, -1, 0, 1, "libSceWebBrowserDialog", g_libSceWebBrowserDialog_modules, 1}, + {0xac, -1, 0, 1, "libSceErrorDialog", g_libSceErrorDialog_modules, 1}, + {0xad, -1, 0, 1, "libSceNpTrophy", g_libSceNpTrophy_modules, 1}, + {0x0, -1, 0, 1, "ulobjmgr", g_ulobjmgr_modules, 1}, + {0xae, -1, 0, 1, "libSceVideoCoreInterface", g_libSceVideoCoreInterface_modules, 1}, + {0xaf, -1, 0, 1, "libSceVideoCoreServerInterface", g_libSceVideoCoreServerInterface_modules, + 1}, + {0x8000001b, -1, 0, 1, "libSceNpSns", g_libSceNpSns_modules, 1}, + {0xb0, -1, 0, 1, "libSceNpSnsFacebookDialog", g_libSceNpSnsFacebookDialog_modules, 2}, + {0xb1, -1, 0, 1, "libSceMoveTracker", g_libSceMoveTracker_modules, 1}, + {0xb2, -1, 0, 1, "libSceNpProfileDialog", g_libSceNpProfileDialog_modules, 1}, + {0xb3, -1, 0, 1, "libSceNpFriendListDialog", g_libSceNpFriendListDialog_modules, 1}, + {0xb4, -1, 0, 1, "libSceAppContent", g_libSceAppContent_modules, 1}, + {0x80000027, -1, 0, 2, "libSceMarlin", g_libSceMarlin_modules, 1}, + {0x80000028, -1, 0, 2, "libSceDtsEnc", g_libSceDtsEnc_modules, 2}, + {0xb5, -1, 0, 1, "libSceNpSignaling", g_libSceNpSignaling_modules, 1}, + {0xb6, -1, 0, 1, "libSceRemoteplay", g_libSceRemoteplay_modules, 1}, + {0xb7, -1, 0, 1, "libSceUsbd", g_libSceUsbd_modules, 1}, + {0xb8, -1, 0, 1, "libSceGameCustomDataDialog", g_libSceGameCustomDataDialog_modules, 1}, + {0xb9, -1, 0, 1, "libSceNpEulaDialog", g_libSceNpEulaDialog_modules, 1}, + {0xba, -1, 0, 1, "libSceRandom", g_libSceRandom_modules, 1}, + {0x80000029, -1, 0, 2, "libSceDipsw", g_libSceDipsw_modules, 1}, + {0x86, -1, 0, 4, "libSceS3DConversion", g_libSceS3DConversion_modules, 1}, + {0x8000003e, -1, 0, 9, "libSceOttvCapture", g_libSceOttvCapture_debug_modules, 1}, + {0x8000002a, -1, 0, 1, "libSceBgft", g_libSceBgft_modules, 1}, + {0xbe, -1, 0, 1, "libSceAudiodecCpuDdp", g_libSceAudiodecCpuDdp_modules, 1}, + {0xc0, -1, 0, 1, "libSceAudiodecCpuM4aac", g_libSceAudiodecCpuM4aac_modules, 1}, + {0x8000002b, -1, 0, 2, "libSceAudiodecCpuDts", g_libSceAudiodecCpuDts_modules, 1}, + {0xc9, -1, 0, 1, "libSceAudiodecCpuDtsHdLbr", g_libSceAudiodecCpuDtsHdLbr_modules, 1}, + {0x8000002d, -1, 0, 2, "libSceAudiodecCpuDtsHdMa", g_libSceAudiodecCpuDtsHdMa_modules, 1}, + {0x8000002e, -1, 0, 2, "libSceAudiodecCpuLpcm", g_libSceAudiodecCpuLpcm_modules, 1}, + {0xc1, -1, 0, 1, "libSceBemp2sys", g_libSceBemp2sys_modules, 1}, + {0xc2, -1, 0, 1, "libSceBeisobmf", g_libSceBeisobmf_modules, 1}, + {0xc3, -1, 0, 1, "libScePlayReady", g_libScePlayReady_modules, 1}, + {0xc4, -1, 0, 1, "libSceVideoNativeExtEssential", g_libSceVideoNativeExtEssential_modules, 1}, + {0xc5, -1, 0, 1, "libSceZlib", g_libSceZlib_modules, 1}, + {0x8000002f, -1, 0, 1, "libSceIduUtil", g_libSceIduUtil_modules, 1}, + {0x80000030, -1, 0, 1, "libScePsm", g_libScePsm_modules, 1}, + {0xc6, -1, 0, 1, "libSceDtcpIp", g_libSceDtcpIp_modules, 1}, + {0x80000031, -1, 0, 1, "libSceKbEmulate", g_libSceKbEmulate_modules, 1}, + {0x80000032, -1, 0, 2, "libSceAppChecker", g_libSceAppChecker_modules, 1}, + {0x80000033, -1, 0, 1, "libSceNpGriefReport", g_libSceNpGriefReport_modules, 1}, + {0xc7, -1, 0, 1, "libSceContentSearch", g_libSceContentSearch_modules, 1}, + {0xc8, -1, 0, 1, "libSceShareUtility", g_libSceShareUtility_modules, 1}, + {0x80000034, -1, 0, 1, "libSceWeb", g_libSceWeb_modules, 6}, + {0x8000006a, -1, 0, 1, "libSceWebKit2", g_libSceWebKit2_modules, 30}, + {0xca, -1, 0, 9, "libSceDeci4h", g_libSceDeci4h_debug_modules, 1}, + {0xcb, -1, 0, 4, "libSceHeadTracker", g_libSceHeadTracker_modules, 1}, + {0xcc, -1, 0, 1, "libSceGameUpdate", g_libSceGameUpdate_modules, 2}, + {0xcd, -1, 0, 1, "libSceAutoMounterClient", g_libSceAutoMounterClient_modules, 2}, + {0xce, -1, 0, 1, "libSceSystemGesture", g_libSceSystemGesture_modules, 1}, + {0x80000035, -1, 0, 1, "libSceVdecSavc", g_libSceVdecSavc_modules, 1}, + {0x80000036, -1, 0, 1, "libSceVdecSavc2", g_libSceVdecSavc2_modules, 1}, + {0xcf, -1, 0, 2049, "libSceVideodec2", g_libSceVideodec2_modules, 3}, + {0xd0, -1, 0, 1, "libSceVdecwrap", g_libSceVdecwrap_modules, 2}, + {0x80000037, -1, 0, 1, "libSceVshctl", g_libSceVshctl_modules, 1}, + {0xd1, -1, 0, 1, "libSceAt9Enc", g_libSceAt9Enc_modules, 1}, + {0xd2, -1, 0, 1, "libSceConvertKeycode", g_libSceConvertKeycode_modules, 1}, + {0x80000039, -1, 0, 1, "libSceGpuException", g_libSceGpuException_modules, 1}, + {0xd3, -1, 0, 1, "libSceSharePlay", g_libSceSharePlay_modules, 1}, + {0x8000003a, -1, 0, 2, "libSceAudiodReport", g_libSceAudiodReport_modules, 1}, + {0x8000003b, -1, 0, 2, "libSceSulphaDrv", g_libSceSulphaDrv_modules, 1}, + {0xd4, -1, 0, 1, "libSceHmd", g_libSceHmd_modules, 1}, + {0xd5, -1, 0, 1, "libSceUsbStorage", g_libSceUsbStorage_modules, 2}, + {0x8000003c, -1, 0, 1, "libSceVdecShevc", g_libSceVdecShevc_modules, 1}, + {0xd6, -1, 0, 1, "libSceUsbStorageDialog", g_libSceUsbStorageDialog_modules, 1}, + {0xd8, -1, 0, 4, "libSceFaceTracker", g_libSceFaceTracker_modules, 2}, + {0xd9, -1, 0, 4, "libSceHandTracker", g_libSceHandTracker_modules, 1}, + {0xda, -1, 0, 1, "libSceNpSnsYouTubeDialog", g_libSceNpSnsYouTubeDialog_modules, 2}, + {0xed, -1, 0, 1, "libSceVrTracker", g_libSceVrTracker_modules, 6}, + {0xdc, -1, 0, 1, "libSceProfileCacheExternal", g_libSceProfileCacheExternal_modules, 2}, + {0x8000003f, -1, 0, 1, "libSceBackupRestoreUtil", g_libSceBackupRestoreUtil_modules, 1}, + {0xdd, -1, 0, 1, "libSceMusicPlayerService", g_libSceMusicPlayerService_modules, 2}, + {0x0, -1, 0, 1, "libSceMusicCoreServerClientJsEx", g_libSceMusicCoreServerClientJsEx_modules, + 1}, + {0xde, -1, 0, 1, "libSceSpSysCallWrapper", g_libSceSpSysCallWrapper_modules, 3}, + {0xdf, -1, 0, 1, "libScePs2EmuMenuDialog", g_libScePs2EmuMenuDialog_modules, 1}, + {0xe0, -1, 0, 1, "libSceNpSnsDailyMotionDialog", g_libSceNpSnsDailyMotionDialog_modules, 1}, + {0xe1, -1, 0, 1, "libSceAudiodecCpuHevag", g_libSceAudiodecCpuHevag_modules, 1}, + {0xe2, -1, 0, 1, "libSceLoginDialog", g_libSceLoginDialog_modules, 2}, + {0xe3, -1, 0, 1, "libSceLoginService", g_libSceLoginService_modules, 2}, + {0xe4, -1, 0, 1, "libSceSigninDialog", g_libSceSigninDialog_modules, 2}, + {0xe5, -1, 0, 1, "libSceVdecsw", g_libSceVdecsw_modules, 3}, + {0x8000006d, -1, 0, 1, "libSceOrbisCompat", g_libSceOrbisCompat_modules, 24}, + {0x0, -1, 0, 1, "libSceCoreIPC", g_libSceCoreIPC_modules, 1}, + {0xe6, -1, 0, 1, "libSceCustomMusicCore", g_libSceCustomMusicCore_modules, 12}, + {0xe7, -1, 0, 1, "libSceJson2", g_libSceJson2_modules, 1}, + {0xe8, -1, 0, 4, "libSceAudioLatencyEstimation", g_libSceAudioLatencyEstimation_modules, 1}, + {0xe9, -1, 0, 1, "libSceWkFontConfig", g_libSceWkFontConfig_modules, 1}, + {0xea, -1, 0, 2, "libSceVorbisDec", g_libSceVorbisDec_modules, 3}, + {0x80000041, -1, 0, 1, "libSceTtsCoreEnUs", g_libSceTtsCoreEnUs_modules, 1}, + {0x80000042, -1, 0, 1, "libSceTtsCoreJp", g_libSceTtsCoreJp_modules, 1}, + {0x80000043, -1, 0, 1, "libSceOpusCeltEnc", g_libSceOpusCeltEnc_modules, 2}, + {0x80000044, -1, 0, 1, "libSceOpusCeltDec", g_libSceOpusCeltDec_modules, 2}, + {0x80000045, -1, 0, 2, "libSceLoginMgrServer", g_libSceLoginMgrServer_modules, 1}, + {0xeb, -1, 0, 1, "libSceHmdSetupDialog", g_libSceHmdSetupDialog_modules, 1}, + {0x80000046, -1, 0, 1, "libSceVideoOutSecondary", g_libSceVideoOutSecondary_modules, 6}, + {0xee, -1, 0, 1, "libSceContentDelete", g_libSceContentDelete_modules, 1}, + {0xef, -1, 0, 1, "libSceImeBackend", g_libSceImeBackend_modules, 1}, + {0xf0, -1, 0, 1, "libSceNetCtlApDialog", g_libSceNetCtlApDialog_modules, 1}, + {0x80000047, -1, 0, 1, "libSceGnmResourceRegistration", + g_libSceGnmResourceRegistration_modules, 1}, + {0xf1, -1, 0, 1, "libScePlayGoDialog", g_libScePlayGoDialog_modules, 1}, + {0xf2, -1, 0, 1, "libSceSocialScreen", g_libSceSocialScreen_modules, 7}, + {0xf3, -1, 0, 1, "libSceEditMp4", g_libSceEditMp4_modules, 1}, + {0x0, -1, 0, 0, nullptr, nullptr, 0}, + {0x0, -1, 0, 0, nullptr, nullptr, 0}, + {0x0, -1, 0, 0, nullptr, nullptr, 0}, + {0x0, -1, 0, 0, nullptr, nullptr, 0}, + {0x0, -1, 0, 0, nullptr, nullptr, 0}, + {0x0, -1, 0, 0, nullptr, nullptr, 0}, + {0x0, -1, 0, 0, nullptr, nullptr, 0}, + {0x0, -1, 0, 0, nullptr, nullptr, 0}, + {0xf5, -1, 0, 1, "libScePsmKitSystem", g_libScePsmKitSystem_modules, 1}, + {0xf6, -1, 0, 1, "libSceTextToSpeech", g_libSceTextToSpeech_modules, 1}, + {0xf7, -1, 0, 2052, "libSceNpToolkit", g_libSceNpToolkit_modules, 1}, + {0xf8, -1, 0, 1, "libSceCustomMusicService", g_libSceCustomMusicService_modules, 2}, + {0xf9, -1, 0, 1, "libSceClSysCallWrapper", g_libSceClSysCallWrapper_modules, 11}, + {0x80000049, -1, 0, 1, "libSceScm", g_libSceScm_modules, 1}, + {0xfa, -1, 0, 1, "libSceSystemLogger", g_libSceSystemLogger_modules, 2}, + {0xfb, -1, 0, 1, "libSceBluetoothHid", g_libSceBluetoothHid_modules, 1}, + {0x80000050, -1, 0, 1, "libSceAvPlayerStreaming", g_libSceAvPlayerStreaming_modules, 1}, + {0x80000051, -1, 0, 2, "libSceAudiodecCpuAlac", g_libSceAudiodecCpuAlac_modules, 1}, + {0xfc, -1, 0, 1, "libSceVideoDecoderArbitration", g_libSceVideoDecoderArbitration_modules, 1}, + {0xfd, -1, 0, 1, "libSceVrServiceDialog", g_libSceVrServiceDialog_modules, 1}, + {0xfe, -1, 0, 4, "libSceJobManager", g_libSceJobManager_modules, 2}, + {0x80000053, -1, 0, 2, "libSceAudiodecCpuFlac", g_libSceAudiodecCpuFlac_modules, 1}, + {0x103, -1, 0, 1, "libSceSrcUtl", g_libSceSrcUtl_modules, 2}, + {0x80000055, -1, 0, 2, "libSceS3da", g_libSceS3da_modules, 1}, + {0x80000056, -1, 0, 2, "libSceDseehx", g_libSceDseehx_modules, 1}, + {0xff, -1, 0, 1, "libSceShareFactoryUtil", g_libSceShareFactoryUtil_modules, 1}, + {0x80000057, -1, 0, 1, "libSceDataTransfer", g_libSceDataTransfer_modules, 1}, + {0x100, -1, 0, 1, "libSceSocialScreenDialog", g_libSceSocialScreenDialog_modules, 1}, + {0x80000058, -1, 0, 1, "libSceAbstractStorage", g_libSceAbstractStorage_modules, 1}, + {0x80000059, -1, 0, 1, "libSceImageUtil", g_libSceImageUtil_modules, 1}, + {0x8000005a, -1, 0, 1, "libSceMetadataReaderWriter", g_libSceMetadataReaderWriter_modules, 1}, + {0x8000005b, -1, 0, 1, "libSceJpegParser", g_libSceJpegParser_modules, 1}, + {0x8000005c, -1, 0, 1, "libSceGvMp4Parser", g_libSceGvMp4Parser_modules, 1}, + {0x8000005d, -1, 0, 1, "libScePngParser", g_libScePngParser_modules, 1}, + {0x8000005e, -1, 0, 1, "libSceGifParser", g_libSceGifParser_modules, 1}, + {0x101, -1, 0, 1, "libSceNpSnsDialog", g_libSceNpSnsDialog_modules, 2}, + {0x8000005f, -1, 0, 1, "libSceAbstractLocal", g_libSceAbstractLocal_modules, 1}, + {0x80000060, -1, 0, 1, "libSceAbstractFacebook", g_libSceAbstractFacebook_modules, 1}, + {0x80000061, -1, 0, 1, "libSceAbstractYoutube", g_libSceAbstractYoutube_modules, 1}, + {0x80000062, -1, 0, 1, "libSceAbstractTwitter", g_libSceAbstractTwitter_modules, 1}, + {0x80000063, -1, 0, 1, "libSceAbstractDailymotion", g_libSceAbstractDailymotion_modules, 1}, + {0x102, -1, 0, 2052, "libSceNpToolkit2", g_libSceNpToolkit2_modules, 1}, + {0x80000064, -1, 0, 1, "libScePrecompiledShaders", g_libScePrecompiledShaders_modules, 1}, + {0x104, -1, 0, 1, "libSceDiscId", g_libSceDiscId_modules, 1}, + {0x80000065, -1, 0, 1, "libSceLibreSsl", g_libSceLibreSsl_modules, 2}, + {0x80000066, -1, 0, 2, "libSceFsInternalForVsh", g_libSceFsInternalForVsh_modules, 1}, + {0x105, -1, 0, 1, "libSceNpUniversalDataSystem", g_libSceNpUniversalDataSystem_modules, 1}, + {0x80000067, -1, 0, 1, "libSceDolbyVision", g_libSceDolbyVision_modules, 1}, + {0x80000068, -1, 0, 1, "libSceOpusSilkEnc", g_libSceOpusSilkEnc_modules, 2}, + {0x80000069, -1, 0, 1, "libSceOpusDec", g_libSceOpusDec_modules, 2}, + {0x8000006b, -1, 0, 1, "libSceWebKit2Secure", g_libSceWebKit2Secure_modules, 34}, + {0x8000006c, -1, 0, 1, "libSceJscCompiler", g_libSceJscCompiler_modules, 1}, + {0x8000006e, -1, 0, 1, "libSceJitBridge", g_libSceJitBridge_modules, 4}, + {0x0, -1, 0, 1, "libScePigletv2VSH", g_libScePigletv2VSH_modules, 4}, + {0x8000006f, -1, 0, 4096, "libSceJitBridge", g_libSceJitBridge_common_ex_modules, 4}, + {0x80000070, -1, 0, 4096, "libSceJscCompiler", g_libSceJscCompiler_common_ex_modules, 1}, + {0x80000071, -1, 0, 4096, "libSceOrbisCompat", g_libSceOrbisCompat_common_ex_modules, 24}, + {0x80000072, -1, 0, 4096, "libSceWeb", g_libSceWeb_common_ex_modules, 6}, + {0x80000073, -1, 0, 4096, "libSceWebKit2", g_libSceWebKit2_common_ex_modules, 30}, + {0x80000074, -1, 0, 4096, "libSceWebKit2Secure", g_libSceWebKit2Secure_common_ex_modules, 34}, + {0x0, -1, 0, 4096, "libScePrecompiledShaders", g_libScePrecompiledShaders_common_ex_modules, + 1}, + {0x107, -1, 0, 1, "libSceGic", g_libSceGic_modules, 1}, + {0x80000076, -1, 0, 1, "libSceRnpsAppMgr", g_libSceRnpsAppMgr_modules, 1}, + {0x80000077, -1, 0, 1, "libSceAsyncStorageInternal", g_libSceAsyncStorageInternal_modules, 1}, + {0x80000078, -1, 0, 1, "libSceHttpCache", g_libSceHttpCache_modules, 1}, + {0x108, -1, 0, 1, "libScePlayReady2", g_libScePlayReady2_modules, 1}, + {0x109, -1, 0, 9, "libSceHdrScopes", g_libSceHdrScopes_debug_modules, 1}, + {0x80000079, -1, 0, 1, "libSceNKWeb", g_libSceNKWeb_modules, 1}, + {0x8000007a, -1, 0, 1, "libSceNKWebKit", g_libSceNKWebKit_modules, 2}, + {0x0, -1, 0, 1, "libSceNKWebKitRequirements", g_libSceNKWebKitRequirements_modules, 1}, + {0x8000007c, -1, 0, 1, "libSceVnaInternal", g_libSceVnaInternal_modules, 1}, + {0x8000007d, -1, 0, 1, "libSceVnaWebsocket", g_libSceVnaWebsocket_modules, 1}, + {0x10c, -1, 0, 1, "libSceCesCs", g_libSceCesCs_modules, 1}, + {0x8000008a, -1, 0, 2, "libSceComposite", g_libSceComposite_modules, 1}, + {0x8000008b, -1, 0, 1, "libSceCompositeExt", g_libSceCompositeExt_modules, 1}, + {0x116, -1, 0, 1, "libSceHubAppUtil", g_libSceHubAppUtil_modules, 1}, + {0x80000098, -1, 0, 1, "libScePosixForWebKit", g_libScePosixForWebKit_modules, 1}, + {0x11a, -1, 0, 1, "libSceNpPartner001", g_libSceNpPartner001_modules, 1}, + {0x112, -1, 0, 1, "libSceNpSessionSignaling", g_libSceNpSessionSignaling_modules, 75}, + {0x10d, -1, 0, 1, "libScePlayerInvitationDialog", g_libScePlayerInvitationDialog_modules, 1}, + {0x115, -1, 0, 4, "libSceNpCppWebApi", g_libSceNpCppWebApi_modules, 42}, + {0x113, -1, 0, 1, "libSceNpEntitlementAccess", g_libSceNpEntitlementAccess_modules, 1}, + {0x8000009a, -1, 0, 2, "libSceNpRemotePlaySessionSignaling", + g_libSceNpRemotePlaySessionSignaling_modules, 76}, + {0x800000b8, -1, 0, 1, "libSceLibreSsl3", g_libSceLibreSsl3_modules, 2}, + {0x800000b1, -1, 0, 1, "libcurl", g_libcurl_modules, 2}, + {0x800000aa, -1, 0, 1, "libicu", g_libicu_modules, 2}, + {0x800000ac, -1, 0, 1, "libcairo", g_libcairo_modules, 9}, + {0x0, -1, 0, 1, "libfontconfig", g_libfontconfig_modules, 1}, + {0x0, -1, 0, 1, "libfreetype", g_libfreetype_modules, 1}, + {0x0, -1, 0, 1, "libharfbuzz", g_libharfbuzz_modules, 1}, + {0x800000ab, -1, 0, 1, "libpng16", g_libpng16_modules, 2}, + {0x12f, -1, 0, 1, "libSceFontGs", g_libSceFontGs_modules, 1}, + {0x800000c0, -1, 0, 1, "libSceGLSlimClientVSH", g_libSceGLSlimClientVSH_modules, 1}, + {0x800000c1, -1, 0, 1, "libSceGLSlimServerVSH", g_libSceGLSlimServerVSH_modules, 1}, + {0x135, -1, 0, 4, "libSceFontGsm", g_libSceFontGsm_modules, 1}, + {0x138, -1, 0, 1, "libSceNpPartnerSubscription", g_libSceNpPartnerSubscription_modules, 1}, + {0x139, -1, 0, 1, "libSceNpAuthAuthorizedAppDialog", g_libSceNpAuthAuthorizedAppDialog_modules, + 1}}); + +} // namespace Libraries::SysModule diff --git a/src/core/libraries/system/sysmodule.cpp b/src/core/libraries/system/sysmodule.cpp deleted file mode 100644 index 50d030065..000000000 --- a/src/core/libraries/system/sysmodule.cpp +++ /dev/null @@ -1,169 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#define MAGIC_ENUM_RANGE_MIN 0 -#define MAGIC_ENUM_RANGE_MAX 300 -#include - -#include "common/logging/log.h" -#include "core/libraries/error_codes.h" -#include "core/libraries/kernel/process.h" -#include "core/libraries/libs.h" -#include "core/libraries/system/sysmodule.h" -#include "core/libraries/system/system_error.h" - -namespace Libraries::SysModule { - -int PS4_SYSV_ABI sceSysmoduleGetModuleHandleInternal() { - LOG_ERROR(Lib_SysModule, "(STUBBED) called"); - return ORBIS_OK; -} - -s32 PS4_SYSV_ABI sceSysmoduleGetModuleInfoForUnwind(VAddr addr, s32 flags, - Kernel::OrbisModuleInfoForUnwind* info) { - LOG_TRACE(Lib_SysModule, "sceSysmoduleGetModuleInfoForUnwind(addr=0x{:X}, flags=0x{:X})", addr, - flags); - - s32 res = Kernel::sceKernelGetModuleInfoForUnwind(addr, flags, info); - if (res != 0) { - return res; - } - - static constexpr std::array modules_to_hide = { - "libc.prx", - "libc.sprx", - "libSceAudioLatencyEstimation.prx", - "libSceFace.prx", - "libSceFaceTracker.prx", - "libSceFios2.prx", - "libSceFios2.sprx", - "libSceFontGsm.prx", - "libSceHand.prx", - "libSceHandTracker.prx", - "libSceHeadTracker.prx", - "libSceJobManager.prx", - "libSceNpCppWebApi.prx", - "libSceNpToolkit.prx", - "libSceNpToolkit2.prx", - "libSceS3DConversion.prx", - "libSceSmart.prx", - }; - - const std::string_view module_name = info->name.data(); - if (std::ranges::find(modules_to_hide, module_name) != modules_to_hide.end()) { - std::ranges::fill(info->name, '\0'); - } - return res; -} - -int PS4_SYSV_ABI sceSysmoduleIsCalledFromSysModule() { - LOG_ERROR(Lib_SysModule, "(STUBBED) called"); - return ORBIS_OK; -} - -int PS4_SYSV_ABI sceSysmoduleIsCameraPreloaded() { - LOG_ERROR(Lib_SysModule, "(STUBBED) called"); - return ORBIS_OK; -} - -int PS4_SYSV_ABI sceSysmoduleIsLoaded(OrbisSysModule id) { - LOG_ERROR(Lib_SysModule, "(DUMMY) called module = {}", magic_enum::enum_name(id)); - if (static_cast(id) == 0) { - LOG_ERROR(Lib_SysModule, "Invalid sysmodule ID: {:#x}", static_cast(id)); - return ORBIS_SYSMODULE_INVALID_ID; - } - return ORBIS_OK; -} - -int PS4_SYSV_ABI sceSysmoduleIsLoadedInternal(OrbisSysModuleInternal id) { - LOG_ERROR(Lib_SysModule, "(DUMMY) called module = {:#x}", static_cast(id)); - if ((static_cast(id) & 0x7FFFFFFF) == 0) { - LOG_ERROR(Lib_SysModule, "Invalid internal sysmodule ID: {:#x}", static_cast(id)); - return ORBIS_SYSMODULE_INVALID_ID; - } - return ORBIS_OK; -} - -int PS4_SYSV_ABI sceSysmoduleLoadModule(OrbisSysModule id) { - LOG_ERROR(Lib_SysModule, "(DUMMY) called module = {}", magic_enum::enum_name(id)); - return ORBIS_OK; -} - -int PS4_SYSV_ABI sceSysmoduleLoadModuleByNameInternal() { - LOG_ERROR(Lib_SysModule, "(STUBBED) called"); - return ORBIS_OK; -} - -int PS4_SYSV_ABI sceSysmoduleLoadModuleInternal() { - LOG_ERROR(Lib_SysModule, "(STUBBED) called"); - return ORBIS_OK; -} - -int PS4_SYSV_ABI sceSysmoduleLoadModuleInternalWithArg() { - LOG_ERROR(Lib_SysModule, "(STUBBED) called"); - return ORBIS_OK; -} - -int PS4_SYSV_ABI sceSysmoduleMapLibcForLibkernel() { - LOG_ERROR(Lib_SysModule, "(STUBBED) called"); - return ORBIS_OK; -} - -int PS4_SYSV_ABI sceSysmodulePreloadModuleForLibkernel() { - LOG_ERROR(Lib_SysModule, "(STUBBED) called"); - return ORBIS_OK; -} - -int PS4_SYSV_ABI sceSysmoduleUnloadModule() { - LOG_ERROR(Lib_SysModule, "(STUBBED) called"); - return ORBIS_OK; -} - -int PS4_SYSV_ABI sceSysmoduleUnloadModuleByNameInternal() { - LOG_ERROR(Lib_SysModule, "(STUBBED) called"); - return ORBIS_OK; -} - -int PS4_SYSV_ABI sceSysmoduleUnloadModuleInternal() { - LOG_ERROR(Lib_SysModule, "(STUBBED) called"); - return ORBIS_OK; -} - -int PS4_SYSV_ABI sceSysmoduleUnloadModuleInternalWithArg() { - LOG_ERROR(Lib_SysModule, "(STUBBED) called"); - return ORBIS_OK; -} - -void RegisterLib(Core::Loader::SymbolsResolver* sym) { - LIB_FUNCTION("D8cuU4d72xM", "libSceSysmodule", 1, "libSceSysmodule", - sceSysmoduleGetModuleHandleInternal); - LIB_FUNCTION("4fU5yvOkVG4", "libSceSysmodule", 1, "libSceSysmodule", - sceSysmoduleGetModuleInfoForUnwind); - LIB_FUNCTION("ctfO7dQ7geg", "libSceSysmodule", 1, "libSceSysmodule", - sceSysmoduleIsCalledFromSysModule); - LIB_FUNCTION("no6T3EfiS3E", "libSceSysmodule", 1, "libSceSysmodule", - sceSysmoduleIsCameraPreloaded); - LIB_FUNCTION("fMP5NHUOaMk", "libSceSysmodule", 1, "libSceSysmodule", sceSysmoduleIsLoaded); - LIB_FUNCTION("ynFKQ5bfGks", "libSceSysmodule", 1, "libSceSysmodule", - sceSysmoduleIsLoadedInternal); - LIB_FUNCTION("g8cM39EUZ6o", "libSceSysmodule", 1, "libSceSysmodule", sceSysmoduleLoadModule); - LIB_FUNCTION("CU8m+Qs+HN4", "libSceSysmodule", 1, "libSceSysmodule", - sceSysmoduleLoadModuleByNameInternal); - LIB_FUNCTION("39iV5E1HoCk", "libSceSysmodule", 1, "libSceSysmodule", - sceSysmoduleLoadModuleInternal); - LIB_FUNCTION("hHrGoGoNf+s", "libSceSysmodule", 1, "libSceSysmodule", - sceSysmoduleLoadModuleInternalWithArg); - LIB_FUNCTION("lZ6RvVl0vo0", "libSceSysmodule", 1, "libSceSysmodule", - sceSysmoduleMapLibcForLibkernel); - LIB_FUNCTION("DOO+zuW1lrE", "libSceSysmodule", 1, "libSceSysmodule", - sceSysmodulePreloadModuleForLibkernel); - LIB_FUNCTION("eR2bZFAAU0Q", "libSceSysmodule", 1, "libSceSysmodule", sceSysmoduleUnloadModule); - LIB_FUNCTION("vpTHmA6Knvg", "libSceSysmodule", 1, "libSceSysmodule", - sceSysmoduleUnloadModuleByNameInternal); - LIB_FUNCTION("vXZhrtJxkGc", "libSceSysmodule", 1, "libSceSysmodule", - sceSysmoduleUnloadModuleInternal); - LIB_FUNCTION("aKa6YfBKZs4", "libSceSysmodule", 1, "libSceSysmodule", - sceSysmoduleUnloadModuleInternalWithArg); -}; - -} // namespace Libraries::SysModule diff --git a/src/core/libraries/system/sysmodule.h b/src/core/libraries/system/sysmodule.h deleted file mode 100644 index 3f1328e4b..000000000 --- a/src/core/libraries/system/sysmodule.h +++ /dev/null @@ -1,194 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2025 shadPS4 Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include "common/types.h" -#include "core/libraries/kernel/process.h" - -namespace Core::Loader { -class SymbolsResolver; -} - -namespace Libraries::SysModule { - -enum class OrbisSysModule : u16 { - ORBIS_SYSMODULE_INVALID = 0x0000, - ORBIS_SYSMODULE_FIBER = 0x0006, // libSceFiber.sprx - ORBIS_SYSMODULE_ULT = 0x0007, // libSceUlt.sprx - ORBIS_SYSMODULE_NGS2 = 0x000B, // libSceNgs2.sprx - ORBIS_SYSMODULE_XML = 0x0017, // libSceXml.sprx - ORBIS_SYSMODULE_NP_UTILITY = 0x0019, // libSceNpUtility.sprx - ORBIS_SYSMODULE_VOICE = 0x001A, // libSceVoice.sprx - ORBIS_SYSMODULE_VOICEQOS = 0x001B, // libSceVoiceQos.sprx - ORBIS_SYSMODULE_NP_MATCHING2 = 0x001C, // libSceNpMatching2.sprx - ORBIS_SYSMODULE_NP_SCORE_RANKING = 0x001E, // libSceNpScoreRanking.sprx - ORBIS_SYSMODULE_RUDP = 0x0021, // libSceRudp.sprx - ORBIS_SYSMODULE_NP_TUS = 0x002C, // libSceNpTus.sprx - ORBIS_SYSMODULE_FACE = 0x0038, // libSceFace.sprx - ORBIS_SYSMODULE_SMART = 0x0039, // libSceSmart.sprx - ORBIS_SYSMODULE_JSON = 0x0080, // libSceJson.sprx - ORBIS_SYSMODULE_GAME_LIVE_STREAMING = 0x0081, // libSceGameLiveStreaming.sprx - ORBIS_SYSMODULE_COMPANION_UTIL = 0x0082, // libSceCompanionUtil.sprx - ORBIS_SYSMODULE_PLAYGO = 0x0083, // libScePlayGo.sprx - ORBIS_SYSMODULE_FONT = 0x0084, // libSceFont.sprx - ORBIS_SYSMODULE_VIDEO_RECORDING = 0x0085, // libSceVideoRecording.sprx - ORBIS_SYSMODULE_S3DCONVERSION = 0x0086, // libSceS3DConversion - ORBIS_SYSMODULE_AUDIODEC = 0x0088, // libSceAudiodec.sprx - ORBIS_SYSMODULE_JPEG_DEC = 0x008A, // libSceJpegDec.sprx - ORBIS_SYSMODULE_JPEG_ENC = 0x008B, // libSceJpegEnc.sprx - ORBIS_SYSMODULE_PNG_DEC = 0x008C, // libScePngDec.sprx - ORBIS_SYSMODULE_PNG_ENC = 0x008D, // libScePngEnc.sprx - ORBIS_SYSMODULE_VIDEODEC = 0x008E, // libSceVideodec.sprx - ORBIS_SYSMODULE_MOVE = 0x008F, // libSceMove.sprx - ORBIS_SYSMODULE_PAD_TRACKER = 0x0091, // libScePadTracker.sprx - ORBIS_SYSMODULE_DEPTH = 0x0092, // libSceDepth.sprx - ORBIS_SYSMODULE_HAND = 0x0093, // libSceHand.sprx - ORBIS_SYSMODULE_LIBIME = 0x0095, // libSceIme.sprx - ORBIS_SYSMODULE_IME_DIALOG = 0x0096, // libSceImeDialog.sprx - ORBIS_SYSMODULE_NP_PARTY = 0x0097, // libSceNpParty.sprx - ORBIS_SYSMODULE_FONT_FT = 0x0098, // libSceFontFt.sprx - ORBIS_SYSMODULE_FREETYPE_OT = 0x0099, // libSceFreeTypeOt.sprx - ORBIS_SYSMODULE_FREETYPE_OL = 0x009A, // libSceFreeTypeOl.sprx - ORBIS_SYSMODULE_FREETYPE_OPT_OL = 0x009B, // libSceFreeTypeOptOl.sprx - ORBIS_SYSMODULE_SCREEN_SHOT = 0x009C, // libSceScreenShot.sprx - ORBIS_SYSMODULE_NP_AUTH = 0x009D, // libSceNpAuth.sprx - ORBIS_SYSMODULE_SULPHA = 0x009F, - ORBIS_SYSMODULE_SAVE_DATA_DIALOG = 0x00A0, // libSceSaveDataDialog.sprx - ORBIS_SYSMODULE_INVITATION_DIALOG = 0x00A2, // libSceInvitationDialog.sprx - ORBIS_SYSMODULE_DEBUG_KEYBOARD = 0x00A3, - ORBIS_SYSMODULE_MESSAGE_DIALOG = 0x00A4, // libSceMsgDialog.sprx - ORBIS_SYSMODULE_AV_PLAYER = 0x00A5, // libSceAvPlayer.sprx - ORBIS_SYSMODULE_CONTENT_EXPORT = 0x00A6, // libSceContentExport.sprx - ORBIS_SYSMODULE_AUDIO_3D = 0x00A7, // libSceAudio3d.sprx - ORBIS_SYSMODULE_NP_COMMERCE = 0x00A8, // libSceNpCommerce.sprx - ORBIS_SYSMODULE_MOUSE = 0x00A9, // libSceMouse.sprx - ORBIS_SYSMODULE_COMPANION_HTTPD = 0x00AA, // libSceCompanionHttpd.sprx - ORBIS_SYSMODULE_WEB_BROWSER_DIALOG = 0x00AB, // libSceWebBrowserDialog.sprx - ORBIS_SYSMODULE_ERROR_DIALOG = 0x00AC, // libSceErrorDialog.sprx - ORBIS_SYSMODULE_NP_TROPHY = 0x00AD, // libSceNpTrophy.sprx - ORBIS_SYSMODULE_VIDEO_CORE_IF = 0x00AE, // libSceVideoCoreInterface.sprx - ORBIS_SYSMODULE_VIDEO_CORE_SERVER_IF = 0x00AF, // libSceVideoCoreServerInterface.sprx - ORBIS_SYSMODULE_NP_SNS_FACEBOOK = 0x00B0, // libSceNpSnsFacebookDialog.sprx - ORBIS_SYSMODULE_MOVE_TRACKER = 0x00B1, // libSceMoveTracker.sprx - ORBIS_SYSMODULE_NP_PROFILE_DIALOG = 0x00B2, // libSceNpProfileDialog.sprx - ORBIS_SYSMODULE_NP_FRIEND_LIST_DIALOG = 0x00B3, // libSceNpFriendListDialog.sprx - ORBIS_SYSMODULE_APP_CONTENT = 0x00B4, // libSceAppContent.sprx - ORBIS_SYSMODULE_NP_SIGNALING = 0x00B5, // libSceNpSignaling.sprx - ORBIS_SYSMODULE_REMOTE_PLAY = 0x00B6, // libSceRemoteplay.sprx - ORBIS_SYSMODULE_USBD = 0x00B7, // libSceUsbd.sprx - ORBIS_SYSMODULE_GAME_CUSTOM_DATA_DIALOG = 0x00B8, // libSceGameCustomDataDialog.sprx - ORBIS_SYSMODULE_NP_EULA_DIALOG = 0x00B9, // libSceNpEulaDialog.sprx - ORBIS_SYSMODULE_RANDOM = 0x00BA, // libSceRandom.sprx - ORBIS_SYSMODULE_RESERVED2 = 0x00BB, - ORBIS_SYSMODULE_M4AAC_ENC = 0x00BC, // libSceM4aacEnc.sprx - ORBIS_SYSMODULE_AUDIODEC_CPU = 0x00BD, // libSceAudiodecCpu.sprx - ORBIS_SYSMODULE_AUDIODEC_CPU_DDP = 0x00BE, // libSceAudiodecCpuDdp.sprx - ORBIS_SYSMODULE_AUDIODEC_CPU_M4AAC = 0x00C0, // libSceAudiodecCpuM4aac.sprx - ORBIS_SYSMODULE_BEMP2_SYS = 0x00C1, // libSceBemp2sys.sprx - ORBIS_SYSMODULE_BEISOBMF = 0x00C2, // libSceBeisobmf.sprx - ORBIS_SYSMODULE_PLAY_READY = 0x00C3, // libScePlayReady.sprx - ORBIS_SYSMODULE_VIDEO_NATIVE_EXT_ESSENTIAL = 0x00C4, // libSceVideoNativeExtEssential.sprx - ORBIS_SYSMODULE_ZLIB = 0x00C5, // libSceZlib.sprx - ORBIS_SYSMODULE_DTCP_IP = 0x00C6, // libSceDtcpIp.sprx - ORBIS_SYSMODULE_CONTENT_SEARCH = 0x00C7, // libSceContentSearch.sprx - ORBIS_SYSMODULE_SHARE_UTILITY = 0x00C8, // libSceShareUtility.sprx - ORBIS_SYSMODULE_AUDIODEC_CPU_DTS_HD_LBR = 0x00C9, // libSceAudiodecCpuDtsHdLbr.sprx - ORBIS_SYSMODULE_DECI4H = 0x00CA, - ORBIS_SYSMODULE_HEAD_TRACKER = 0x00CB, // libSceHeadTracker.sprx - ORBIS_SYSMODULE_GAME_UPDATE = 0x00CC, // libSceGameUpdate.sprx - ORBIS_SYSMODULE_AUTO_MOUNTER_CLIENT = 0x00CD, // libSceAutoMounterClient.sprx - ORBIS_SYSMODULE_SYSTEM_GESTURE = 0x00CE, // libSceSystemGesture.sprx - ORBIS_SYSMODULE_VIDEODEC2 = 0x00CF, // libSceVideodec2.sprx - ORBIS_SYSMODULE_VDECWRAP = 0x00D0, // libSceVdecwrap.sprx - ORBIS_SYSMODULE_AT9_ENC = 0x00D1, // libSceAt9Enc.sprx - ORBIS_SYSMODULE_CONVERT_KEYCODE = 0x00D2, // libSceConvertKeycode.sprx - ORBIS_SYSMODULE_SHARE_PLAY = 0x00D3, // libSceSharePlay.sprx - ORBIS_SYSMODULE_HMD = 0x00D4, // libSceHmd.sprx - ORBIS_SYSMODULE_USB_STORAGE = 0x00D5, // libSceUsbStorage.sprx - ORBIS_SYSMODULE_USB_STORAGE_DIALOG = 0x00D6, // libSceUsbStorageDialog.sprx - ORBIS_SYSMODULE_DISC_MAP = 0x00D7, // libSceDiscMap.sprx - ORBIS_SYSMODULE_FACE_TRACKER = 0x00D8, // libSceFaceTracker.sprx - ORBIS_SYSMODULE_HAND_TRACKER = 0x00D9, // libSceHandTracker.sprx - ORBIS_SYSMODULE_NP_SNS_YOUTUBE_DIALOG = 0x00DA, // libSceNpSnsYouTubeDialog.sprx - ORBIS_SYSMODULE_PROFILE_CACHE_EXTERNAL = 0x00DC, // libSceProfileCacheExternal.sprx - ORBIS_SYSMODULE_MUSIC_PLAYER_SERVICE = 0x00DD, // libSceMusicPlayerService.sprx - ORBIS_SYSMODULE_SP_SYS_CALL_WRAPPER = 0x00DE, // libSceSpSysCallWrapper.sprx - ORBIS_SYSMODULE_PS2_EMU_MENU_DIALOG = 0x00DF, // libScePs2EmuMenuDialog.sprx - ORBIS_SYSMODULE_NP_SNS_DAILYMOTION_DIALOG = 0x00E0, // libSceNpSnsDailyMotionDialog.sprx - ORBIS_SYSMODULE_AUDIODEC_CPU_HEVAG = 0x00E1, // libSceAudiodecCpuHevag.sprx - ORBIS_SYSMODULE_LOGIN_DIALOG = 0x00E2, // libSceLoginDialog.sprx - ORBIS_SYSMODULE_LOGIN_SERVICE = 0x00E3, // libSceLoginService.sprx - ORBIS_SYSMODULE_SIGNIN_DIALOG = 0x00E4, // libSceSigninDialog.sprx - ORBIS_SYSMODULE_VDECSW = 0x00E5, // libSceVdecsw.sprx - ORBIS_SYSMODULE_CUSTOM_MUSIC_CORE = 0x00E6, // libSceCustomMusicCore.sprx - ORBIS_SYSMODULE_JSON2 = 0x00E7, // libSceJson2.sprx - ORBIS_SYSMODULE_AUDIO_LATENCY_ESTIMATION = 0x00E8, // libSceAudioLatencyEstimation.sprx - ORBIS_SYSMODULE_WK_FONT_CONFIG = 0x00E9, // libSceWkFontConfig.sprx - ORBIS_SYSMODULE_VORBIS_DEC = 0x00EA, // libSceVorbisDec.sprx - ORBIS_SYSMODULE_HMD_SETUP_DIALOG = 0x00EB, // libSceHmdSetupDialog.sprx - ORBIS_SYSMODULE_RESERVED28 = 0x00EC, - ORBIS_SYSMODULE_VR_TRACKER = 0x00ED, // libSceVrTracker.sprx - ORBIS_SYSMODULE_CONTENT_DELETE = 0x00EE, // libSceContentDelete.sprx - ORBIS_SYSMODULE_IME_BACKEND = 0x00EF, // libSceImeBackend.sprx - ORBIS_SYSMODULE_NET_CTL_AP_DIALOG = 0x00F0, // libSceNetCtlApDialog.sprx - ORBIS_SYSMODULE_PLAYGO_DIALOG = 0x00F1, // libScePlayGoDialog.sprx - ORBIS_SYSMODULE_SOCIAL_SCREEN = 0x00F2, // libSceSocialScreen.sprx - ORBIS_SYSMODULE_EDIT_MP4 = 0x00F3, // libSceEditMp4.sprx - ORBIS_SYSMODULE_PSM_KIT_SYSTEM = 0x00F5, // libScePsmKitSystem.sprx - ORBIS_SYSMODULE_TEXT_TO_SPEECH = 0x00F6, // libSceTextToSpeech.sprx - ORBIS_SYSMODULE_NP_TOOLKIT = 0x00F7, // libSceNpToolkit.sprx - ORBIS_SYSMODULE_CUSTOM_MUSIC_SERVICE = 0x00F8, // libSceCustomMusicService.sprx - ORBIS_SYSMODULE_CL_SYS_CALL_WRAPPER = 0x00F9, // libSceClSysCallWrapper.sprx - ORBIS_SYSMODULE_SYSTEM_LOGGER = 0x00FA, // libSceSystemLogger.sprx - ORBIS_SYSMODULE_BLUETOOTH_HID = 0x00FB, // libSceBluetoothHid.sprx - ORBIS_SYSMODULE_VIDEO_DECODER_ARBITRATION = 0x00FC, // libSceVideoDecoderArbitration.sprx - ORBIS_SYSMODULE_VR_SERVICE_DIALOG = 0x00FD, // libSceVrServiceDialog.sprx - ORBIS_SYSMODULE_JOB_MANAGER = 0x00FE, // libSceJobManager.sprx - ORBIS_SYSMODULE_SHARE_FACTORY_UTIL = 0x00FF, // libSceShareFactoryUtil.sprx - ORBIS_SYSMODULE_SOCIAL_SCREEN_DIALOG = 0x0100, // libSceSocialScreenDialog.sprx - ORBIS_SYSMODULE_NP_SNS_DIALOG = 0x0101, // libSceNpSnsDialog.sprx - ORBIS_SYSMODULE_NP_TOOLKIT2 = 0x0102, // libSceNpToolkit2.sprx - ORBIS_SYSMODULE_SRC_UTL = 0x0103, // libSceSrcUtl.sprx - ORBIS_SYSMODULE_DISC_ID = 0x0104, // libSceDiscId.sprx - ORBIS_SYSMODULE_NP_UNIVERSAL_DATA_SYSTEM = 0x0105, // libSceNpUniversalDataSystem.sprx - ORBIS_SYSMODULE_KEYBOARD = 0x0106, // libSceKeyboard.sprx - ORBIS_SYSMODULE_GIC = 0x0107, // libSceGic.sprx - ORBIS_SYSMODULE_PLAY_READY2 = 0x0108, // libScePlayReady2.sprx - ORBIS_SYSMODULE_CES_CS = 0x010c, // libSceCesCs.sprx - ORBIS_SYSMODULE_PLAYER_INVITATION_DIALOG = 0x010d, // libScePlayerInvitationDialog.sprx - ORBIS_SYSMODULE_NP_SESSION_SIGNALING = 0x0112, // libSceNpSessionSignaling.sprx - ORBIS_SYSMODULE_NP_ENTITLEMENT_ACCESS = 0x0113, // libSceNpEntitlementAccess.sprx - ORBIS_SYSMODULE_NP_CPP_WEB_API = 0x0115, // libSceNpCppWebApi.sprx - ORBIS_SYSMODULE_HUB_APP_UTIL = 0x0116, // libSceHubAppUtil.sprx - ORBIS_SYSMODULE_NP_PARTNER001 = 0x011a, // libSceNpPartner001.sprx - ORBIS_SYSMODULE_FONT_GS = 0x012f, // libSceFontGs.sprx - ORBIS_SYSMODULE_FONT_GSM = 0x0135, // libSceFontGsm.sprx - ORBIS_SYSMODULE_NP_PARTNER_SUBSCRIPTION = 0x0138, // libSceNpPartnerSubscription.sprx - ORBIS_SYSMODULE_NP_AUTH_AUTHORIZED_APP_DIALOG = 0x0139, // libSceNpAuthAuthorizedAppDialog.sprx -}; - -enum class OrbisSysModuleInternal : u32 { - ORBIS_SYSMODULE_INTERNAL_RAZOR_CPU = 0x80000019, // libSceRazorCpu.sprx -}; - -int PS4_SYSV_ABI sceSysmoduleGetModuleHandleInternal(); -s32 PS4_SYSV_ABI sceSysmoduleGetModuleInfoForUnwind(VAddr addr, s32 flags, - Kernel::OrbisModuleInfoForUnwind* info); -int PS4_SYSV_ABI sceSysmoduleIsCalledFromSysModule(); -int PS4_SYSV_ABI sceSysmoduleIsCameraPreloaded(); -int PS4_SYSV_ABI sceSysmoduleIsLoaded(OrbisSysModule id); -int PS4_SYSV_ABI sceSysmoduleIsLoadedInternal(OrbisSysModuleInternal id); -int PS4_SYSV_ABI sceSysmoduleLoadModule(OrbisSysModule id); -int PS4_SYSV_ABI sceSysmoduleLoadModuleByNameInternal(); -int PS4_SYSV_ABI sceSysmoduleLoadModuleInternal(); -int PS4_SYSV_ABI sceSysmoduleLoadModuleInternalWithArg(); -int PS4_SYSV_ABI sceSysmoduleMapLibcForLibkernel(); -int PS4_SYSV_ABI sceSysmodulePreloadModuleForLibkernel(); -int PS4_SYSV_ABI sceSysmoduleUnloadModule(); -int PS4_SYSV_ABI sceSysmoduleUnloadModuleByNameInternal(); -int PS4_SYSV_ABI sceSysmoduleUnloadModuleInternal(); -int PS4_SYSV_ABI sceSysmoduleUnloadModuleInternalWithArg(); - -void RegisterLib(Core::Loader::SymbolsResolver* sym); -} // namespace Libraries::SysModule diff --git a/src/core/libraries/system/system_error.h b/src/core/libraries/system/system_error.h deleted file mode 100644 index 615e4cd5f..000000000 --- a/src/core/libraries/system/system_error.h +++ /dev/null @@ -1,8 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -constexpr int ORBIS_SYSMODULE_INVALID_ID = 0x805A1000; -constexpr int ORBIS_SYSMODULE_NOT_LOADED = 0x805A1001; -constexpr int ORBIS_SYSMODULE_LOCK_FAILED = 0x805A10FF; \ No newline at end of file diff --git a/src/core/linker.cpp b/src/core/linker.cpp index 0b80ecacc..d0d682043 100644 --- a/src/core/linker.cpp +++ b/src/core/linker.cpp @@ -16,6 +16,7 @@ #include "core/libraries/kernel/kernel.h" #include "core/libraries/kernel/memory.h" #include "core/libraries/kernel/threads.h" +#include "core/libraries/sysmodule/sysmodule.h" #include "core/linker.h" #include "core/memory.h" #include "core/tls.h" @@ -110,7 +111,8 @@ void Linker::Execute(const std::vector& args) { ipc.WaitForStart(); } - LoadSharedLibraries(); + // Have libSceSysmodule preload our libraries. + Libraries::SysModule::sceSysmodulePreloadModuleForLibkernel(); // Simulate libSceGnmDriver initialization, which maps a chunk of direct memory. // Some games fail without accurately emulating this behavior. @@ -350,8 +352,8 @@ bool Linker::Resolve(const std::string& name, Loader::SymbolType sym_type, Modul return_info->virtual_address = AeroLib::GetStub(sr.name.c_str()); return_info->name = "Unknown !!!"; } - LOG_ERROR(Core_Linker, "Linker: Stub resolved {} as {} (lib: {}, mod: {})", sr.name, - return_info->name, library->name, module->name); + LOG_WARNING(Core_Linker, "Linker: Stub resolved {} as {} (lib: {}, mod: {})", sr.name, + return_info->name, library->name, module->name); return false; } diff --git a/src/emulator.cpp b/src/emulator.cpp index 18d3024dc..cc862f8ab 100644 --- a/src/emulator.cpp +++ b/src/emulator.cpp @@ -32,17 +32,9 @@ #include "core/file_format/psf.h" #include "core/file_format/trp.h" #include "core/file_sys/fs.h" -#include "core/libraries/disc_map/disc_map.h" -#include "core/libraries/font/font.h" -#include "core/libraries/font/fontft.h" -#include "core/libraries/jpeg/jpegenc.h" #include "core/libraries/kernel/kernel.h" -#include "core/libraries/libc_internal/libc_internal.h" -#include "core/libraries/libpng/pngenc.h" #include "core/libraries/libs.h" -#include "core/libraries/ngs2/ngs2.h" #include "core/libraries/np/np_trophy.h" -#include "core/libraries/rtc/rtc.h" #include "core/libraries/save_data/save_backup.h" #include "core/linker.h" #include "core/memory.h" @@ -405,17 +397,6 @@ void Emulator::Run(std::filesystem::path file, std::vector args, std::quick_exit(0); } - // check if we have system modules to load - LoadSystemModules(game_info.game_serial); - - // Load all prx from game's sce_module folder - mnt->IterateDirectory("/app0/sce_module", [this](const auto& path, const auto is_file) { - if (is_file) { - LOG_INFO(Loader, "Loading {}", fmt::UTF(path.u8string())); - linker->LoadModule(path); - } - }); - #ifdef ENABLE_DISCORD_RPC // Discord RPC if (Config::getEnableDiscordRPC()) { @@ -556,54 +537,6 @@ void Emulator::Restart(std::filesystem::path eboot_path, std::quick_exit(0); } -void Emulator::LoadSystemModules(const std::string& game_serial) { - constexpr auto ModulesToLoad = std::to_array( - {{"libSceNgs2.sprx", &Libraries::Ngs2::RegisterLib}, - {"libSceUlt.sprx", nullptr}, - {"libSceRtc.sprx", &Libraries::Rtc::RegisterLib}, - {"libSceJpegDec.sprx", nullptr}, - {"libSceJpegEnc.sprx", &Libraries::JpegEnc::RegisterLib}, - {"libScePngEnc.sprx", &Libraries::PngEnc::RegisterLib}, - {"libSceJson.sprx", nullptr}, - {"libSceJson2.sprx", nullptr}, - {"libSceLibcInternal.sprx", &Libraries::LibcInternal::RegisterLib}, - {"libSceCesCs.sprx", nullptr}, - {"libSceAudiodec.sprx", nullptr}, - {"libSceFont.sprx", &Libraries::Font::RegisterlibSceFont}, - {"libSceFontFt.sprx", &Libraries::FontFt::RegisterlibSceFontFt}, - {"libSceFreeTypeOt.sprx", nullptr}}); - - std::vector found_modules; - const auto& sys_module_path = Config::getSysModulesPath(); - for (const auto& entry : std::filesystem::directory_iterator(sys_module_path)) { - found_modules.push_back(entry.path()); - } - for (const auto& [module_name, init_func] : ModulesToLoad) { - const auto it = std::ranges::find_if( - found_modules, [&](const auto& path) { return path.filename() == module_name; }); - if (it != found_modules.end()) { - LOG_INFO(Loader, "Loading {}", it->string()); - if (linker->LoadModule(*it) != -1) { - continue; - } - } - if (init_func) { - LOG_INFO(Loader, "Can't Load {} switching to HLE", module_name); - init_func(&linker->GetHLESymbols()); - } else { - LOG_INFO(Loader, "No HLE available for {} module", module_name); - } - } - if (!game_serial.empty() && std::filesystem::exists(sys_module_path / game_serial)) { - for (const auto& entry : - std::filesystem::directory_iterator(sys_module_path / game_serial)) { - LOG_INFO(Loader, "Loading {} from game serial file {}", entry.path().string(), - game_serial); - linker->LoadModule(entry.path()); - } - } -} - void Emulator::UpdatePlayTime(const std::string& serial) { const auto user_dir = Common::FS::GetUserPath(Common::FS::PathType::UserDir); const auto filePath = (user_dir / "play_time.txt").string(); From 0579569f139bd1da3d356d529a41b044e0f1eb77 Mon Sep 17 00:00:00 2001 From: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com> Date: Mon, 9 Mar 2026 13:20:14 +0100 Subject: [PATCH 4/7] Improve signal emulation (#4108) * improve signal emulation * make the sce function use the new posix ones * ifdefing away the issues * fix me being very tired yesterday night * let macOS handle SIGRT signals with the native sigaction call instead of an early error return * windows still has no clue what the fuck is going on * the loathsome clang-formatter * fix oact * return the guest handler, not the host one * Clear any existing signal mask for game threads. * don't rely on implementation specific things * Fix Windows support and sceKernelRaiseException bug * Review suggestions @kalaposfos13 suggested I push these. --------- Co-authored-by: Stephen Miller <56742918+StevenMiller123@users.noreply.github.com> --- src/core/cpu_patches.cpp | 13 +- .../libraries/kernel/threads/exception.cpp | 236 +++++++++++++----- src/core/libraries/kernel/threads/exception.h | 82 +++++- src/core/libraries/kernel/threads/pthread.cpp | 1 + src/core/linker.cpp | 9 + src/core/signals.cpp | 6 +- src/core/signals.h | 4 +- 7 files changed, 277 insertions(+), 74 deletions(-) diff --git a/src/core/cpu_patches.cpp b/src/core/cpu_patches.cpp index e303417c3..f6a4f7620 100644 --- a/src/core/cpu_patches.cpp +++ b/src/core/cpu_patches.cpp @@ -788,14 +788,11 @@ static bool PatchesIllegalInstructionHandler(void* context) { ZydisDecodedOperand operands[ZYDIS_MAX_OPERAND_COUNT]; const auto status = Common::Decoder::Instance()->decodeInstruction(instruction, operands, code_address); - if (ZYAN_SUCCESS(status) && instruction.mnemonic == ZydisMnemonic::ZYDIS_MNEMONIC_UD2) - [[unlikely]] { - UNREACHABLE_MSG("ud2 at code address {:#x}", reinterpret_cast(code_address)); - } - UNREACHABLE_MSG("Failed to patch address {:x} -- mnemonic: {}", - reinterpret_cast(code_address), - ZYAN_SUCCESS(status) ? ZydisMnemonicGetString(instruction.mnemonic) - : "Failed to decode"); + LOG_ERROR(Core, "Failed to patch address {:x} -- mnemonic: {}", + reinterpret_cast(code_address), + ZYAN_SUCCESS(status) ? ZydisMnemonicGetString(instruction.mnemonic) + : "Failed to decode"); + return false; } } diff --git a/src/core/libraries/kernel/threads/exception.cpp b/src/core/libraries/kernel/threads/exception.cpp index 247c387fe..e2fd032f5 100644 --- a/src/core/libraries/kernel/threads/exception.cpp +++ b/src/core/libraries/kernel/threads/exception.cpp @@ -2,7 +2,9 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include "common/assert.h" +#include "core/libraries/kernel/kernel.h" #include "core/libraries/kernel/orbis_error.h" +#include "core/libraries/kernel/posix_error.h" #include "core/libraries/kernel/threads/exception.h" #include "core/libraries/kernel/threads/pthread.h" #include "core/libraries/libs.h" @@ -13,23 +15,24 @@ #else #include #endif +#include namespace Libraries::Kernel { #ifdef _WIN32 // Windows doesn't have native versions of these, and we don't need to use them either. -static s32 NativeToOrbisSignal(s32 s) { +s32 NativeToOrbisSignal(s32 s) { return s; } -static s32 OrbisToNativeSignal(s32 s) { +s32 OrbisToNativeSignal(s32 s) { return s; } #else -static s32 NativeToOrbisSignal(s32 s) { +s32 NativeToOrbisSignal(s32 s) { switch (s) { case SIGHUP: return POSIX_SIGHUP; @@ -89,12 +92,21 @@ static s32 NativeToOrbisSignal(s32 s) { return POSIX_SIGUSR1; case SIGUSR2: return POSIX_SIGUSR2; + case _SIGEMT: + return POSIX_SIGEMT; + case _SIGINFO: + return POSIX_SIGINFO; + case 0: + return 128; default: + if (s > 0 && s < 128) { + return s; + } UNREACHABLE_MSG("Unknown signal {}", s); } } -static s32 OrbisToNativeSignal(s32 s) { +s32 OrbisToNativeSignal(s32 s) { switch (s) { case POSIX_SIGHUP: return SIGHUP; @@ -108,6 +120,8 @@ static s32 OrbisToNativeSignal(s32 s) { return SIGTRAP; case POSIX_SIGABRT: return SIGABRT; + case POSIX_SIGEMT: + return _SIGEMT; case POSIX_SIGFPE: return SIGFPE; case POSIX_SIGKILL: @@ -150,22 +164,33 @@ static s32 OrbisToNativeSignal(s32 s) { return SIGPROF; case POSIX_SIGWINCH: return SIGWINCH; + case POSIX_SIGINFO: + return _SIGINFO; case POSIX_SIGUSR1: return SIGUSR1; case POSIX_SIGUSR2: return SIGUSR2; + case 128: + return 0; default: + if (s > 0 && s < 128) { + return s; + } UNREACHABLE_MSG("Unknown signal {}", s); } } #endif -std::array Handlers{}; +#ifdef __APPLE__ +#define sigisemptyset(x) (*(x) == 0) +#endif + +std::array Handlers{}; #ifndef _WIN64 void SigactionHandler(int native_signum, siginfo_t* inf, ucontext_t* raw_context) { - const auto handler = Handlers[native_signum]; + const auto handler = Handlers[NativeToOrbisSignal(native_signum)]; if (handler) { auto ctx = Ucontext{}; #ifdef __APPLE__ @@ -214,6 +239,8 @@ void SigactionHandler(int native_signum, siginfo_t* inf, ucontext_t* raw_context ctx.uc_mcontext.mc_addr = reinterpret_cast(inf->si_addr); #endif handler(NativeToOrbisSignal(native_signum), &ctx); + } else { + UNREACHABLE_MSG("Unhandled exception"); } } #else @@ -221,7 +248,7 @@ void ExceptionHandler(void* arg1, void* arg2, void* arg3, PCONTEXT context) { const char* thrName = (char*)arg1; int native_signum = reinterpret_cast(arg2); LOG_INFO(Lib_Kernel, "Exception raised successfully on thread '{}'", thrName); - const auto handler = Handlers[native_signum]; + const auto handler = Handlers[NativeToOrbisSignal(native_signum)]; if (handler) { auto ctx = Ucontext{}; ctx.uc_mcontext.mc_r8 = context->R8; @@ -243,76 +270,105 @@ void ExceptionHandler(void* arg1, void* arg2, void* arg3, PCONTEXT context) { ctx.uc_mcontext.mc_fs = context->SegFs; ctx.uc_mcontext.mc_gs = context->SegGs; handler(NativeToOrbisSignal(native_signum), &ctx); + } else { + UNREACHABLE_MSG("Unhandled exception"); } } #endif -int PS4_SYSV_ABI sceKernelInstallExceptionHandler(s32 signum, SceKernelExceptionHandler handler) { - if (signum > POSIX_SIGUSR2) { - return ORBIS_KERNEL_ERROR_EINVAL; +s32 PS4_SYSV_ABI posix_sigemptyset(Sigset* s) { + s->bits[0] = 0; + s->bits[1] = 0; + return 0; +} + +bool PS4_SYSV_ABI posix_sigisemptyset(Sigset* s) { + return s->bits[0] == 0 && s->bits[1] == 0; +} + +s32 PS4_SYSV_ABI posix_sigaction(s32 sig, Sigaction* act, Sigaction* oact) { + if (sig < 1 || sig > 128 || sig == POSIX_SIGTHR || sig == POSIX_SIGKILL || + sig == POSIX_SIGSTOP) { + *__Error() = POSIX_EINVAL; + return ORBIS_FAIL; + } +#ifdef _WIN32 + LOG_ERROR(Lib_Kernel, "(STUBBED) called, sig: {}", sig); + Handlers[sig] = reinterpret_cast( + act ? act->__sigaction_handler.sigaction : nullptr); +#else + s32 native_sig = OrbisToNativeSignal(sig); + if (native_sig == SIGVTALRM) { + LOG_ERROR(Lib_Kernel, "Guest is attempting to use the HLE-reserved signal {}!", sig); + *__Error() = POSIX_EINVAL; + return ORBIS_FAIL; + } +#ifndef __APPLE__ + if (native_sig >= __SIGRTMIN && native_sig < SIGRTMIN) { + LOG_ERROR(Lib_Kernel, "Guest is attempting to use the HLE libc-reserved signal {}!", sig); + *__Error() = POSIX_EINVAL; + return ORBIS_FAIL; + } +#else + if (native_sig > SIGUSR2) { + LOG_ERROR(Lib_Kernel, + "Guest is attempting to use SIGRT signals, which aren't available on this " + "platform (signal: {})!", + sig); } - LOG_INFO(Lib_Kernel, "Installing signal handler for {}", signum); - int const native_signum = OrbisToNativeSignal(signum); -#ifdef __APPLE__ - ASSERT_MSG(native_signum != SIGVTALRM, "SIGVTALRM is HLE-reserved on macOS!"); #endif - ASSERT_MSG(!Handlers[native_signum], "Invalid parameters"); - Handlers[native_signum] = handler; -#ifndef _WIN64 - if (native_signum == SIGSEGV || native_signum == SIGBUS || native_signum == SIGILL) { + LOG_INFO(Lib_Kernel, "called, sig: {}, native sig: {}", sig, native_sig); + struct sigaction native_act{}; + if (act) { + native_act.sa_flags = act->sa_flags; // todo check compatibility, on Linux it seems fine + native_act.sa_sigaction = + reinterpret_cast(SigactionHandler); + if (!posix_sigisemptyset(&act->sa_mask)) { + LOG_ERROR(Lib_Kernel, "Unhandled sa_mask: {:x}", act->sa_mask.bits[0]); + } + } + auto const prev_handler = Handlers[sig]; + Handlers[sig] = reinterpret_cast( + act ? act->__sigaction_handler.sigaction : nullptr); + + if (native_sig == SIGSEGV || native_sig == SIGBUS || native_sig == SIGILL) { return ORBIS_OK; // These are handled in Core::SignalHandler } - struct sigaction act = {}; - act.sa_flags = SA_SIGINFO | SA_RESTART; - act.sa_sigaction = reinterpret_cast(SigactionHandler); - sigemptyset(&act.sa_mask); - sigaction(native_signum, &act, nullptr); -#endif - return ORBIS_OK; -} - -int PS4_SYSV_ABI sceKernelRemoveExceptionHandler(s32 signum) { - if (signum > POSIX_SIGUSR2) { - return ORBIS_KERNEL_ERROR_EINVAL; + if (native_sig > 127) { + LOG_WARNING(Lib_Kernel, "We can't install a handler for native signal {}!", native_sig); + return ORBIS_OK; } - int const native_signum = OrbisToNativeSignal(signum); - if (!Handlers[native_signum]) { - LOG_WARNING(Lib_Kernel, "removing non-installed handler for signum {}", signum); - return ORBIS_KERNEL_ERROR_EINVAL; + struct sigaction native_oact{}; + s32 ret = sigaction(native_sig, act ? &native_act : nullptr, oact ? &native_oact : nullptr); + if (oact) { + oact->sa_flags = native_oact.sa_flags; + oact->__sigaction_handler.sigaction = + reinterpret_cast__sigaction_handler.sigaction)>(prev_handler); + if (!sigisemptyset(&native_oact.sa_mask)) { + LOG_ERROR(Lib_Kernel, "Unhandled sa_mask"); + } } - Handlers[native_signum] = nullptr; -#ifndef _WIN64 - if (native_signum == SIGSEGV || native_signum == SIGBUS || native_signum == SIGILL) { - struct sigaction action{}; - action.sa_sigaction = Core::SignalHandler; - action.sa_flags = SA_SIGINFO | SA_ONSTACK; - sigemptyset(&action.sa_mask); - - ASSERT_MSG(sigaction(native_signum, &action, nullptr) == 0, - "Failed to reinstate original signal handler for signal {}", native_signum); - } else { - struct sigaction act = {}; - act.sa_flags = SA_SIGINFO | SA_RESTART; - act.sa_sigaction = nullptr; - sigemptyset(&act.sa_mask); - sigaction(native_signum, &act, nullptr); + if (ret < 0) { + LOG_ERROR(Lib_Kernel, "sigaction failed: {}", strerror(errno)); + *__Error() = ErrnoToSceKernelError(errno); + return ORBIS_FAIL; } #endif return ORBIS_OK; } -int PS4_SYSV_ABI sceKernelRaiseException(PthreadT thread, int signum) { - if (signum != POSIX_SIGUSR1) { - return ORBIS_KERNEL_ERROR_EINVAL; +s32 PS4_SYSV_ABI posix_pthread_kill(PthreadT thread, s32 sig) { + if (sig < 1 || sig > 128) { // off-by-one error? + return POSIX_EINVAL; } - LOG_WARNING(Lib_Kernel, "Raising exception on thread '{}'", thread->name); - int const native_signum = OrbisToNativeSignal(signum); + LOG_WARNING(Lib_Kernel, "Raising signal {} on thread '{}'", sig, thread->name); + int const native_signum = OrbisToNativeSignal(sig); #ifndef _WIN64 const auto pthr = reinterpret_cast(thread->native_thr.GetHandle()); const auto ret = pthread_kill(pthr, native_signum); if (ret != 0) { LOG_ERROR(Kernel, "Failed to send exception signal to thread '{}': {}", thread->name, - strerror(ret)); + strerror(errno)); } #else USER_APC_OPTION option; @@ -326,6 +382,67 @@ int PS4_SYSV_ABI sceKernelRaiseException(PthreadT thread, int signum) { return ORBIS_OK; } +// libkernel has a check in sceKernelInstallExceptionHandler and sceKernelRemoveExceptionHandler for +// validating if the application requested a handler for an allowed signal or not. However, that is +// just a wrapper for sigaction, which itself does not have any such restrictions, and therefore +// this check is ridiculously trivial to go around. This, however, means that we need to support all +// 127 - 3 possible signals, even if realistically, only homebrew will use most of them. +static std::unordered_set orbis_allowed_signals{ + POSIX_SIGHUP, POSIX_SIGILL, POSIX_SIGFPE, POSIX_SIGBUS, POSIX_SIGSEGV, POSIX_SIGUSR1, +}; + +int PS4_SYSV_ABI sceKernelInstallExceptionHandler(s32 signum, OrbisKernelExceptionHandler handler) { + if (!orbis_allowed_signals.contains(signum)) { + return ORBIS_KERNEL_ERROR_EINVAL; + } + if (Handlers[signum] != nullptr) { + return ORBIS_KERNEL_ERROR_EAGAIN; + } + LOG_INFO(Lib_Kernel, "Installing signal handler for {}", signum); + Sigaction act = {}; + act.sa_flags = POSIX_SA_SIGINFO | POSIX_SA_RESTART; + act.__sigaction_handler.sigaction = + reinterpret_cast(handler); + posix_sigemptyset(&act.sa_mask); + s32 ret = posix_sigaction(signum, &act, nullptr); + if (ret < 0) { + LOG_ERROR(Lib_Kernel, "Failed to add handler for signal {}: {}", signum, + strerror(*__Error())); + return ErrnoToSceKernelError(*__Error()); + } + return ORBIS_OK; +} + +int PS4_SYSV_ABI sceKernelRemoveExceptionHandler(s32 signum) { + if (!orbis_allowed_signals.contains(signum)) { + return ORBIS_KERNEL_ERROR_EINVAL; + } + int const native_signum = OrbisToNativeSignal(signum); + Handlers[signum] = nullptr; + Sigaction act = {}; + act.sa_flags = POSIX_SA_SIGINFO; + act.__sigaction_handler.sigaction = nullptr; + posix_sigemptyset(&act.sa_mask); + s32 ret = posix_sigaction(signum, &act, nullptr); + if (ret < 0) { + LOG_ERROR(Lib_Kernel, "Failed to remove handler for signal {}: {}", signum, + strerror(*__Error())); + return ErrnoToSceKernelError(*__Error()); + } + return ORBIS_OK; +} + +int PS4_SYSV_ABI sceKernelRaiseException(PthreadT thread, int signum) { + if (signum != POSIX_SIGUSR1) { + return ORBIS_KERNEL_ERROR_EINVAL; + } + s32 ret = posix_pthread_kill(thread, signum); + if (ret < 0) { + return ErrnoToSceKernelError(ret); + } + return ret; +} + s32 PS4_SYSV_ABI sceKernelDebugRaiseException(s32 error, s64 unk) { if (unk != 0) { return ORBIS_KERNEL_ERROR_EINVAL; @@ -352,6 +469,13 @@ void RegisterException(Core::Loader::SymbolsResolver* sym) { sceKernelDebugRaiseExceptionOnReleaseMode); LIB_FUNCTION("WkwEd3N7w0Y", "libkernel", 1, "libkernel", sceKernelInstallExceptionHandler); LIB_FUNCTION("Qhv5ARAoOEc", "libkernel", 1, "libkernel", sceKernelRemoveExceptionHandler); + + LIB_FUNCTION("KiJEPEWRyUY", "libkernel", 1, "libkernel", posix_sigaction); + LIB_FUNCTION("+F7C-hdk7+E", "libkernel", 1, "libkernel", posix_sigemptyset); + LIB_FUNCTION("yH-uQW3LbX0", "libkernel", 1, "libkernel", posix_pthread_kill); + LIB_FUNCTION("KiJEPEWRyUY", "libScePosix", 1, "libkernel", posix_sigaction); + LIB_FUNCTION("+F7C-hdk7+E", "libScePosix", 1, "libkernel", posix_sigemptyset); + LIB_FUNCTION("yH-uQW3LbX0", "libScePosix", 1, "libkernel", posix_pthread_kill); } } // namespace Libraries::Kernel diff --git a/src/core/libraries/kernel/threads/exception.h b/src/core/libraries/kernel/threads/exception.h index 42c92ab2e..c07242c1d 100644 --- a/src/core/libraries/kernel/threads/exception.h +++ b/src/core/libraries/kernel/threads/exception.h @@ -11,7 +11,7 @@ class SymbolsResolver; namespace Libraries::Kernel { -using SceKernelExceptionHandler = PS4_SYSV_ABI void (*)(int, void*); +using OrbisKernelExceptionHandler = PS4_SYSV_ABI void (*)(int, void*); constexpr s32 POSIX_SIGHUP = 1; constexpr s32 POSIX_SIGINT = 2; @@ -47,6 +47,23 @@ constexpr s32 POSIX_SIGUSR2 = 31; constexpr s32 POSIX_SIGTHR = 32; constexpr s32 POSIX_SIGLIBRT = 33; +#ifdef __linux__ +constexpr s32 _SIGEMT = 128; +constexpr s32 _SIGINFO = 129; +#elif !defined(_WIN32) +constexpr s32 _SIGEMT = SIGEMT; +constexpr s32 _SIGINFO = SIGINFO; +#endif + +constexpr s32 POSIX_SA_NOCLDSTOP = 1; +constexpr s32 POSIX_SA_NOCLDWAIT = 2; +constexpr s32 POSIX_SA_SIGINFO = 4; +constexpr s32 POSIX_SA_ONSTACK = 0x08000000; +constexpr s32 POSIX_SA_RESTART = 0x10000000; +constexpr s32 POSIX_SA_NODEFER = 0x40000000; +constexpr s32 POSIX_SA_RESETHAND = 0x80000000; +constexpr s32 POSIX_SA_RESTORER = 0x04000000; + struct Mcontext { u64 mc_onstack; u64 mc_rdi; @@ -101,17 +118,74 @@ struct Sigset { u64 bits[2]; }; +union Sigval { + /* Members as suggested by Annex C of POSIX 1003.1b. */ + int sival_int; + void* sival_ptr; + /* 6.0 compatibility */ + int sigval_int; + void* sigval_ptr; +}; + +struct Siginfo { + int _si_signo; /* signal number */ + int _si_errno; /* errno association */ + /* + * Cause of signal, one of the SI_ macros or signal-specific + * values, i.e. one of the FPE_... values for SIGFPE. This + * value is equivalent to the second argument to an old-style + * FreeBSD signal handler. + */ + int _si_code; /* signal code */ + s32 _si_pid; /* sending process */ + u32 _si_uid; /* sender's ruid */ + int _si_status; /* exit value */ + void* _si_addr; /* faulting instruction */ + union Sigval _si_value; /* signal value */ + union { + struct { + int _trapno; /* machine specific trap code */ + } _fault; + struct { + int _timerid; + int _overrun; + } _timer; + struct { + int _mqd; + } _mesgq; + struct { + long _band; /* band event for SIGPOLL */ + } _poll; /* was this ever used ? */ + struct { + long __spare1__; + int __spare2__[7]; + } __spare__; + } _reason; +}; + +struct Sigaction { + union { + void (*handler)(int); + void (*sigaction)(int, struct Siginfo*, void*); + } __sigaction_handler; + int sa_flags; + Sigset sa_mask; +}; + struct Ucontext { struct Sigset uc_sigmask; int field1_0x10[12]; - struct Mcontext uc_mcontext; - struct Ucontext* uc_link; - struct ExStack uc_stack; + Mcontext uc_mcontext; + Ucontext* uc_link; + ExStack uc_stack; int uc_flags; int __spare[4]; int field7_0x4f4[3]; }; +s32 NativeToOrbisSignal(s32 s); +s32 OrbisToNativeSignal(s32 s); + void RegisterException(Core::Loader::SymbolsResolver* sym); } // namespace Libraries::Kernel diff --git a/src/core/libraries/kernel/threads/pthread.cpp b/src/core/libraries/kernel/threads/pthread.cpp index da9e1600f..f97451154 100644 --- a/src/core/libraries/kernel/threads/pthread.cpp +++ b/src/core/libraries/kernel/threads/pthread.cpp @@ -665,6 +665,7 @@ void RegisterThread(Core::Loader::SymbolsResolver* sym) { LIB_FUNCTION("Z4QosVuAsA0", "libkernel", 1, "libkernel", posix_pthread_once); LIB_FUNCTION("EotR8a3ASf4", "libkernel", 1, "libkernel", posix_pthread_self); LIB_FUNCTION("OxhIB8LB-PQ", "libkernel", 1, "libkernel", posix_pthread_create); + LIB_FUNCTION("Jmi+9w9u0E4", "libkernel", 1, "libkernel", posix_pthread_create_name_np); LIB_FUNCTION("lZzFeSxPl08", "libkernel", 1, "libkernel", posix_pthread_setcancelstate); LIB_FUNCTION("CBNtXOoef-E", "libkernel", 1, "libkernel", posix_sched_get_priority_max); LIB_FUNCTION("m0iS6jNsXds", "libkernel", 1, "libkernel", posix_sched_get_priority_min); diff --git a/src/core/linker.cpp b/src/core/linker.cpp index d0d682043..6640c7204 100644 --- a/src/core/linker.cpp +++ b/src/core/linker.cpp @@ -22,6 +22,10 @@ #include "core/tls.h" #include "ipc/ipc.h" +#ifndef _WIN32 +#include +#endif + namespace Core { static PS4_SYSV_ABI void ProgramExitFunc() { @@ -107,6 +111,11 @@ void Linker::Execute(const std::vector& args) { main_thread.Run([this, module, &args](std::stop_token) { Common::SetCurrentThreadName("Game:Main"); +#ifndef _WIN32 // Clear any existing signal mask for game threads. + sigset_t emptyset; + sigemptyset(&emptyset); + pthread_sigmask(SIG_SETMASK, &emptyset, nullptr); +#endif if (auto& ipc = IPC::Instance()) { ipc.WaitForStart(); } diff --git a/src/core/signals.cpp b/src/core/signals.cpp index 70b431d39..f9b45bab7 100644 --- a/src/core/signals.cpp +++ b/src/core/signals.cpp @@ -21,7 +21,7 @@ #ifndef _WIN32 namespace Libraries::Kernel { void SigactionHandler(int native_signum, siginfo_t* inf, ucontext_t* raw_context); -extern std::array Handlers; +extern std::array Handlers; } // namespace Libraries::Kernel #endif @@ -86,7 +86,7 @@ void SignalHandler(int sig, siginfo_t* info, void* raw_context) { if (!signals->DispatchAccessViolation(raw_context, info->si_addr)) { // If the guest has installed a custom signal handler, and the access violation didn't // come from HLE memory tracking, pass the signal on - if (Libraries::Kernel::Handlers[sig]) { + if (Libraries::Kernel::Handlers[Libraries::Kernel::NativeToOrbisSignal(sig)]) { Libraries::Kernel::SigactionHandler(sig, info, reinterpret_cast(raw_context)); return; @@ -99,7 +99,7 @@ void SignalHandler(int sig, siginfo_t* info, void* raw_context) { } case SIGILL: if (!signals->DispatchIllegalInstruction(raw_context)) { - if (Libraries::Kernel::Handlers[sig]) { + if (Libraries::Kernel::Handlers[Libraries::Kernel::NativeToOrbisSignal(sig)]) { Libraries::Kernel::SigactionHandler(sig, info, reinterpret_cast(raw_context)); return; diff --git a/src/core/signals.h b/src/core/signals.h index 90801debb..011383693 100644 --- a/src/core/signals.h +++ b/src/core/signals.h @@ -10,10 +10,8 @@ #ifdef _WIN32 #define SIGSLEEP -1 -#elif defined(__APPLE__) -#define SIGSLEEP SIGVTALRM #else -#define SIGSLEEP SIGRTMAX +#define SIGSLEEP SIGVTALRM #endif namespace Core { From e16ba06ab0aa10492d719c3a11f46aeaf73ff5c1 Mon Sep 17 00:00:00 2001 From: TheTurtle Date: Mon, 9 Mar 2026 17:33:58 +0200 Subject: [PATCH 5/7] shader_recompiler: Support 32 thread sharing mode (#4110) --- .../frontend/translate/data_share.cpp | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/shader_recompiler/frontend/translate/data_share.cpp b/src/shader_recompiler/frontend/translate/data_share.cpp index 634486fc4..b1aca83d3 100644 --- a/src/shader_recompiler/frontend/translate/data_share.cpp +++ b/src/shader_recompiler/frontend/translate/data_share.cpp @@ -277,12 +277,21 @@ void Translator::DS_SWIZZLE_B32(const GcnInst& inst) { const u8 offset0 = inst.control.ds.offset0; const u8 offset1 = inst.control.ds.offset1; const IR::U32 src{GetSrc(inst.src[0])}; - // ASSERT(offset1 & 0x80); const IR::U32 lane_id = ir.LaneId(); - const IR::U32 id_in_group = ir.BitwiseAnd(lane_id, ir.Imm32(0b11)); - const IR::U32 base = ir.ShiftLeftLogical(id_in_group, ir.Imm32(1)); - const IR::U32 index = ir.BitFieldExtract(ir.Imm32(offset0), base, ir.Imm32(2)); - SetDst(inst.dst[0], ir.QuadShuffle(src, index)); + if (offset1 & 0x80) { + const IR::U32 id_in_group = ir.BitwiseAnd(lane_id, ir.Imm32(0b11)); + const IR::U32 base = ir.ShiftLeftLogical(id_in_group, ir.Imm32(1)); + const IR::U32 index = ir.BitFieldExtract(ir.Imm32(offset0), base, ir.Imm32(2)); + SetDst(inst.dst[0], ir.QuadShuffle(src, index)); + } else { + const u8 and_mask = (offset0 & 0x1f) | (~u8{0} << 5); + const u8 or_mask = (offset0 >> 5) | ((offset1 & 0x3) << 3); + const u8 xor_mask = offset1 >> 2; + const IR::U32 index = ir.BitwiseXor( + ir.BitwiseOr(ir.BitwiseAnd(lane_id, ir.Imm32(and_mask)), ir.Imm32(or_mask)), + ir.Imm32(xor_mask)); + SetDst(inst.dst[0], ir.ReadLane(src, index)); + } } void Translator::DS_APPEND(const GcnInst& inst) { From df6bb8562e79971beb966789e4cbbb2b35fcc9d9 Mon Sep 17 00:00:00 2001 From: TheTurtle Date: Mon, 9 Mar 2026 17:46:51 +0200 Subject: [PATCH 6/7] renderer_vulkan: Force subgroup size to 64 when possible (#4111) --- src/video_core/renderer_vulkan/vk_compute_pipeline.cpp | 4 ++++ src/video_core/renderer_vulkan/vk_instance.cpp | 7 +++++-- src/video_core/renderer_vulkan/vk_instance.h | 7 +++++++ 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp index 35eda86da..eecd416d1 100644 --- a/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp +++ b/src/video_core/renderer_vulkan/vk_compute_pipeline.cpp @@ -21,7 +21,11 @@ ComputePipeline::ComputePipeline(const Instance& instance, Scheduler& scheduler, info = &info_; const auto debug_str = GetDebugString(); + const vk::PipelineShaderStageRequiredSubgroupSizeCreateInfo subgroup_size_ci = { + .requiredSubgroupSize = 64, + }; const vk::PipelineShaderStageCreateInfo shader_ci = { + .pNext = instance.IsSubgroupSize64Supported() ? &subgroup_size_ci : nullptr, .stage = vk::ShaderStageFlagBits::eCompute, .module = module, .pName = "main", diff --git a/src/video_core/renderer_vulkan/vk_instance.cpp b/src/video_core/renderer_vulkan/vk_instance.cpp index 44aa79d98..6898df97a 100644 --- a/src/video_core/renderer_vulkan/vk_instance.cpp +++ b/src/video_core/renderer_vulkan/vk_instance.cpp @@ -220,9 +220,11 @@ bool Instance::CreateDevice() { const vk::StructureChain properties_chain = physical_device.getProperties2< vk::PhysicalDeviceProperties2, vk::PhysicalDeviceVulkan11Properties, - vk::PhysicalDeviceVulkan12Properties, vk::PhysicalDevicePushDescriptorPropertiesKHR>(); + vk::PhysicalDeviceVulkan12Properties, vk::PhysicalDeviceVulkan13Properties, + vk::PhysicalDevicePushDescriptorPropertiesKHR>(); vk11_props = properties_chain.get(); vk12_props = properties_chain.get(); + vk13_props = properties_chain.get(); push_descriptor_props = properties_chain.get(); LOG_INFO(Render_Vulkan, "Physical device subgroup size {}", vk11_props.subgroupSize); @@ -367,7 +369,7 @@ bool Instance::CreateDevice() { feature_chain.get(); const auto vk11_features = feature_chain.get(); vk12_features = feature_chain.get(); - const auto vk13_features = feature_chain.get(); + vk13_features = feature_chain.get(); vk::StructureChain device_chain = { vk::DeviceCreateInfo{ .queueCreateInfoCount = 1u, @@ -429,6 +431,7 @@ bool Instance::CreateDevice() { vk::PhysicalDeviceVulkan13Features{ .robustImageAccess = vk13_features.robustImageAccess, .shaderDemoteToHelperInvocation = vk13_features.shaderDemoteToHelperInvocation, + .subgroupSizeControl = vk13_features.subgroupSizeControl, .synchronization2 = vk13_features.synchronization2, .dynamicRendering = vk13_features.dynamicRendering, .maintenance4 = vk13_features.maintenance4, diff --git a/src/video_core/renderer_vulkan/vk_instance.h b/src/video_core/renderer_vulkan/vk_instance.h index 8975669bb..7a8a906d5 100644 --- a/src/video_core/renderer_vulkan/vk_instance.h +++ b/src/video_core/renderer_vulkan/vk_instance.h @@ -233,6 +233,11 @@ public: return vk12_features.shaderSharedInt64Atomics; } + /// Returns true if the subgroup size can be set to match guest subgroup size + bool IsSubgroupSize64Supported() const { + return vk13_features.subgroupSizeControl && vk13_props.maxSubgroupSize >= 64; + } + /// Returns true when VK_KHR_workgroup_memory_explicit_layout is supported. bool IsWorkgroupMemoryExplicitLayoutSupported() const { return workgroup_memory_explicit_layout && @@ -455,9 +460,11 @@ private: vk::PhysicalDeviceMemoryProperties memory_properties; vk::PhysicalDeviceVulkan11Properties vk11_props; vk::PhysicalDeviceVulkan12Properties vk12_props; + vk::PhysicalDeviceVulkan13Properties vk13_props; vk::PhysicalDevicePushDescriptorPropertiesKHR push_descriptor_props; vk::PhysicalDeviceFeatures features; vk::PhysicalDeviceVulkan12Features vk12_features; + vk::PhysicalDeviceVulkan13Features vk13_features; vk::PhysicalDevicePortabilitySubsetFeaturesKHR portability_features; vk::PhysicalDeviceExtendedDynamicState3FeaturesEXT dynamic_state_3_features; vk::PhysicalDeviceRobustness2FeaturesEXT robustness2_features; From 85476e55ea70201c470eb618193864844bead976 Mon Sep 17 00:00:00 2001 From: Stephen Miller <56742918+StevenMiller123@users.noreply.github.com> Date: Mon, 9 Mar 2026 11:02:22 -0500 Subject: [PATCH 7/7] Recompiler: Implement IMAGE_ATOMIC_CMPSWAP (#4109) * To implement ImageAtomicCmpSwap ...but it doesn't work, so here it shall stay. * a fix * Clang * Add to MayHaveSideEffects I missed this while digging through IR code. --- .../backend/spirv/emit_spirv_atomic.cpp | 15 +++++++++++++++ .../backend/spirv/emit_spirv_instructions.h | 2 ++ src/shader_recompiler/frontend/format.cpp | 4 ++-- .../frontend/translate/vector_memory.cpp | 6 ++++++ src/shader_recompiler/ir/ir_emitter.cpp | 5 +++++ src/shader_recompiler/ir/ir_emitter.h | 3 +++ src/shader_recompiler/ir/microinstruction.cpp | 1 + src/shader_recompiler/ir/opcodes.inc | 1 + .../ir/passes/resource_tracking_pass.cpp | 1 + 9 files changed, 36 insertions(+), 2 deletions(-) diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_atomic.cpp b/src/shader_recompiler/backend/spirv/emit_spirv_atomic.cpp index 6dd1637dd..549e27ae0 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_atomic.cpp +++ b/src/shader_recompiler/backend/spirv/emit_spirv_atomic.cpp @@ -140,6 +140,15 @@ Id ImageAtomicF32(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords, Id va const auto [scope, semantics]{AtomicArgs(ctx)}; return (ctx.*atomic_func)(ctx.F32[1], pointer, scope, semantics, value); } + +Id ImageAtomicU32CmpSwap(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords, Id value, + Id cmp_value, + Id (Sirit::Module::*atomic_func)(Id, Id, Id, Id, Id, Id, Id)) { + const auto& texture = ctx.images[handle & 0xFFFF]; + const Id pointer{ctx.OpImageTexelPointer(ctx.image_u32, texture.id, coords, ctx.ConstU32(0U))}; + const auto [scope, semantics]{AtomicArgs(ctx)}; + return (ctx.*atomic_func)(ctx.F32[1], pointer, scope, semantics, semantics, value, cmp_value); +} } // Anonymous namespace Id EmitSharedAtomicIAdd32(EmitContext& ctx, Id offset, Id value) { @@ -420,6 +429,12 @@ Id EmitImageAtomicExchange32(EmitContext& ctx, IR::Inst* inst, u32 handle, Id co return ImageAtomicU32(ctx, inst, handle, coords, value, &Sirit::Module::OpAtomicExchange); } +Id EmitImageAtomicCmpSwap32(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords, Id value, + Id cmp_value) { + return ImageAtomicU32CmpSwap(ctx, inst, handle, coords, value, cmp_value, + &Sirit::Module::OpAtomicCompareExchange); +} + Id EmitDataAppend(EmitContext& ctx, u32 gds_addr, u32 binding) { const auto& buffer = ctx.buffers[binding]; const auto [id, pointer_type] = buffer.Alias(PointerType::U32); diff --git a/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h b/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h index 80968eaf0..69fa36eaa 100644 --- a/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h +++ b/src/shader_recompiler/backend/spirv/emit_spirv_instructions.h @@ -456,6 +456,8 @@ Id EmitImageAtomicAnd32(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords, Id EmitImageAtomicOr32(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords, Id value); Id EmitImageAtomicXor32(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords, Id value); Id EmitImageAtomicExchange32(EmitContext& ctx, IR::Inst* inst, u32 handle, Id coords, Id value); +Id EmitImageAtomicCmpSwap32(EmitContext& ctx, IR::Inst* inst, u32 handle, Id address, Id value, + Id cmp_value); Id EmitCubeFaceIndex(EmitContext& ctx, IR::Inst* inst, Id cube_coords); Id EmitLaneId(EmitContext& ctx); Id EmitWarpId(EmitContext& ctx); diff --git a/src/shader_recompiler/frontend/format.cpp b/src/shader_recompiler/frontend/format.cpp index d26873396..4a90fe358 100644 --- a/src/shader_recompiler/frontend/format.cpp +++ b/src/shader_recompiler/frontend/format.cpp @@ -3430,8 +3430,8 @@ constexpr std::array InstructionFormatMIMG = {{ {InstClass::VectorMemImgNoSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Uint32, ScalarType::Uint32}, // 16 = IMAGE_ATOMIC_CMPSWAP - {InstClass::VectorMemImgNoSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Undefined, - ScalarType::Undefined}, + {InstClass::VectorMemImgNoSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Uint32, + ScalarType::Uint32}, // 17 = IMAGE_ATOMIC_ADD {InstClass::VectorMemImgNoSmp, InstCategory::VectorMemory, 4, 1, ScalarType::Uint32, ScalarType::Uint32}, diff --git a/src/shader_recompiler/frontend/translate/vector_memory.cpp b/src/shader_recompiler/frontend/translate/vector_memory.cpp index 72286b29c..0d9e8f220 100644 --- a/src/shader_recompiler/frontend/translate/vector_memory.cpp +++ b/src/shader_recompiler/frontend/translate/vector_memory.cpp @@ -137,6 +137,8 @@ void Translator::EmitVectorMemory(const GcnInst& inst) { // Image atomic operations case Opcode::IMAGE_ATOMIC_SWAP: return IMAGE_ATOMIC(AtomicOp::Swap, inst); + case Opcode::IMAGE_ATOMIC_CMPSWAP: + return IMAGE_ATOMIC(AtomicOp::CmpSwap, inst); case Opcode::IMAGE_ATOMIC_ADD: return IMAGE_ATOMIC(AtomicOp::Add, inst); case Opcode::IMAGE_ATOMIC_SMIN: @@ -520,6 +522,10 @@ void Translator::IMAGE_ATOMIC(AtomicOp op, const GcnInst& inst) { switch (op) { case AtomicOp::Swap: return ir.ImageAtomicExchange(handle, body, value, {}); + case AtomicOp::CmpSwap: { + const IR::Value cmp_val = ir.GetVectorReg(val_reg + 1); + return ir.ImageAtomicCmpSwap(handle, body, value, cmp_val, info); + } case AtomicOp::Add: return ir.ImageAtomicIAdd(handle, body, value, info); case AtomicOp::Smin: diff --git a/src/shader_recompiler/ir/ir_emitter.cpp b/src/shader_recompiler/ir/ir_emitter.cpp index 1e77dc677..c681c3120 100644 --- a/src/shader_recompiler/ir/ir_emitter.cpp +++ b/src/shader_recompiler/ir/ir_emitter.cpp @@ -2055,6 +2055,11 @@ Value IREmitter::ImageAtomicExchange(const Value& handle, const Value& coords, c return Inst(Opcode::ImageAtomicExchange32, Flags{info}, handle, coords, value); } +Value IREmitter::ImageAtomicCmpSwap(const Value& handle, const Value& coords, const Value& value, + const Value& cmp_value, TextureInstInfo info) { + return Inst(Opcode::ImageAtomicCmpSwap32, Flags{info}, handle, coords, value, cmp_value); +} + Value IREmitter::ImageSampleRaw(const Value& image_handle, const Value& sampler_handle, const Value& address1, const Value& address2, const Value& address3, const Value& address4, TextureInstInfo info) { diff --git a/src/shader_recompiler/ir/ir_emitter.h b/src/shader_recompiler/ir/ir_emitter.h index 6f20d5780..adc8f5fb1 100644 --- a/src/shader_recompiler/ir/ir_emitter.h +++ b/src/shader_recompiler/ir/ir_emitter.h @@ -360,6 +360,9 @@ public: TextureInstInfo info); [[nodiscard]] Value ImageAtomicExchange(const Value& handle, const Value& coords, const Value& value, TextureInstInfo info); + [[nodiscard]] Value ImageAtomicCmpSwap(const Value& handle, const Value& coords, + const Value& value, const Value& cmp_value, + TextureInstInfo info); [[nodiscard]] Value ImageSampleRaw(const Value& image_handle, const Value& sampler_handle, const Value& address1, const Value& address2, diff --git a/src/shader_recompiler/ir/microinstruction.cpp b/src/shader_recompiler/ir/microinstruction.cpp index 40ce69df8..cd0131770 100644 --- a/src/shader_recompiler/ir/microinstruction.cpp +++ b/src/shader_recompiler/ir/microinstruction.cpp @@ -123,6 +123,7 @@ bool Inst::MayHaveSideEffects() const noexcept { case Opcode::ImageAtomicOr32: case Opcode::ImageAtomicXor32: case Opcode::ImageAtomicExchange32: + case Opcode::ImageAtomicCmpSwap32: case Opcode::DebugPrint: case Opcode::EmitVertex: case Opcode::EmitPrimitive: diff --git a/src/shader_recompiler/ir/opcodes.inc b/src/shader_recompiler/ir/opcodes.inc index 4875375bc..6304a96fa 100644 --- a/src/shader_recompiler/ir/opcodes.inc +++ b/src/shader_recompiler/ir/opcodes.inc @@ -436,6 +436,7 @@ OPCODE(ImageAtomicAnd32, U32, Opaq OPCODE(ImageAtomicOr32, U32, Opaque, Opaque, U32, ) OPCODE(ImageAtomicXor32, U32, Opaque, Opaque, U32, ) OPCODE(ImageAtomicExchange32, U32, Opaque, Opaque, U32, ) +OPCODE(ImageAtomicCmpSwap32, U32, Opaque, Opaque, U32, U32, ) // Cube operations - optional, usable if profile.supports_native_cube_calc OPCODE(CubeFaceIndex, F32, F32x3, ) diff --git a/src/shader_recompiler/ir/passes/resource_tracking_pass.cpp b/src/shader_recompiler/ir/passes/resource_tracking_pass.cpp index 93129ac0e..4c41e94e9 100644 --- a/src/shader_recompiler/ir/passes/resource_tracking_pass.cpp +++ b/src/shader_recompiler/ir/passes/resource_tracking_pass.cpp @@ -214,6 +214,7 @@ bool IsImageAtomicInstruction(const IR::Inst& inst) { case IR::Opcode::ImageAtomicOr32: case IR::Opcode::ImageAtomicXor32: case IR::Opcode::ImageAtomicExchange32: + case IR::Opcode::ImageAtomicCmpSwap32: return true; default: return false;