diff --git a/CMakeLists.txt b/CMakeLists.txt index 520ba4c8..a79c1bd6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -100,7 +100,12 @@ set(GNM_LIB src/core/libraries/gnmdriver/gnmdriver.cpp src/core/libraries/gnmdriver/gnmdriver.h ) -set(KERNEL_LIB src/core/libraries/kernel/cpu_management.cpp +set(KERNEL_LIB + src/core/libraries/kernel/event_flag/event_flag.cpp + src/core/libraries/kernel/event_flag/event_flag.h + src/core/libraries/kernel/event_flag/event_flag_obj.cpp + src/core/libraries/kernel/event_flag/event_flag_obj.h + src/core/libraries/kernel/cpu_management.cpp src/core/libraries/kernel/cpu_management.h src/core/libraries/kernel/event_queue.cpp src/core/libraries/kernel/event_queue.h diff --git a/src/core/libraries/kernel/event_flag/event_flag.cpp b/src/core/libraries/kernel/event_flag/event_flag.cpp new file mode 100644 index 00000000..01efad70 --- /dev/null +++ b/src/core/libraries/kernel/event_flag/event_flag.cpp @@ -0,0 +1,141 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include +#include "common/logging/log.h" +#include "core/libraries/error_codes.h" +#include "core/libraries/libs.h" +#include "event_flag.h" + +namespace Libraries::Kernel { +int PS4_SYSV_ABI sceKernelCreateEventFlag(OrbisKernelEventFlag* ef, const char* pName, u32 attr, + u64 initPattern, + const OrbisKernelEventFlagOptParam* pOptParam) { + LOG_INFO(Kernel_Event, "called name = {} attr = {:#x} initPattern = {:#x}", pName, attr, + initPattern); + if (ef == nullptr || pName == nullptr) { + return ORBIS_KERNEL_ERROR_EINVAL; + } + if (pOptParam || !pName || + attr > (ORBIS_KERNEL_EVF_ATTR_MULTI | ORBIS_KERNEL_EVF_ATTR_TH_PRIO)) { + return SCE_KERNEL_ERROR_EINVAL; + } + + if (strlen(pName) >= 32) { + return ORBIS_KERNEL_ERROR_ENAMETOOLONG; + } + + bool single = true; + bool fifo = true; + + switch (attr) { + case 0x10: + case 0x11: + single = true; + fifo = true; + break; + case 0x20: + case 0x21: + single = false; + fifo = true; + break; + case 0x22: + single = false; + fifo = false; + break; + default: + UNREACHABLE(); + } + + *ef = new EventFlagInternal(std::string(pName), single, fifo, initPattern); + return ORBIS_OK; +} +int PS4_SYSV_ABI sceKernelDeleteEventFlag(OrbisKernelEventFlag ef) { + LOG_ERROR(Kernel_Event, "(STUBBED) called"); + return ORBIS_OK; +} +int PS4_SYSV_ABI sceKernelOpenEventFlag() { + LOG_ERROR(Kernel_Event, "(STUBBED) called"); + return ORBIS_OK; +} +int PS4_SYSV_ABI sceKernelCloseEventFlag() { + LOG_ERROR(Kernel_Event, "(STUBBED) called"); + return ORBIS_OK; +} +int PS4_SYSV_ABI sceKernelClearEventFlag(OrbisKernelEventFlag ef, u64 bitPattern) { + LOG_ERROR(Kernel_Event, "(STUBBED) called"); + return ORBIS_OK; +} +int PS4_SYSV_ABI sceKernelCancelEventFlag(OrbisKernelEventFlag ef, u64 setPattern, + int* pNumWaitThreads) { + LOG_ERROR(Kernel_Event, "(STUBBED) called"); + return ORBIS_OK; +} +int PS4_SYSV_ABI sceKernelSetEventFlag(OrbisKernelEventFlag ef, u64 bitPattern) { + LOG_ERROR(Kernel_Event, "(STUBBED) called"); + return ORBIS_OK; +} +int PS4_SYSV_ABI sceKernelPollEventFlag(OrbisKernelEventFlag ef, u64 bitPattern, u32 waitMode, + u64* pResultPat) { + LOG_ERROR(Kernel_Event, "(STUBBED) called"); + return ORBIS_OK; +} +int PS4_SYSV_ABI sceKernelWaitEventFlag(OrbisKernelEventFlag ef, u64 bitPattern, u32 waitMode, + u64* pResultPat, OrbisKernelUseconds* pTimeout) { + LOG_INFO(Kernel_Event, "called bitPattern = {:#x} waitMode = {:#x}", bitPattern, waitMode); + if (ef == nullptr) { + return ORBIS_KERNEL_ERROR_ESRCH; + } + + if (bitPattern == 0) { + return ORBIS_KERNEL_ERROR_EINVAL; + } + + EventFlagInternal::WaitMode wait = EventFlagInternal::WaitMode::And; + EventFlagInternal::ClearMode clear = EventFlagInternal::ClearMode::None; + + switch (waitMode & 0xf) { + case 0x01: + wait = EventFlagInternal::WaitMode::And; + break; + case 0x02: + wait = EventFlagInternal::WaitMode::Or; + break; + default: + UNREACHABLE(); + } + + switch (waitMode & 0xf0) { + case 0x00: + clear = EventFlagInternal::ClearMode::None; + break; + case 0x10: + clear = EventFlagInternal::ClearMode::All; + break; + case 0x20: + clear = EventFlagInternal::ClearMode::Bits; + break; + default: + UNREACHABLE(); + } + + auto result = ef->Wait(bitPattern, wait, clear, pResultPat, pTimeout); + + if (result != ORBIS_OK) { + LOG_ERROR(Kernel_Event, "returned {}", result); + } + + return result; +} +void RegisterKernelEventFlag(Core::Loader::SymbolsResolver* sym) { + LIB_FUNCTION("PZku4ZrXJqg", "libkernel", 1, "libkernel", 1, 1, sceKernelCancelEventFlag); + LIB_FUNCTION("7uhBFWRAS60", "libkernel", 1, "libkernel", 1, 1, sceKernelClearEventFlag); + LIB_FUNCTION("s9-RaxukuzQ", "libkernel", 1, "libkernel", 1, 1, sceKernelCloseEventFlag); + LIB_FUNCTION("BpFoboUJoZU", "libkernel", 1, "libkernel", 1, 1, sceKernelCreateEventFlag); + LIB_FUNCTION("8mql9OcQnd4", "libkernel", 1, "libkernel", 1, 1, sceKernelDeleteEventFlag); + LIB_FUNCTION("1vDaenmJtyA", "libkernel", 1, "libkernel", 1, 1, sceKernelOpenEventFlag); + LIB_FUNCTION("9lvj5DjHZiA", "libkernel", 1, "libkernel", 1, 1, sceKernelPollEventFlag); + LIB_FUNCTION("IOnSvHzqu6A", "libkernel", 1, "libkernel", 1, 1, sceKernelSetEventFlag); + LIB_FUNCTION("JTvBflhYazQ", "libkernel", 1, "libkernel", 1, 1, sceKernelWaitEventFlag); +} +} // namespace Libraries::Kernel \ No newline at end of file diff --git a/src/core/libraries/kernel/event_flag/event_flag.h b/src/core/libraries/kernel/event_flag/event_flag.h new file mode 100644 index 00000000..2147e3f1 --- /dev/null +++ b/src/core/libraries/kernel/event_flag/event_flag.h @@ -0,0 +1,40 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/types.h" +#include "event_flag_codes.h" +#include "event_flag_obj.h" + +namespace Core::Loader { +class SymbolsResolver; +} + +namespace Libraries::Kernel { + +using OrbisKernelUseconds = u32; +using OrbisKernelEventFlag = EventFlagInternal*; + +struct OrbisKernelEventFlagOptParam { + size_t size; +}; + +int PS4_SYSV_ABI sceKernelCreateEventFlag(OrbisKernelEventFlag* ef, const char* pName, u32 attr, + u64 initPattern, + const OrbisKernelEventFlagOptParam* pOptParam); +int PS4_SYSV_ABI sceKernelDeleteEventFlag(OrbisKernelEventFlag ef); +int PS4_SYSV_ABI sceKernelOpenEventFlag(); +int PS4_SYSV_ABI sceKernelCloseEventFlag(); +int PS4_SYSV_ABI sceKernelClearEventFlag(OrbisKernelEventFlag ef, u64 bitPattern); +int PS4_SYSV_ABI sceKernelCancelEventFlag(OrbisKernelEventFlag ef, u64 setPattern, + int* pNumWaitThreads); +int PS4_SYSV_ABI sceKernelSetEventFlag(OrbisKernelEventFlag ef, u64 bitPattern); +int PS4_SYSV_ABI sceKernelPollEventFlag(OrbisKernelEventFlag ef, u64 bitPattern, u32 waitMode, + u64* pResultPat); +int PS4_SYSV_ABI sceKernelWaitEventFlag(OrbisKernelEventFlag ef, u64 bitPattern, u32 waitMode, + u64* pResultPat, OrbisKernelUseconds* pTimeout); + +void RegisterKernelEventFlag(Core::Loader::SymbolsResolver* sym); + +} // namespace Libraries::Kernel \ No newline at end of file diff --git a/src/core/libraries/kernel/event_flag/event_flag_codes.h b/src/core/libraries/kernel/event_flag/event_flag_codes.h new file mode 100644 index 00000000..92b265c8 --- /dev/null +++ b/src/core/libraries/kernel/event_flag/event_flag_codes.h @@ -0,0 +1,14 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +constexpr int ORBIS_KERNEL_EVF_ATTR_TH_FIFO = 0x01; +constexpr int ORBIS_KERNEL_EVF_ATTR_TH_PRIO = 0x02; +constexpr int ORBIS_KERNEL_EVF_ATTR_SINGLE = 0x10; +constexpr int ORBIS_KERNEL_EVF_ATTR_MULTI = 0x20; + +constexpr int ORBIS_KERNEL_EVF_WAITMODE_AND = 0x01; +constexpr int ORBIS_KERNEL_EVF_WAITMODE_OR = 0x02; +constexpr int ORBIS_KERNEL_EVF_WAITMODE_CLEAR_ALL = 0x10; +constexpr int ORBIS_KERNEL_EVF_WAITMODE_CLEAR_PAT = 0x20; \ No newline at end of file diff --git a/src/core/libraries/kernel/event_flag/event_flag_obj.cpp b/src/core/libraries/kernel/event_flag/event_flag_obj.cpp new file mode 100644 index 00000000..86250c35 --- /dev/null +++ b/src/core/libraries/kernel/event_flag/event_flag_obj.cpp @@ -0,0 +1,73 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include +#include "event_flag_obj.h" + +namespace Libraries::Kernel { +int EventFlagInternal::Wait(u64 bits, WaitMode wait_mode, ClearMode clear_mode, u64* result, + u32* ptr_micros) { + std::unique_lock lock{m_mutex}; + + uint32_t micros = 0; + bool infinitely = true; + if (ptr_micros != nullptr) { + micros = *ptr_micros; + infinitely = false; + } + + if (m_single_thread && m_waiting_threads > 0) { + return ORBIS_KERNEL_ERROR_EPERM; + } + + auto const start = std::chrono::system_clock::now(); + m_waiting_threads++; + auto waitFunc = [this, wait_mode, bits] { + return (m_status == Status::Canceled || m_status == Status::Deleted || + (wait_mode == WaitMode::And && (m_bits & bits) == bits) || + (wait_mode == WaitMode::Or && (m_bits & bits) != 0)); + }; + + if (infinitely) { + m_cond_var.wait(lock, waitFunc); + } else { + if (!m_cond_var.wait_for(lock, std::chrono::microseconds(micros), waitFunc)) { + if (result != nullptr) { + *result = m_bits; + } + *ptr_micros = 0; + --m_waiting_threads; + return ORBIS_KERNEL_ERROR_ETIMEDOUT; + } + } + --m_waiting_threads; + if (result != nullptr) { + *result = m_bits; + } + + auto elapsed = std::chrono::duration_cast( + std::chrono::system_clock::now() - start) + .count(); + if (result != nullptr) { + *result = m_bits; + } + + if (ptr_micros != nullptr) { + *ptr_micros = (elapsed >= micros ? 0 : micros - elapsed); + } + + if (m_status == Status::Canceled) { + return ORBIS_KERNEL_ERROR_ECANCELED; + } else if (m_status == Status::Deleted) { + return ORBIS_KERNEL_ERROR_EACCES; + } + + if (clear_mode == ClearMode::All) { + m_bits = 0; + } else if (clear_mode == ClearMode::Bits) { + m_bits &= ~bits; + } + + return ORBIS_OK; +} +} // namespace Libraries::Kernel \ No newline at end of file diff --git a/src/core/libraries/kernel/event_flag/event_flag_obj.h b/src/core/libraries/kernel/event_flag/event_flag_obj.h new file mode 100644 index 00000000..9284ec56 --- /dev/null +++ b/src/core/libraries/kernel/event_flag/event_flag_obj.h @@ -0,0 +1,34 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once +#include +#include +#include "common/types.h" + +namespace Libraries::Kernel { + +class EventFlagInternal { +public: + enum class ClearMode { None, All, Bits }; + + enum class WaitMode { And, Or }; + + EventFlagInternal(const std::string& name, bool single, bool fifo, uint64_t bits) + : m_name(name), m_single_thread(single), m_fifo(fifo), m_bits(bits){}; + + int Wait(u64 bits, WaitMode wait_mode, ClearMode clear_mode, u64* result, u32* ptr_micros); + +private: + enum class Status { Set, Canceled, Deleted }; + + std::mutex m_mutex; + std::condition_variable m_cond_var; + Status m_status = Status::Set; + int m_waiting_threads = 0; + std::string m_name; + bool m_single_thread = false; + bool m_fifo = false; + u64 m_bits = 0; +}; +} // namespace Libraries::Kernel \ No newline at end of file diff --git a/src/core/libraries/kernel/libkernel.cpp b/src/core/libraries/kernel/libkernel.cpp index 3f3a3624..a6c2231a 100644 --- a/src/core/libraries/kernel/libkernel.cpp +++ b/src/core/libraries/kernel/libkernel.cpp @@ -8,6 +8,7 @@ #include "common/singleton.h" #include "core/libraries/error_codes.h" #include "core/libraries/kernel/cpu_management.h" +#include "core/libraries/kernel/event_flag/event_flag.h" #include "core/libraries/kernel/event_queues.h" #include "core/libraries/kernel/file_system.h" #include "core/libraries/kernel/libkernel.h" @@ -231,6 +232,7 @@ void LibKernel_Register(Core::Loader::SymbolsResolver* sym) { Libraries::Kernel::fileSystemSymbolsRegister(sym); Libraries::Kernel::timeSymbolsRegister(sym); Libraries::Kernel::pthreadSymbolsRegister(sym); + Libraries::Kernel::RegisterKernelEventFlag(sym); // temp LIB_FUNCTION("NWtTN10cJzE", "libSceLibcInternalExt", 1, "libSceLibcInternal", 1, 1,