diff --git a/core/libs/prx/libSceSysmodule/CMakeLists.txt b/core/libs/prx/libSceSysmodule/CMakeLists.txt new file mode 100644 index 000000000..afbcf4cd6 --- /dev/null +++ b/core/libs/prx/libSceSysmodule/CMakeLists.txt @@ -0,0 +1,20 @@ +add_library(libSceSysmodule SHARED EXCLUDE_FROM_ALL Export.cpp) +target_include_directories(libSceSysmodule PRIVATE ${LIBS_INCLUDE_DIR}) +configure_windows_unwind(libSceSysmodule) + +if(MINGW) + foreach(runtimeLinkFlag IN ITEMS -static-libgcc -static-libstdc++ -static) + string(REPLACE "${runtimeLinkFlag}" "" CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}") + endforeach() +endif() + +if(BUILD_TESTING) + add_test_executable(guest_sysmodule_tests ${LIBS_INCLUDE_DIR}/tests/GuestSysmodule.cpp) + target_include_directories(guest_sysmodule_tests PRIVATE ${LIBS_INCLUDE_DIR}) + target_link_libraries(guest_sysmodule_tests PRIVATE libSceSysmodule) + add_test(NAME guest_sysmodule COMMAND guest_sysmodule_tests) + if(WIN32) + set_tests_properties(guest_sysmodule PROPERTIES ENVIRONMENT_MODIFICATION + "PATH=path_list_prepend:$") + endif() +endif() diff --git a/core/libs/prx/libSceSysmodule/Export.cpp b/core/libs/prx/libSceSysmodule/Export.cpp index 76f993459..85b64a2ed 100644 --- a/core/libs/prx/libSceSysmodule/Export.cpp +++ b/core/libs/prx/libSceSysmodule/Export.cpp @@ -166,4 +166,32 @@ int APS5_VABI sceSysmoduleUnloadModule(std::uint16_t id) { return 0; } +int APS5_VABI sceSysmoduleLoadModuleInternal(std::uint32_t id) { + if ((id & 0x7fffffffu) == 0) { + throw std::runtime_error("sceSysmoduleLoadModuleInternal: invalid id 0"); + } + if (!findModuleName(id)) { + throw std::runtime_error(std::string("sceSysmoduleLoadModuleInternal: unknown id ") + std::to_string(id)); + } + std::lock_guard lock(gMutex); + gLoadCount[id]++; + return 0; +} + +int APS5_VABI sceSysmoduleUnloadModuleInternal(std::uint32_t id) { + if ((id & 0x7fffffffu) == 0) { + throw std::runtime_error("sceSysmoduleUnloadModuleInternal: invalid id 0"); + } + if (!findModuleName(id)) { + throw std::runtime_error(std::string("sceSysmoduleUnloadModuleInternal: unknown id ") + std::to_string(id)); + } + std::lock_guard lock(gMutex); + auto it = gLoadCount.find(id); + if (it == gLoadCount.end() || it->second < 1) { + return 0x80A90003; + } + it->second--; + return 0; +} + } diff --git a/core/libs/tests/GuestSysmodule.cpp b/core/libs/tests/GuestSysmodule.cpp new file mode 100644 index 000000000..bf6dbaa00 --- /dev/null +++ b/core/libs/tests/GuestSysmodule.cpp @@ -0,0 +1,25 @@ +#include "prx/libc/include/general/VabiMacros.hpp" +#include +#include + +extern "C" { +int APS5_VABI sceSysmoduleLoadModuleInternal(std::uint32_t id); +int APS5_VABI sceSysmoduleUnloadModuleInternal(std::uint32_t id); +} + +namespace { + +void Require(bool value) { if (!value) std::abort(); } + +constexpr std::uint32_t kFiberModuleId = 0x00000006; +constexpr int kModuleNotLoaded = static_cast(0x80A90003); + +} + +int main() { + Require(sceSysmoduleLoadModuleInternal(kFiberModuleId) == 0); + Require(sceSysmoduleLoadModuleInternal(kFiberModuleId) == 0); + Require(sceSysmoduleUnloadModuleInternal(kFiberModuleId) == 0); + Require(sceSysmoduleUnloadModuleInternal(kFiberModuleId) == 0); + Require(sceSysmoduleUnloadModuleInternal(kFiberModuleId) == kModuleNotLoaded); +}