From 97cae1458ea4869c45025ee669134184db5041c3 Mon Sep 17 00:00:00 2001 From: QDarkRex Date: Sun, 27 Sep 2026 13:22:01 +0700 Subject: [PATCH] fix(kernel): use SCE kernel error codes in equeue, direct memory and mutex SCE kernel errors are 0x80020000 plus the FreeBSD errno. The equeue and direct memory constants used an unrelated 0x8001xxxx range with mismatched errno values (e.g. ETIMEDOUT was 0x80010023), so a guest checking sceKernelWaitEqueue for SCE_KERNEL_ERROR_ETIMEDOUT saw an unexpected error. SCE_KERNEL_ERROR_EDEADLK in Mutex.cpp held the EAGAIN value. Co-Authored-By: Claude Opus 5.5 --- core/libs/CMakeLists.txt | 10 ++++ .../libkernel/DirectMemory/DirectMemory.hpp | 10 ++-- core/libs/prx/libkernel/Equeue/Equeue.hpp | 10 ++-- core/libs/prx/libkernel/Pthread/src/Mutex.cpp | 2 +- core/libs/tests/GuestKernelErrors.cpp | 56 +++++++++++++++++++ 5 files changed, 77 insertions(+), 11 deletions(-) create mode 100644 core/libs/tests/GuestKernelErrors.cpp diff --git a/core/libs/CMakeLists.txt b/core/libs/CMakeLists.txt index 2ad90fd7e..931265f9b 100644 --- a/core/libs/CMakeLists.txt +++ b/core/libs/CMakeLists.txt @@ -249,6 +249,16 @@ if(BUILD_TESTING) set_tests_properties(guest_signals PROPERTIES ENVIRONMENT_MODIFICATION "PATH=path_list_prepend:$") endif() + add_executable(guest_kernel_error_tests tests/GuestKernelErrors.cpp) + target_include_directories(guest_kernel_error_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) + target_link_libraries(guest_kernel_error_tests PRIVATE libkernel libc) + configure_windows_unwind(guest_kernel_error_tests) + add_test(NAME guest_kernel_errors COMMAND guest_kernel_error_tests) + set_tests_properties(guest_kernel_errors PROPERTIES TIMEOUT 20) + if(WIN32) + set_tests_properties(guest_kernel_errors PROPERTIES ENVIRONMENT_MODIFICATION + "PATH=path_list_prepend:$") + endif() add_executable(guest_system_configuration_tests tests/GuestSystemConfiguration.cpp) target_include_directories(guest_system_configuration_tests PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) target_link_libraries(guest_system_configuration_tests PRIVATE libkernel libc) diff --git a/core/libs/prx/libkernel/DirectMemory/DirectMemory.hpp b/core/libs/prx/libkernel/DirectMemory/DirectMemory.hpp index c53b17f05..ff97aaeb1 100644 --- a/core/libs/prx/libkernel/DirectMemory/DirectMemory.hpp +++ b/core/libs/prx/libkernel/DirectMemory/DirectMemory.hpp @@ -7,11 +7,11 @@ static constexpr size_t DIRECT_MEMORY_SIZE = 13824ULL * 1024 * 1024; static constexpr size_t PS5_PAGE_SIZE = 0x4000; -static constexpr int SCE_KERNEL_ERROR_EINVAL = -2147418107; -static constexpr int SCE_KERNEL_ERROR_EAGAIN = -2147418110; -static constexpr int SCE_KERNEL_ERROR_ENOMEM = -2147418105; -static constexpr int SCE_KERNEL_ERROR_EACCES = -2147418108; -static constexpr int SCE_KERNEL_ERROR_EFAULT = -2147418103; +static constexpr int SCE_KERNEL_ERROR_EINVAL = 0x80020016; +static constexpr int SCE_KERNEL_ERROR_EAGAIN = 0x80020023; +static constexpr int SCE_KERNEL_ERROR_ENOMEM = 0x8002000C; +static constexpr int SCE_KERNEL_ERROR_EACCES = 0x8002000D; +static constexpr int SCE_KERNEL_ERROR_EFAULT = 0x8002000E; int DirectMemoryAlloc(int64_t searchStart, int64_t searchEnd, size_t len, size_t alignment, int64_t* physOut); void DirectMemoryFree(int64_t start, size_t len); diff --git a/core/libs/prx/libkernel/Equeue/Equeue.hpp b/core/libs/prx/libkernel/Equeue/Equeue.hpp index 0082a1edd..e8571a78e 100644 --- a/core/libs/prx/libkernel/Equeue/Equeue.hpp +++ b/core/libs/prx/libkernel/Equeue/Equeue.hpp @@ -23,11 +23,11 @@ static constexpr uint16_t EV_CLEAR = 0x0020; static constexpr uint16_t EV_ERROR = 0x4000; static constexpr int EQUEUE_OK = 0; -static constexpr int EQUEUE_ERROR_EBADF = -2147418090; -static constexpr int EQUEUE_ERROR_EFAULT = -2147418103; -static constexpr int EQUEUE_ERROR_EINVAL = -2147418107; -static constexpr int EQUEUE_ERROR_ENOENT = -2147418095; -static constexpr int EQUEUE_ERROR_ETIMEDOUT = -2147418077; +static constexpr int EQUEUE_ERROR_EBADF = 0x80020009; +static constexpr int EQUEUE_ERROR_EFAULT = 0x8002000E; +static constexpr int EQUEUE_ERROR_EINVAL = 0x80020016; +static constexpr int EQUEUE_ERROR_ENOENT = 0x80020002; +static constexpr int EQUEUE_ERROR_ETIMEDOUT = 0x8002003C; struct KernelEqueueEvent; diff --git a/core/libs/prx/libkernel/Pthread/src/Mutex.cpp b/core/libs/prx/libkernel/Pthread/src/Mutex.cpp index cc9ac1881..e3a4448e5 100644 --- a/core/libs/prx/libkernel/Pthread/src/Mutex.cpp +++ b/core/libs/prx/libkernel/Pthread/src/Mutex.cpp @@ -6,7 +6,7 @@ static constexpr int SCE_OK = 0; static constexpr int SCE_KERNEL_ERROR_ENOMEM = 0x8002000C; -static constexpr int SCE_KERNEL_ERROR_EDEADLK = 0x80020023; +static constexpr int SCE_KERNEL_ERROR_EDEADLK = 0x8002000B; static constexpr int SCE_KERNEL_ERROR_EPERM = 0x80020001; extern "C" { diff --git a/core/libs/tests/GuestKernelErrors.cpp b/core/libs/tests/GuestKernelErrors.cpp new file mode 100644 index 000000000..96997af26 --- /dev/null +++ b/core/libs/tests/GuestKernelErrors.cpp @@ -0,0 +1,56 @@ +#include "SceTypes.hpp" +#include +#include + +extern "C" { +int APS5_VABI sceKernelCreateEqueue(KernelEqueue* eq, const char* name); +int APS5_VABI sceKernelDeleteEqueue(KernelEqueue eq); +int APS5_VABI sceKernelWaitEqueue(KernelEqueue eq, KernelEvent* ev, int num, int* out, const KernelUseconds* timo); +int APS5_VABI sceKernelDeleteUserEvent(KernelEqueue eq, int id); +int APS5_VABI scePthreadMutexattrInit(PthreadMutexattr* attr); +int APS5_VABI scePthreadMutexattrDestroy(PthreadMutexattr* attr); +int APS5_VABI scePthreadMutexattrSettype(PthreadMutexattr* attr, int type); +int APS5_VABI scePthreadMutexInit(PthreadMutex* mutex, const PthreadMutexattr* attr, const char* name); +int APS5_VABI scePthreadMutexDestroy(PthreadMutex* mutex); +int APS5_VABI scePthreadMutexLock(PthreadMutex* mutex); +int APS5_VABI scePthreadMutexUnlock(PthreadMutex* mutex); +} + +static constexpr int SCE_OK = 0; +static constexpr int SCE_KERNEL_ERROR_ENOENT = static_cast(0x80020002); +static constexpr int SCE_KERNEL_ERROR_EBADF = static_cast(0x80020009); +static constexpr int SCE_KERNEL_ERROR_EDEADLK = static_cast(0x8002000B); +static constexpr int SCE_KERNEL_ERROR_EFAULT = static_cast(0x8002000E); +static constexpr int SCE_KERNEL_ERROR_EINVAL = static_cast(0x80020016); +static constexpr int SCE_KERNEL_ERROR_ETIMEDOUT = static_cast(0x8002003C); +static constexpr int MUTEX_TYPE_ERRORCHECK = 1; + +static void Require(bool value) { if (!value) std::abort(); } + +int main() { + KernelEqueue eq = 0; + Require(sceKernelCreateEqueue(&eq, "errors") == SCE_OK); + KernelEvent event{}; + int count = -1; + const KernelUseconds timeout = 1000; + Require(sceKernelWaitEqueue(eq, &event, 1, &count, &timeout) == SCE_KERNEL_ERROR_ETIMEDOUT); + Require(count == 0); + Require(sceKernelWaitEqueue(eq, nullptr, 1, &count, &timeout) == SCE_KERNEL_ERROR_EFAULT); + Require(sceKernelWaitEqueue(eq, &event, 0, &count, &timeout) == SCE_KERNEL_ERROR_EINVAL); + Require(sceKernelDeleteUserEvent(eq, 7) == SCE_KERNEL_ERROR_ENOENT); + Require(sceKernelDeleteEqueue(eq) == SCE_OK); + Require(sceKernelDeleteEqueue(eq) == SCE_KERNEL_ERROR_EBADF); + Require(sceKernelWaitEqueue(eq, &event, 1, &count, &timeout) == SCE_KERNEL_ERROR_EBADF); + Require(sceKernelCreateEqueue(nullptr, "errors") == SCE_KERNEL_ERROR_EINVAL); + + PthreadMutexattr attr = nullptr; + Require(scePthreadMutexattrInit(&attr) == SCE_OK); + Require(scePthreadMutexattrSettype(&attr, MUTEX_TYPE_ERRORCHECK) == SCE_OK); + PthreadMutex mutex = nullptr; + Require(scePthreadMutexInit(&mutex, &attr, nullptr) == SCE_OK); + Require(scePthreadMutexattrDestroy(&attr) == SCE_OK); + Require(scePthreadMutexLock(&mutex) == SCE_OK); + Require(scePthreadMutexLock(&mutex) == SCE_KERNEL_ERROR_EDEADLK); + Require(scePthreadMutexUnlock(&mutex) == SCE_OK); + Require(scePthreadMutexDestroy(&mutex) == SCE_OK); +}