From eccd454db257b1bb4fcbd8e1234e1326291f5ddb Mon Sep 17 00:00:00 2001 From: raphaelthegreat <47210458+raphaelthegreat@users.noreply.github.com> Date: Tue, 11 Jun 2024 02:55:40 +0300 Subject: [PATCH] libkernel: More proper memory mapped files --- src/common/io_file.cpp | 19 ++ src/common/io_file.h | 3 + src/core/address_space.cpp | 17 +- src/core/address_space.h | 5 +- src/core/libraries/disc_map/disc_map.cpp | 3 +- src/core/libraries/kernel/file_system.cpp | 8 + src/core/libraries/kernel/libkernel.cpp | 61 ++---- .../libraries/kernel/thread_management.cpp | 17 +- .../libraries/kernel/threads/kernel_threads.h | 53 ------ .../{kernel_threads_rwlock.cpp => rwlock.cpp} | 6 +- .../libraries/kernel/threads/semaphore.cpp | 174 ++++++++++++++++++ src/core/libraries/kernel/threads/threads.h | 19 ++ src/core/libraries/kernel/time_management.cpp | 13 ++ src/core/libraries/rtc/rtc.cpp | 3 +- src/core/memory.cpp | 36 +++- src/core/memory.h | 9 + src/emulator.cpp | 5 +- 17 files changed, 336 insertions(+), 115 deletions(-) delete mode 100644 src/core/libraries/kernel/threads/kernel_threads.h rename src/core/libraries/kernel/threads/{kernel_threads_rwlock.cpp => rwlock.cpp} (99%) create mode 100644 src/core/libraries/kernel/threads/semaphore.cpp create mode 100644 src/core/libraries/kernel/threads/threads.h diff --git a/src/common/io_file.cpp b/src/common/io_file.cpp index fda3353ef..fe41c6199 100644 --- a/src/common/io_file.cpp +++ b/src/common/io_file.cpp @@ -10,6 +10,7 @@ #ifdef _WIN32 #include #include +#include #else #include #endif @@ -205,6 +206,24 @@ void IOFile::Close() { } file = nullptr; + +#ifdef _WIN64 + if (file_mapping) { + CloseHandle(file_mapping); + } +#endif +} + +void* IOFile::GetFileMapping() { +#ifdef _WIN64 + if (file_mapping) { + return file_mapping; + } + const int fd = fileno(file); + HANDLE hfile = reinterpret_cast(_get_osfhandle(fd)); + file_mapping = CreateFileMapping(hfile, NULL, PAGE_READWRITE, 0, 0, NULL); + return file_mapping; +#endif } std::string IOFile::ReadString(size_t length) const { diff --git a/src/common/io_file.h b/src/common/io_file.h index 59cfcf7b5..7abd454de 100644 --- a/src/common/io_file.h +++ b/src/common/io_file.h @@ -100,6 +100,8 @@ public: return file != nullptr; } + void* GetFileMapping(); + void Open(const std::filesystem::path& path, FileAccessMode mode, FileType type = FileType::BinaryFile, FileShareFlag flag = FileShareFlag::ShareReadOnly); @@ -207,6 +209,7 @@ private: FileType file_type{}; std::FILE* file = nullptr; + void* file_mapping = nullptr; }; } // namespace Common::FS diff --git a/src/core/address_space.cpp b/src/core/address_space.cpp index 420ed59ab..bec3f9bc1 100644 --- a/src/core/address_space.cpp +++ b/src/core/address_space.cpp @@ -84,7 +84,7 @@ struct AddressSpace::Impl { } } - void* Map(VAddr virtual_addr, PAddr phys_addr, size_t size, ULONG prot) { + void* Map(VAddr virtual_addr, PAddr phys_addr, size_t size, ULONG prot, HANDLE fd = nullptr) { const auto it = placeholders.find(virtual_addr); ASSERT_MSG(it != placeholders.end(), "Cannot map already mapped region"); ASSERT_MSG(virtual_addr >= it->lower() && virtual_addr + size <= it->upper(), @@ -116,7 +116,8 @@ struct AddressSpace::Impl { // Perform the map. void* ptr = nullptr; if (phys_addr != -1) { - ptr = MapViewOfFile3(backing_handle, process, reinterpret_cast(virtual_addr), + HANDLE backing = fd ? fd : backing_handle; + ptr = MapViewOfFile3(backing, process, reinterpret_cast(virtual_addr), phys_addr, size, MEM_REPLACE_PLACEHOLDER, prot, nullptr, 0); } else { ptr = @@ -127,9 +128,9 @@ struct AddressSpace::Impl { return ptr; } - void Unmap(VAddr virtual_addr, PAddr phys_addr, size_t size) { + void Unmap(VAddr virtual_addr, size_t size, bool has_backing) { bool ret; - if (phys_addr != -1) { + if (has_backing) { ret = UnmapViewOfFile2(process, reinterpret_cast(virtual_addr), MEM_PRESERVE_PLACEHOLDER); } else { @@ -251,8 +252,12 @@ void* AddressSpace::Map(VAddr virtual_addr, size_t size, u64 alignment, PAddr ph is_exec ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE); } -void AddressSpace::Unmap(VAddr virtual_addr, size_t size, PAddr phys_addr) { - return impl->Unmap(virtual_addr, phys_addr, size); +void* AddressSpace::MapFile(VAddr virtual_addr, size_t size, size_t offset, void* fd) { + return impl->Map(virtual_addr, offset, size, PAGE_READWRITE, fd); +} + +void AddressSpace::Unmap(VAddr virtual_addr, size_t size, bool has_backing) { + return impl->Unmap(virtual_addr, size, has_backing); } void AddressSpace::Protect(VAddr virtual_addr, size_t size, MemoryPermission perms) { diff --git a/src/core/address_space.h b/src/core/address_space.h index ccaeb199a..547afa375 100644 --- a/src/core/address_space.h +++ b/src/core/address_space.h @@ -62,8 +62,11 @@ public: void* Map(VAddr virtual_addr, size_t size, u64 alignment = 0, PAddr phys_addr = -1, bool exec = false); + /// Memory maps a specified file descriptor. + void* MapFile(VAddr virtual_addr, size_t size, size_t offset, void* fd); + /// Unmaps specified virtual memory area. - void Unmap(VAddr virtual_addr, size_t size, PAddr phys_addr); + void Unmap(VAddr virtual_addr, size_t size, bool has_backing); void Protect(VAddr virtual_addr, size_t size, MemoryPermission perms); diff --git a/src/core/libraries/disc_map/disc_map.cpp b/src/core/libraries/disc_map/disc_map.cpp index 7fd5ed3ce..638adaf29 100644 --- a/src/core/libraries/disc_map/disc_map.cpp +++ b/src/core/libraries/disc_map/disc_map.cpp @@ -36,6 +36,7 @@ int PS4_SYSV_ABI Func_E7EBCE96E92F91F8() { } void RegisterlibSceDiscMap(Core::Loader::SymbolsResolver* sym) { + return; LIB_FUNCTION("fl1eoDnwQ4s", "libSceDiscMap", 1, "libSceDiscMap", 1, 1, sceDiscMapGetPackageSize); LIB_FUNCTION("lbQKqsERhtE", "libSceDiscMap", 1, "libSceDiscMap", 1, 1, @@ -45,4 +46,4 @@ void RegisterlibSceDiscMap(Core::Loader::SymbolsResolver* sym) { LIB_FUNCTION("5+vOlukvkfg", "libSceDiscMap", 1, "libSceDiscMap", 1, 1, Func_E7EBCE96E92F91F8); }; -} // namespace Libraries::DiscMap \ No newline at end of file +} // namespace Libraries::DiscMap diff --git a/src/core/libraries/kernel/file_system.cpp b/src/core/libraries/kernel/file_system.cpp index a454c2754..8d7b5bfae 100644 --- a/src/core/libraries/kernel/file_system.cpp +++ b/src/core/libraries/kernel/file_system.cpp @@ -282,6 +282,13 @@ int PS4_SYSV_ABI sceKernelFStat(int fd, OrbisKernelStat* sb) { return ORBIS_OK; } +s32 PS4_SYSV_ABI sceKernelFsync(int fd) { + auto* h = Common::Singleton::Instance(); + auto* file = h->GetFile(fd); + file->f.Flush(); + return ORBIS_OK; +} + void fileSystemSymbolsRegister(Core::Loader::SymbolsResolver* sym) { LIB_FUNCTION("1G3lF1Gg1k8", "libkernel", 1, "libkernel", 1, 1, sceKernelOpen); LIB_FUNCTION("wuCroIGjt2g", "libScePosix", 1, "libkernel", 1, 1, posix_open); @@ -299,6 +306,7 @@ void fileSystemSymbolsRegister(Core::Loader::SymbolsResolver* sym) { LIB_FUNCTION("E6ao34wPw+U", "libScePosix", 1, "libkernel", 1, 1, posix_stat); LIB_FUNCTION("+r3rMFwItV4", "libkernel", 1, "libkernel", 1, 1, sceKernelPread); LIB_FUNCTION("uWyW3v98sU4", "libkernel", 1, "libkernel", 1, 1, sceKernelCheckReachability); + LIB_FUNCTION("fTx66l5iWIA", "libkernel", 1, "libkernel", 1, 1, sceKernelFsync); // openOrbis (to check if it is valid out of OpenOrbis LIB_FUNCTION("6c3rCVE-fTU", "libkernel", 1, "libkernel", 1, 1, diff --git a/src/core/libraries/kernel/libkernel.cpp b/src/core/libraries/kernel/libkernel.cpp index 8b47606ae..8dc906f54 100644 --- a/src/core/libraries/kernel/libkernel.cpp +++ b/src/core/libraries/kernel/libkernel.cpp @@ -67,50 +67,21 @@ int* PS4_SYSV_ABI __Error() { return &libc_error; } -#define PROT_READ 0x1 -#define PROT_WRITE 0x2 - -int PS4_SYSV_ABI sceKernelMmap(void* addr, u64 len, int prot, int flags, int fd, off_t offset, +int PS4_SYSV_ABI sceKernelMmap(void* addr, u64 len, int prot, int flags, int fd, size_t offset, void** res) { -#ifdef _WIN64 - LOG_INFO(Kernel_Vmm, "called"); - if (prot > 3) { - LOG_ERROR(Kernel_Vmm, "prot = {} not supported", prot); + LOG_INFO(Kernel_Vmm, "called addr = {}, len = {}, prot = {}, flags = {}, fd = {}, offset = {}", + fmt::ptr(addr), len, prot, flags, fd, offset); + auto* h = Common::Singleton::Instance(); + auto* memory = Core::Memory::Instance(); + void* handle = NULL; + if (fd == -1) { + handle = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, len + offset, NULL); + } else { + void* handle = h->GetFile(fd)->f.GetFileMapping(); } - DWORD flProtect; - if (prot & PROT_WRITE) { - flProtect = PAGE_READWRITE; - } - off_t end = len + offset; - HANDLE mmap_fd, h; - if (fd == -1) - mmap_fd = INVALID_HANDLE_VALUE; - else - mmap_fd = (HANDLE)_get_osfhandle(fd); - h = CreateFileMapping(mmap_fd, NULL, flProtect, 0, end, NULL); - int k = GetLastError(); - if (NULL == h) - return -1; - DWORD dwDesiredAccess; - if (prot & PROT_WRITE) - dwDesiredAccess = FILE_MAP_WRITE; - else - dwDesiredAccess = FILE_MAP_READ; - void* ret = MapViewOfFile(h, dwDesiredAccess, 0, offset, len); - if (ret == NULL) { - CloseHandle(h); - ret = nullptr; - } - *res = ret; - return 0; -#else - void* result = mmap(addr, len, prot, flags, fd, offset); - if (result != MAP_FAILED) { - *res = result; - return 0; - } - std::abort(); -#endif + const auto mem_prot = static_cast(prot); + const auto mem_flags = static_cast(flags); + return memory->MapFile(res, std::bit_cast(addr), len, mem_prot, mem_flags, handle, offset); } PS4_SYSV_ABI void* posix_mmap(void* addr, u64 len, int prot, int flags, int fd, u64 offset) { @@ -225,10 +196,16 @@ s32 PS4_SYSV_ABI sceKernelDlsym(s32 handle, const char* symbol, void** addrp) { return ORBIS_OK; } +int PS4_SYSV_ABI sceKernelDebugRaiseException() { + UNREACHABLE(); + return 0; +} + void LibKernel_Register(Core::Loader::SymbolsResolver* sym) { // obj LIB_OBJ("f7uOxY9mM1U", "libkernel", 1, "libkernel", 1, 1, &g_stack_chk_guard); // memory + LIB_FUNCTION("OMDRKKAZ8I4", "libkernel", 1, "libkernel", 1, 1, sceKernelDebugRaiseException); LIB_FUNCTION("rTXw65xmLIA", "libkernel", 1, "libkernel", 1, 1, sceKernelAllocateDirectMemory); LIB_FUNCTION("B+vc2AO2Zrc", "libkernel", 1, "libkernel", 1, 1, sceKernelAllocateMainDirectMemory); diff --git a/src/core/libraries/kernel/thread_management.cpp b/src/core/libraries/kernel/thread_management.cpp index 218a743af..931ce75db 100644 --- a/src/core/libraries/kernel/thread_management.cpp +++ b/src/core/libraries/kernel/thread_management.cpp @@ -8,13 +8,13 @@ #include "common/singleton.h" #include "common/thread.h" #include "core/libraries/error_codes.h" +#include "core/libraries/kernel/threads/threads.h" #include "core/libraries/kernel/thread_management.h" #include "core/libraries/libs.h" #include "core/linker.h" #ifdef _WIN64 #include #endif -#include "core/libraries/kernel/threads/kernel_threads.h" namespace Libraries::Kernel { @@ -1165,7 +1165,19 @@ int PS4_SYSV_ABI posix_pthread_create_name_np(ScePthread* thread, const ScePthre return result; } +using Destructor = void(*)(void*); + +int PS4_SYSV_ABI posix_pthread_key_create(u32* key, Destructor func) { + return pthread_key_create(key, func); +} + +int PS4_SYSV_ABI posix_pthread_setspecific(int key, const void *value) { + return pthread_setspecific(key, value); +} + void pthreadSymbolsRegister(Core::Loader::SymbolsResolver* sym) { + LIB_FUNCTION("mqULNdimTn0", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_key_create); + LIB_FUNCTION("WrOLvHU0yQM", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_setspecific); LIB_FUNCTION("4+h9EzwKF4I", "libkernel", 1, "libkernel", 1, 1, scePthreadAttrSetschedpolicy); LIB_FUNCTION("-Wreprtu0Qs", "libkernel", 1, "libkernel", 1, 1, scePthreadAttrSetdetachstate); LIB_FUNCTION("eXbUSpEaTsA", "libkernel", 1, "libkernel", 1, 1, scePthreadAttrSetinheritsched); @@ -1242,7 +1254,8 @@ void pthreadSymbolsRegister(Core::Loader::SymbolsResolver* sym) { LIB_FUNCTION("CBNtXOoef-E", "libScePosix", 1, "libkernel", 1, 1, posix_sched_get_priority_max); LIB_FUNCTION("m0iS6jNsXds", "libScePosix", 1, "libkernel", 1, 1, posix_sched_get_priority_min); // libs - ThreadsRwlockSymbolsRegister(sym); + RwlockSymbolsRegister(sym); + SemaphoreSymbolsRegister(sym); } } // namespace Libraries::Kernel diff --git a/src/core/libraries/kernel/threads/kernel_threads.h b/src/core/libraries/kernel/threads/kernel_threads.h deleted file mode 100644 index a2a2eb487..000000000 --- a/src/core/libraries/kernel/threads/kernel_threads.h +++ /dev/null @@ -1,53 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include "core/libraries/kernel/thread_management.h" - -namespace Core::Loader { -class SymbolsResolver; -} - -namespace Libraries::Kernel { -/**** - * rwlock calls - */ -int PS4_SYSV_ABI posix_pthread_rwlock_destroy(OrbisPthreadRwlock* rwlock); -int PS4_SYSV_ABI posix_pthread_rwlock_init(OrbisPthreadRwlock* rwlock, - const OrbisPthreadRwlockattr* attr, const char* name); -int PS4_SYSV_ABI posix_pthread_rwlock_rdlock(OrbisPthreadRwlock* rwlock); -int PS4_SYSV_ABI posix_pthread_rwlock_reltimedrdlock_np(); -int PS4_SYSV_ABI posix_pthread_rwlock_reltimedwrlock_np(); -int PS4_SYSV_ABI posix_pthread_rwlock_setname_np(); -int PS4_SYSV_ABI posix_pthread_rwlock_timedrdlock(); -int PS4_SYSV_ABI posix_pthread_rwlock_timedwrlock(); -int PS4_SYSV_ABI posix_pthread_rwlock_tryrdlock(OrbisPthreadRwlock* rwlock); -int PS4_SYSV_ABI posix_pthread_rwlock_trywrlock(OrbisPthreadRwlock* rwlock); -int PS4_SYSV_ABI posix_pthread_rwlock_unlock(OrbisPthreadRwlock* rwlock); -int PS4_SYSV_ABI posix_pthread_rwlock_wrlock(OrbisPthreadRwlock* rwlock); -int PS4_SYSV_ABI posix_pthread_rwlockattr_destroy(OrbisPthreadRwlockattr* attr); -int PS4_SYSV_ABI posix_pthread_rwlockattr_getpshared(); -int PS4_SYSV_ABI posix_pthread_rwlockattr_gettype_np(); -int PS4_SYSV_ABI posix_pthread_rwlockattr_init(OrbisPthreadRwlockattr* attr); -int PS4_SYSV_ABI posix_pthread_rwlockattr_setpshared(); -int PS4_SYSV_ABI posix_pthread_rwlockattr_settype_np(); -int PS4_SYSV_ABI scePthreadRwlockattrDestroy(OrbisPthreadRwlockattr* attr); -int PS4_SYSV_ABI scePthreadRwlockattrGetpshared(); -int PS4_SYSV_ABI scePthreadRwlockattrGettype(); -int PS4_SYSV_ABI scePthreadRwlockattrInit(OrbisPthreadRwlockattr* attr); -int PS4_SYSV_ABI scePthreadRwlockattrSetpshared(); -int PS4_SYSV_ABI scePthreadRwlockattrSettype(); -int PS4_SYSV_ABI scePthreadRwlockDestroy(OrbisPthreadRwlock* rwlock); -int PS4_SYSV_ABI scePthreadRwlockInit(OrbisPthreadRwlock* rwlock, - const OrbisPthreadRwlockattr* attr, const char* name); -int PS4_SYSV_ABI scePthreadRwlockRdlock(OrbisPthreadRwlock* rwlock); -int PS4_SYSV_ABI scePthreadRwlockTimedrdlock(); -int PS4_SYSV_ABI scePthreadRwlockTimedwrlock(); -int PS4_SYSV_ABI scePthreadRwlockTryrdlock(OrbisPthreadRwlock* rwlock); -int PS4_SYSV_ABI scePthreadRwlockTrywrlock(OrbisPthreadRwlock* rwlock); -int PS4_SYSV_ABI scePthreadRwlockUnlock(OrbisPthreadRwlock* rwlock); -int PS4_SYSV_ABI scePthreadRwlockWrlock(OrbisPthreadRwlock* rwlock); - -void ThreadsRwlockSymbolsRegister(Core::Loader::SymbolsResolver* sym); -} // namespace Libraries::Kernel \ No newline at end of file diff --git a/src/core/libraries/kernel/threads/kernel_threads_rwlock.cpp b/src/core/libraries/kernel/threads/rwlock.cpp similarity index 99% rename from src/core/libraries/kernel/threads/kernel_threads_rwlock.cpp rename to src/core/libraries/kernel/threads/rwlock.cpp index c8bf3724a..b4c59092a 100644 --- a/src/core/libraries/kernel/threads/kernel_threads_rwlock.cpp +++ b/src/core/libraries/kernel/threads/rwlock.cpp @@ -4,7 +4,7 @@ #include "common/logging/log.h" #include "core/libraries/error_codes.h" #include "core/libraries/libs.h" -#include "kernel_threads.h" +#include "threads.h" namespace Libraries::Kernel { @@ -282,7 +282,7 @@ int PS4_SYSV_ABI scePthreadRwlockWrlock(OrbisPthreadRwlock* rwlock) { return result; } -void ThreadsRwlockSymbolsRegister(Core::Loader::SymbolsResolver* sym) { +void RwlockSymbolsRegister(Core::Loader::SymbolsResolver* sym) { LIB_FUNCTION("1471ajPzxh0", "libkernel", 1, "libkernel", 1, 1, posix_pthread_rwlock_destroy); LIB_FUNCTION("ytQULN-nhL4", "libkernel", 1, "libkernel", 1, 1, posix_pthread_rwlock_init); LIB_FUNCTION("iGjsr1WAtI0", "libkernel", 1, "libkernel", 1, 1, posix_pthread_rwlock_rdlock); @@ -350,4 +350,4 @@ void ThreadsRwlockSymbolsRegister(Core::Loader::SymbolsResolver* sym) { LIB_FUNCTION("+L98PIbGttk", "libkernel", 1, "libkernel", 1, 1, scePthreadRwlockUnlock); LIB_FUNCTION("mqdNorrB+gI", "libkernel", 1, "libkernel", 1, 1, scePthreadRwlockWrlock); } -} // namespace Libraries::Kernel \ No newline at end of file +} // namespace Libraries::Kernel diff --git a/src/core/libraries/kernel/threads/semaphore.cpp b/src/core/libraries/kernel/threads/semaphore.cpp new file mode 100644 index 000000000..b66f66c52 --- /dev/null +++ b/src/core/libraries/kernel/threads/semaphore.cpp @@ -0,0 +1,174 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include +#include +#include +#include "common/assert.h" +#include "common/scope_exit.h" +#include "common/logging/log.h" +#include "core/libraries/error_codes.h" +#include "core/libraries/libs.h" + +namespace Libraries::Kernel { + +using ListBaseHook = + boost::intrusive::list_base_hook>; + +class Semaphore { +public: + Semaphore(s32 init_count, s32 max_count, bool is_fifo) + : token_count{init_count}, max_count{max_count}, is_fifo{is_fifo} { + + } + + bool Wait(bool can_block, s32 need_count, u64* timeout) { + if (HasAvailableTokens(need_count)) { + return true; + } + if (!can_block) { + return false; + } + + // Create waiting thread object and add it into the list of waiters. + WaitingThread waiter{need_count, is_fifo}; + AddWaiter(waiter); + SCOPE_EXIT { PopWaiter(waiter); }; + + // Perform the wait. + return waiter.Wait(timeout); + } + + bool Signal(s32 signal_count) { + std::scoped_lock lk{mutex}; + if (token_count + signal_count > max_count) { + return false; + } + token_count += signal_count; + + // Wake up threads in order of priority. + for (auto& waiter : wait_list) { + if (waiter.need_count > token_count) { + continue; + } + token_count -= waiter.need_count; + waiter.cv.notify_one(); + } + + return true; + } + +private: + struct WaitingThread : public ListBaseHook { + std::mutex mutex; + std::condition_variable cv; + u32 priority; + s32 need_count; + + explicit WaitingThread(s32 need_count, bool is_fifo) : need_count{need_count} { + if (is_fifo) { + return; + } + // Retrieve calling thread priority for sorting into waiting threads list. + s32 policy; + sched_param param; + pthread_getschedparam(pthread_self(), &policy, ¶m); + priority = param.sched_priority; + } + + bool Wait(u64* timeout) { + std::unique_lock lk{mutex}; + if (!timeout) { + // Wait indefinitely until we are woken up. + cv.wait(lk); + return true; + } + // Wait until timeout runs out, recording how much remaining time there was. + const auto start = std::chrono::high_resolution_clock::now(); + const auto status = cv.wait_for(lk, std::chrono::microseconds(*timeout)); + const auto end = std::chrono::high_resolution_clock::now(); + const auto time = std::chrono::duration_cast(end - start).count(); + *timeout -= time; + return status != std::cv_status::timeout; + } + + bool operator<(const WaitingThread& other) const { + return priority < other.priority; + } + }; + + void AddWaiter(WaitingThread& waiter) { + std::scoped_lock lk{mutex}; + // Insert at the end of the list for FIFO order. + if (is_fifo) { + wait_list.push_back(waiter); + return; + } + // Find the first with priority less then us and insert right before it. + auto it = wait_list.begin(); + while (it != wait_list.end() && it->priority > waiter.priority) { + it++; + } + wait_list.insert(it, waiter); + } + + void PopWaiter(WaitingThread& waiter) { + std::scoped_lock lk{mutex}; + wait_list.erase(WaitingThreads::s_iterator_to(waiter)); + } + + bool HasAvailableTokens(s32 need_count) { + std::scoped_lock lk{mutex}; + if (token_count >= need_count) { + token_count -= need_count; + return true; + } + return false; + } + + using WaitingThreads = boost::intrusive::list, + boost::intrusive::constant_time_size>; + WaitingThreads wait_list; + std::atomic token_count; + std::mutex mutex; + s32 max_count; + bool is_fifo; +}; + +using OrbisKernelSema = Semaphore*; + +s32 PS4_SYSV_ABI sceKernelCreateSema(OrbisKernelSema *sem, const char *pName, u32 attr, + s32 initCount, s32 maxCount, const void* pOptParam) { + if (!pName || attr > 2 || initCount < 0 || maxCount <= 0 || initCount > maxCount) { + LOG_ERROR(Lib_Kernel, "Semaphore creation parameters are invalid!"); + return ORBIS_KERNEL_ERROR_EINVAL; + } + *sem = new Semaphore(initCount, maxCount, attr == 1); + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceKernelWaitSema(OrbisKernelSema sem, s32 needCount, u64* pTimeout) { + ASSERT(sem->Wait(true, needCount, pTimeout)); + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceKernelSignalSema(OrbisKernelSema sem, s32 signalCount) { + if (!sem->Signal(signalCount)) { + return ORBIS_KERNEL_ERROR_EINVAL; + } + return ORBIS_OK; +} + +s32 PS4_SYSV_ABI sceKernelPollSema(OrbisKernelSema sem, s32 needCount) { + ASSERT(sem->Wait(false, needCount, nullptr)); + return ORBIS_OK; +} + +void SemaphoreSymbolsRegister(Core::Loader::SymbolsResolver* sym) { + LIB_FUNCTION("188x57JYp0g", "libkernel", 1, "libkernel", 1, 1, sceKernelCreateSema); + LIB_FUNCTION("Zxa0VhQVTsk", "libkernel", 1, "libkernel", 1, 1, sceKernelWaitSema); + LIB_FUNCTION("4czppHBiriw", "libkernel", 1, "libkernel", 1, 1, sceKernelSignalSema); +} + +} // namespace Libraries::Kernel diff --git a/src/core/libraries/kernel/threads/threads.h b/src/core/libraries/kernel/threads/threads.h new file mode 100644 index 000000000..135bccec5 --- /dev/null +++ b/src/core/libraries/kernel/threads/threads.h @@ -0,0 +1,19 @@ +// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/libraries/kernel/thread_management.h" + +namespace Core::Loader { +class SymbolsResolver; +} + +namespace Libraries::Kernel { + +int PS4_SYSV_ABI scePthreadRwlockattrInit(OrbisPthreadRwlockattr* attr); + +void SemaphoreSymbolsRegister(Core::Loader::SymbolsResolver* sym); +void RwlockSymbolsRegister(Core::Loader::SymbolsResolver* sym); + +} // namespace Libraries::Kernel diff --git a/src/core/libraries/kernel/time_management.cpp b/src/core/libraries/kernel/time_management.cpp index 8c31c550c..0c6aeb44e 100644 --- a/src/core/libraries/kernel/time_management.cpp +++ b/src/core/libraries/kernel/time_management.cpp @@ -134,6 +134,18 @@ int PS4_SYSV_ABI gettimeofday(OrbisKernelTimeval* tp, OrbisKernelTimezone* tz) { return sceKernelGettimeofday(tp); } +s32 PS4_SYSV_ABI sceKernelGettimezone(OrbisKernelTimezone* tz) { + ASSERT(tz); + static int tzflag = 0; + if (!tzflag) { + _tzset(); + tzflag++; + } + tz->tz_minuteswest = _timezone / 60; + tz->tz_dsttime = _daylight; + return ORBIS_OK; +} + void timeSymbolsRegister(Core::Loader::SymbolsResolver* sym) { clock = std::make_unique(); initial_ptc = clock->GetUptime(); @@ -154,6 +166,7 @@ void timeSymbolsRegister(Core::Loader::SymbolsResolver* sym) { LIB_FUNCTION("QBi7HCK03hw", "libkernel", 1, "libkernel", 1, 1, sceKernelClockGettime); LIB_FUNCTION("lLMT9vJAck0", "libkernel", 1, "libkernel", 1, 1, clock_gettime); LIB_FUNCTION("lLMT9vJAck0", "libScePosix", 1, "libkernel", 1, 1, clock_gettime); + LIB_FUNCTION("kOcnerypnQA", "libkernel", 1, "libkernel", 1, 1, sceKernelGettimezone); } } // namespace Libraries::Kernel diff --git a/src/core/libraries/rtc/rtc.cpp b/src/core/libraries/rtc/rtc.cpp index 6bf6a91bc..e330e0df2 100644 --- a/src/core/libraries/rtc/rtc.cpp +++ b/src/core/libraries/rtc/rtc.cpp @@ -248,6 +248,7 @@ int PS4_SYSV_ABI sceRtcTickAddYears() { } void RegisterlibSceRtc(Core::Loader::SymbolsResolver* sym) { + return; LIB_FUNCTION("lPEBYdVX0XQ", "libSceRtc", 1, "libSceRtc", 1, 1, sceRtcCheckValid); LIB_FUNCTION("fNaZ4DbzHAE", "libSceRtc", 1, "libSceRtc", 1, 1, sceRtcCompareTick); LIB_FUNCTION("8Yr143yEnRo", "libSceRtc", 1, "libSceRtc", 1, 1, sceRtcConvertLocalTimeToUtc); @@ -300,4 +301,4 @@ void RegisterlibSceRtc(Core::Loader::SymbolsResolver* sym) { LIB_FUNCTION("-5y2uJ62qS8", "libSceRtc", 1, "libSceRtc", 1, 1, sceRtcTickAddYears); }; -} // namespace Libraries::Rtc \ No newline at end of file +} // namespace Libraries::Rtc diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 946eb8637..1b82f654c 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -83,7 +83,7 @@ int MemoryManager::MapMemory(void** out_addr, VAddr virtual_addr, size_t size, M MemoryMapFlags flags, VMAType type, std::string_view name, bool is_exec, PAddr phys_addr, u64 alignment) { std::scoped_lock lk{mutex}; - if (total_flexible_usage + size > 448_MB) { + if (type == VMAType::Flexible && total_flexible_usage + size > 448_MB) { return SCE_KERNEL_ERROR_ENOMEM; } @@ -132,6 +132,34 @@ int MemoryManager::MapMemory(void** out_addr, VAddr virtual_addr, size_t size, M return ORBIS_OK; } +int MemoryManager::MapFile(void** out_addr, VAddr virtual_addr, size_t size, MemoryProt prot, + MemoryMapFlags flags, void* fd, size_t offset) { + ASSERT(virtual_addr == 0); + virtual_addr = impl.VirtualBase(); + + // Find first free area to map the file. + auto it = FindVMA(virtual_addr); + while (it->second.type != VMAType::Free || it->second.size < size) { + it++; + } + ASSERT(it != vma_map.end()); + + // Map the file. + const VAddr mapped_addr = it->second.base; + impl.MapFile(mapped_addr, size, offset, fd); + + // Add virtual memory area + auto& new_vma = AddMapping(mapped_addr, size); + new_vma.disallow_merge = True(flags & MemoryMapFlags::NoCoalesce); + new_vma.prot = prot; + new_vma.name = "File"; + new_vma.fd = fd; + new_vma.type = VMAType::File; + + *out_addr = std::bit_cast(mapped_addr); + return ORBIS_OK; +} + void MemoryManager::UnmapMemory(VAddr virtual_addr, size_t size) { std::scoped_lock lk{mutex}; @@ -141,7 +169,7 @@ void MemoryManager::UnmapMemory(VAddr virtual_addr, size_t size) { "Attempting to unmap partially mapped range"); const auto type = it->second.type; - const PAddr phys_addr = type == VMAType::Direct ? it->second.phys_base : -1; + const bool has_backing = type == VMAType::Direct || type == VMAType::File; if (type == VMAType::Direct) { UnmapVulkanMemory(virtual_addr, size); } @@ -157,7 +185,7 @@ void MemoryManager::UnmapMemory(VAddr virtual_addr, size_t size) { MergeAdjacent(vma_map, it); // Unmap the memory region. - impl.Unmap(virtual_addr, size, phys_addr); + impl.Unmap(virtual_addr, size, has_backing); } int MemoryManager::QueryProtection(VAddr addr, void** start, void** end, u32* prot) { @@ -206,7 +234,7 @@ int MemoryManager::DirectMemoryQuery(PAddr addr, bool find_next, std::scoped_lock lk{mutex}; auto dmem_area = FindDmemArea(addr); - if (dmem_area->second.is_free && find_next) { + while (dmem_area != dmem_map.end() && dmem_area->second.is_free && find_next) { dmem_area++; } diff --git a/src/core/memory.h b/src/core/memory.h index 27ee5194f..a64d511e6 100644 --- a/src/core/memory.h +++ b/src/core/memory.h @@ -36,8 +36,12 @@ enum class MemoryProt : u32 { enum class MemoryMapFlags : u32 { NoFlags = 0, + Shared = 1, + Private = 2, Fixed = 0x10, NoOverwrite = 0x0080, + NoSync = 0x800, + NoCore = 0x20000, NoCoalesce = 0x400000, }; DECLARE_ENUM_FLAG_OPERATORS(MemoryMapFlags) @@ -50,6 +54,7 @@ enum class VMAType : u32 { Pooled = 4, Stack = 5, Code = 6, + File = 7, }; struct DirectMemoryArea { @@ -81,6 +86,7 @@ struct VirtualMemoryArea { MemoryProt prot = MemoryProt::NoAccess; bool disallow_merge = false; std::string name = ""; + void* fd = nullptr; bool CanMergeWith(const VirtualMemoryArea& next) const { if (disallow_merge || next.disallow_merge) { @@ -123,6 +129,9 @@ public: MemoryMapFlags flags, VMAType type, std::string_view name = "", bool is_exec = false, PAddr phys_addr = -1, u64 alignment = 0); + int MapFile(void** out_addr, VAddr virtual_addr, size_t size, MemoryProt prot, + MemoryMapFlags flags, void* fd, size_t offset); + void UnmapMemory(VAddr virtual_addr, size_t size); int QueryProtection(VAddr addr, void** start, void** end, u32* prot); diff --git a/src/emulator.cpp b/src/emulator.cpp index dd8de3a7d..fbf8066ca 100644 --- a/src/emulator.cpp +++ b/src/emulator.cpp @@ -129,11 +129,12 @@ void Emulator::Run(const std::filesystem::path& file) { void Emulator::LoadSystemModules(const std::filesystem::path& file) { const auto& sys_module_path = Common::FS::GetUserPath(Common::FS::PathType::SysModuleDir); for (const auto& entry : std::filesystem::directory_iterator(sys_module_path)) { - if (entry.path().filename() == "libSceNgs2.sprx") { + if (entry.path().filename() == "libSceNgs2.sprx" || entry.path().filename() == "libSceRtc.sprx" || + entry.path().filename() == "libSceDiscMap.sprx") { LOG_INFO(Loader, "Loading {}", entry.path().string().c_str()); linker->LoadModule(entry.path()); } } } -} // namespace Core \ No newline at end of file +} // namespace Core