mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2025-04-20 19:44:46 +00:00
libkernel: More proper memory mapped files
This commit is contained in:
parent
c86a00638f
commit
eccd454db2
17 changed files with 336 additions and 115 deletions
|
@ -10,6 +10,7 @@
|
|||
#ifdef _WIN32
|
||||
#include <io.h>
|
||||
#include <share.h>
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#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<HANDLE>(_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 {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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<PVOID>(virtual_addr),
|
||||
HANDLE backing = fd ? fd : backing_handle;
|
||||
ptr = MapViewOfFile3(backing, process, reinterpret_cast<PVOID>(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<PVOID>(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) {
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
||||
} // namespace Libraries::DiscMap
|
||||
|
|
|
@ -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<Core::FileSys::HandleTable>::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,
|
||||
|
|
|
@ -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<Core::FileSys::HandleTable>::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<Core::MemoryProt>(prot);
|
||||
const auto mem_flags = static_cast<Core::MemoryMapFlags>(flags);
|
||||
return memory->MapFile(res, std::bit_cast<VAddr>(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);
|
||||
|
|
|
@ -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 <windows.h>
|
||||
#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
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
} // namespace Libraries::Kernel
|
174
src/core/libraries/kernel/threads/semaphore.cpp
Normal file
174
src/core/libraries/kernel/threads/semaphore.cpp
Normal file
|
@ -0,0 +1,174 @@
|
|||
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <condition_variable>
|
||||
#include <boost/intrusive/list.hpp>
|
||||
#include <pthread.h>
|
||||
#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<boost::intrusive::link_mode<boost::intrusive::normal_link>>;
|
||||
|
||||
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<std::chrono::microseconds>(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<WaitingThread,
|
||||
boost::intrusive::base_hook<ListBaseHook>,
|
||||
boost::intrusive::constant_time_size<false>>;
|
||||
WaitingThreads wait_list;
|
||||
std::atomic<s32> 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
|
19
src/core/libraries/kernel/threads/threads.h
Normal file
19
src/core/libraries/kernel/threads/threads.h
Normal file
|
@ -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
|
|
@ -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<Common::NativeClock>();
|
||||
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
|
||||
|
|
|
@ -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
|
||||
} // namespace Libraries::Rtc
|
||||
|
|
|
@ -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<void*>(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++;
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
} // namespace Core
|
||||
|
|
Loading…
Add table
Reference in a new issue