diff --git a/README.md b/README.md index 1fedd1b4d..f5cdfc87e 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,7 @@ Execution reaches `_start`, stack unwinding and exception handling tables are bu Shader initialization via `sceAgcCreate*` passes. Audio output and video output initialization pass -Now: `sceKernelCreateSema not implemented`. +Now: `fopen: open failed: "C:\app0\~INDEX": No such file or directory`. On Windows, after printing an unhandled exception the process exits with STATUS_STACK_BUFFER_OVERRUN due to the difficulty of manually [implementing proper exception handling](core/libs/prx/libc/src/exception). diff --git a/core/libs/prx/libkernel/Export.cpp b/core/libs/prx/libkernel/Export.cpp index 37f8ad266..baf0bb71f 100644 --- a/core/libs/prx/libkernel/Export.cpp +++ b/core/libs/prx/libkernel/Export.cpp @@ -5,8 +5,8 @@ #include "prx/libc/include/General.hpp" #include "DirectMemory/DirectMemory.hpp" #include "Equeue/Equeue.hpp" -#include "File/include/File.hpp" -#include "Semaphore/include/Semaphore.hpp" +#include "prx/libkernel/File/include/File.hpp" +#include "prx/libkernel/Semaphore/include/Semaphore.hpp" extern "C" { diff --git a/core/libs/prx/libkernel/File/include/File.hpp b/core/libs/prx/libkernel/File/include/File.hpp index d5772ff06..d889b6cae 100644 --- a/core/libs/prx/libkernel/File/include/File.hpp +++ b/core/libs/prx/libkernel/File/include/File.hpp @@ -5,7 +5,7 @@ #include #include "SceTypes.hpp" -#include "prx/libc/include/general/VabiMacros.hpp" +#include "prx/libc/include/General.hpp" extern "C" { @@ -20,3 +20,4 @@ int64_t APS5_VABI sceKernelWrite(int d, const void* buf, size_t nbytes); } #endif + diff --git a/core/libs/prx/libkernel/File/src/File.cpp b/core/libs/prx/libkernel/File/src/File.cpp index c8dc4be8b..2593f2187 100644 --- a/core/libs/prx/libkernel/File/src/File.cpp +++ b/core/libs/prx/libkernel/File/src/File.cpp @@ -1,51 +1,62 @@ #include "prx/libkernel/File/include/File.hpp" #include +#include extern "C" { int APS5_VABI sceKernelClose(int d) { (void)d; - throw std::runtime_error("sceKernelClose is not implemented"); + throw std::runtime_error(std::string(__func__) + " is not implemented"); } int APS5_VABI sceKernelLseek(int d, int64_t offset, int whence) { (void)d; (void)offset; (void)whence; - throw std::runtime_error("sceKernelLseek is not implemented"); + + NotImplemented_nid_no_patch(__func__); + return 0; } int APS5_VABI sceKernelOpen(const char* path, int flags, uint16_t mode) { (void)path; (void)flags; (void)mode; - throw std::runtime_error("sceKernelOpen is not implemented"); + + NotImplemented_nid_no_patch(__func__); + return 0; } int64_t APS5_VABI sceKernelRead(int d, void* buf, size_t nbytes) { (void)d; (void)buf; (void)nbytes; - throw std::runtime_error("sceKernelRead is not implemented"); + + NotImplemented_nid_no_patch(__func__); + return 0; } int APS5_VABI sceKernelStat(const char* path, FileStat* sb) { (void)path; (void)sb; - throw std::runtime_error("sceKernelStat is not implemented"); + NotImplemented_nid_no_patch(__func__); + return 0; } int APS5_VABI sceKernelUnlink(const char* path) { (void)path; - throw std::runtime_error("sceKernelUnlink is not implemented"); + NotImplemented_nid_no_patch(__func__); + return 0; } int64_t APS5_VABI sceKernelWrite(int d, const void* buf, size_t nbytes) { (void)d; (void)buf; (void)nbytes; - throw std::runtime_error("sceKernelWrite is not implemented"); + + NotImplemented_nid_no_patch(__func__); + return 0; } } diff --git a/core/libs/prx/libkernel/Semaphore/include/Semaphore.hpp b/core/libs/prx/libkernel/Semaphore/include/Semaphore.hpp index 530a34ec3..e7c6e49d2 100644 --- a/core/libs/prx/libkernel/Semaphore/include/Semaphore.hpp +++ b/core/libs/prx/libkernel/Semaphore/include/Semaphore.hpp @@ -1,10 +1,30 @@ #ifndef CORE_LIBS_PRX_LIBKERNEL_SEMAPHORE_SEMAPHORE_HPP #define CORE_LIBS_PRX_LIBKERNEL_SEMAPHORE_SEMAPHORE_HPP +#include +#include #include +#include +#include #include "SceTypes.hpp" -#include "prx/libc/include/general/VabiMacros.hpp" +#include "prx/libc/include/General.hpp" + +constexpr int KERNEL_SEMA_OK = 0; +constexpr int KERNEL_SEMA_ERROR_EINVAL = static_cast(0x80020016); +constexpr int KERNEL_SEMA_ERROR_EBUSY = static_cast(0x80020010); +constexpr int KERNEL_SEMA_ERROR_ETIMEDOUT = static_cast(0x8002003C); + +struct KernelSemaPrivate { + KernelSemaPrivate(std::int32_t initCount, std::int32_t maxCount, std::string name, bool isFifo); + + std::mutex mutex; + std::condition_variable condition; + std::string name; + std::int32_t tokenCount; + std::int32_t maxCount; + bool isFifo; +}; extern "C" { diff --git a/core/libs/prx/libkernel/Semaphore/src/Semaphore.cpp b/core/libs/prx/libkernel/Semaphore/src/Semaphore.cpp index 21673c787..e85aba9d3 100644 --- a/core/libs/prx/libkernel/Semaphore/src/Semaphore.cpp +++ b/core/libs/prx/libkernel/Semaphore/src/Semaphore.cpp @@ -1,36 +1,71 @@ #include "prx/libkernel/Semaphore/include/Semaphore.hpp" #include +#include +#include + +KernelSemaPrivate::KernelSemaPrivate(std::int32_t initCount, std::int32_t maxCount, std::string name, bool isFifo) + : name(std::move(name)), tokenCount(initCount), maxCount(maxCount), isFifo(isFifo) { +} extern "C" { int APS5_VABI sceKernelCreateSema(KernelSema* sem, const char* name, uint32_t attr, int init, int max, void* opt) { - (void)sem; - (void)name; - (void)attr; - (void)init; - (void)max; (void)opt; - throw std::runtime_error("sceKernelCreateSema is not implemented"); + if (sem == nullptr || name == nullptr || attr > 2 || init < 0 || max <= 0 || init > max) { + APS5_INVALID_ARG_EX; + } + + *sem = new KernelSemaPrivate(init, max, std::string(name), attr == 1); + return KERNEL_SEMA_OK; } int APS5_VABI sceKernelPollSema(KernelSema sem, int need) { - (void)sem; - (void)need; - throw std::runtime_error("sceKernelPollSema is not implemented"); + if (sem == nullptr || need <= 0) { + APS5_INVALID_ARG_EX; + } + + std::lock_guard lock(sem->mutex); + if (sem->tokenCount < need) { + return KERNEL_SEMA_ERROR_EBUSY; + } + sem->tokenCount -= need; + return KERNEL_SEMA_OK; } int APS5_VABI sceKernelSignalSema(KernelSema sem, int count) { - (void)sem; - (void)count; - throw std::runtime_error("sceKernelSignalSema is not implemented"); + if (sem == nullptr || count <= 0) { + APS5_INVALID_ARG_EX; + } + + std::lock_guard lock(sem->mutex); + if (sem->tokenCount + count > sem->maxCount) { + return KERNEL_SEMA_ERROR_EINVAL; + } + sem->tokenCount += count; + sem->condition.notify_all(); + return KERNEL_SEMA_OK; } int APS5_VABI sceKernelWaitSema(KernelSema sem, int need, KernelUseconds* time) { - (void)sem; - (void)need; - (void)time; - throw std::runtime_error("sceKernelWaitSema is not implemented"); + if (sem == nullptr || need <= 0) { + APS5_INVALID_ARG_EX; + } + + std::unique_lock lock(sem->mutex); + if (time == nullptr) { + sem->condition.wait(lock, [&] { return sem->tokenCount >= need; }); + sem->tokenCount -= need; + return KERNEL_SEMA_OK; + } + + auto timeout = std::chrono::microseconds(*time); + bool acquired = sem->condition.wait_for(lock, timeout, [&] { return sem->tokenCount >= need; }); + if (!acquired) { + return KERNEL_SEMA_ERROR_ETIMEDOUT; + } + sem->tokenCount -= need; + return KERNEL_SEMA_OK; } }