Improve linux support

This commit is contained in:
IndecisiveTurtle 2024-06-15 03:43:42 +03:00
parent b031ba0719
commit 5834b82efb
25 changed files with 193 additions and 126 deletions

View file

@ -224,8 +224,6 @@ set(COMMON src/common/logging/backend.cpp
src/common/debug.h
src/common/disassembler.cpp
src/common/disassembler.h
src/common/discord.cpp
src/common/discord.h
src/common/endian.h
src/common/enum.h
src/common/io_file.cpp
@ -509,7 +507,7 @@ endif()
create_target_directory_groups(shadps4)
target_link_libraries(shadps4 PRIVATE magic_enum::magic_enum fmt::fmt toml11::toml11 tsl::robin_map xbyak Tracy::TracyClient)
target_link_libraries(shadps4 PRIVATE discord-rpc boost vma sirit vulkan-headers xxhash Zydis SPIRV glslang SDL3-shared)
target_link_libraries(shadps4 PRIVATE boost vma sirit vulkan-headers xxhash Zydis SPIRV glslang SDL3-shared)
if (NOT ENABLE_QT_GUI)
target_link_libraries(shadps4 PRIVATE SDL3-shared)

View file

@ -216,17 +216,20 @@ void IOFile::Close() {
#endif
}
void* IOFile::GetFileMapping() {
#ifdef _WIN64
uintptr_t IOFile::GetFileMapping() {
if (file_mapping) {
return file_mapping;
}
#ifdef _WIN64
const int fd = fileno(file);
HANDLE hfile = reinterpret_cast<HANDLE>(_get_osfhandle(fd));
file_mapping =
CreateFileMapping2(hfile, NULL, FILE_MAP_READ, PAGE_READONLY, SEC_COMMIT, 0, NULL, NULL, 0);
ASSERT_MSG(file_mapping, "{}", Common::GetLastErrorMsg());
return file_mapping;
#else
file_mapping = fileno(file);
return file_mapping;
#endif
}

View file

@ -100,7 +100,7 @@ public:
return file != nullptr;
}
void* GetFileMapping();
uintptr_t GetFileMapping();
void Open(const std::filesystem::path& path, FileAccessMode mode,
FileType type = FileType::BinaryFile,
@ -214,7 +214,7 @@ private:
FileType file_type{};
std::FILE* file = nullptr;
void* file_mapping = nullptr;
uintptr_t file_mapping = 0;
};
} // namespace Common::FS

View file

@ -255,13 +255,14 @@ struct AddressSpace::Impl {
m_free_regions.insert({start_addr, start_addr + virtual_size});
}
void* Map(VAddr virtual_addr, PAddr phys_addr, size_t size, PosixPageProtection prot) {
void* Map(VAddr virtual_addr, PAddr phys_addr, size_t size, PosixPageProtection prot,
int fd = -1) {
m_free_regions.subtract({virtual_addr, virtual_addr + size});
const int fd = phys_addr != -1 ? backing_fd : -1;
const int host_offset = phys_addr != -1 ? phys_addr : 0;
const int handle = phys_addr != -1 ? (fd == -1 ? backing_fd : fd) : -1;
const off_t host_offset = phys_addr != -1 ? phys_addr : 0;
const int flag = phys_addr != -1 ? MAP_SHARED : (MAP_ANONYMOUS | MAP_PRIVATE);
void* ret = mmap(reinterpret_cast<void*>(virtual_addr), size, prot, MAP_FIXED | flag, fd,
host_offset);
void* ret = mmap(reinterpret_cast<void*>(virtual_addr), size, prot, MAP_FIXED | flag,
handle, host_offset);
ASSERT_MSG(ret != MAP_FAILED, "mmap failed: {}", strerror(errno));
return ret;
}
@ -324,7 +325,7 @@ void* AddressSpace::Map(VAddr virtual_addr, size_t size, u64 alignment, PAddr ph
is_exec ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE);
}
void* AddressSpace::MapFile(VAddr virtual_addr, size_t size, size_t offset, void* fd) {
void* AddressSpace::MapFile(VAddr virtual_addr, size_t size, size_t offset, uintptr_t fd) {
return impl->Map(virtual_addr, offset, size, fd ? PAGE_READONLY : PAGE_READWRITE, fd);
}

View file

@ -20,7 +20,7 @@ DECLARE_ENUM_FLAG_OPERATORS(MemoryPermission)
constexpr VAddr SYSTEM_RESERVED = 0x800000000ULL;
constexpr VAddr CODE_BASE_OFFSET = 0x100000000ULL;
constexpr VAddr SYSTEM_MANAGED_MIN = 0x0000040000ULL;
constexpr VAddr SYSTEM_MANAGED_MIN = 0x00000400000ULL;
constexpr VAddr SYSTEM_MANAGED_MAX = 0x07FFFFBFFFULL;
constexpr VAddr USER_MIN = 0x1000000000ULL;
constexpr VAddr USER_MAX = 0xFBFFFFFFFFULL;
@ -63,7 +63,7 @@ public:
bool exec = false);
/// Memory maps a specified file descriptor.
void* MapFile(VAddr virtual_addr, size_t size, size_t offset, void* fd);
void* MapFile(VAddr virtual_addr, size_t size, size_t offset, uintptr_t fd);
/// Unmaps specified virtual memory area.
void Unmap(VAddr virtual_addr, size_t size, bool has_backing);

View file

@ -989,7 +989,7 @@ s32 PS4_SYSV_ABI sceGnmSetEmbeddedVsShader(u32* cmdbuf, u32 size, u32 shader_id,
// a check for zero in the upper part of shader address. In our case, the address is a
// pointer to a stack memory, so the check will likely fail. To workaround it we will
// repeat set shader functionality here as it is trivial.
cmdbuf = PM4CmdSetData::SetShReg(cmdbuf, 0x48u, vs_regs[0], 0u); // SPI_SHADER_PGM_LO_VS
cmdbuf = PM4CmdSetData::SetShReg(cmdbuf, 0x48u, vs_regs[0], vs_regs[1]); // SPI_SHADER_PGM_LO_VS
cmdbuf =
PM4CmdSetData::SetShReg(cmdbuf, 0x4au, vs_regs[2], vs_regs[3]); // SPI_SHADER_PGM_RSRC1_VS
cmdbuf = PM4CmdSetData::SetContextReg(cmdbuf, 0x207u, vs_regs[6]); // PA_CL_VS_OUT_CNTL

View file

@ -31,6 +31,10 @@ int PS4_SYSV_ABI sceKernelOpen(const char* path, int flags, u16 mode) {
bool direct = (flags & ORBIS_KERNEL_O_DIRECT) != 0;
bool directory = (flags & ORBIS_KERNEL_O_DIRECTORY) != 0;
if (std::string_view{path} == "/dev/console" || std::string_view{path} == "/dev/deci_tty6") {
return ORBIS_OK;
}
if (directory) {
LOG_ERROR(Kernel_Fs, "called on directory");
} else {

View file

@ -73,17 +73,16 @@ int PS4_SYSV_ABI sceKernelMmap(void* addr, u64 len, int prot, int flags, int fd,
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 {
handle = h->GetFile(fd)->f.GetFileMapping();
}
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);
if (fd == -1) {
return memory->MapMemory(res, std::bit_cast<VAddr>(addr), len, mem_prot, mem_flags,
Core::VMAType::Flexible);
} else {
const uintptr_t handle = h->GetFile(fd)->f.GetFileMapping();
return memory->MapFile(res, std::bit_cast<VAddr>(addr), len, mem_prot, mem_flags, handle,
offset);
}
}
void* PS4_SYSV_ABI posix_mmap(void* addr, u64 len, int prot, int flags, int fd, u64 offset) {
@ -248,6 +247,15 @@ s32 PS4_SYSV_ABI sceKernelGetModuleInfoForUnwind(VAddr addr, int flags,
return ORBIS_OK;
}
int PS4_SYSV_ABI sceKernelGetModuleInfoFromAddr(VAddr addr, int flags,
Core::OrbisKernelModuleInfoEx* info) {
LOG_INFO(Lib_Kernel, "called addr = {:#x}, flags = {:#x}", addr, flags);
auto* linker = Common::Singleton<Core::Linker>::Instance();
auto* module = linker->FindByAddress(addr);
*info = module->GetModuleInfoEx();
return ORBIS_OK;
}
int PS4_SYSV_ABI sceKernelDebugRaiseException() {
UNREACHABLE();
return 0;
@ -267,6 +275,10 @@ int PS4_SYSV_ABI sceKernelGetCpumode() {
return 5;
}
void PS4_SYSV_ABI sched_yield() {
return std::this_thread::yield();
}
void LibKernel_Register(Core::Loader::SymbolsResolver* sym) {
// obj
LIB_OBJ("f7uOxY9mM1U", "libkernel", 1, "libkernel", 1, 1, &g_stack_chk_guard);
@ -292,6 +304,7 @@ void LibKernel_Register(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("wzvqT4UqKX8", "libkernel", 1, "libkernel", 1, 1, sceKernelLoadStartModule);
LIB_FUNCTION("LwG8g3niqwA", "libkernel", 1, "libkernel", 1, 1, sceKernelDlsym);
LIB_FUNCTION("RpQJJVKTiFM", "libkernel", 1, "libkernel", 1, 1, sceKernelGetModuleInfoForUnwind);
LIB_FUNCTION("f7KBOafysXo", "libkernel", 1, "libkernel", 1, 1, sceKernelGetModuleInfoFromAddr);
LIB_FUNCTION("VOx8NGmHXTs", "libkernel", 1, "libkernel", 1, 1, sceKernelGetCpumode);
// equeue
@ -326,6 +339,7 @@ void LibKernel_Register(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("NWtTN10cJzE", "libSceLibcInternalExt", 1, "libSceLibcInternal", 1, 1,
sceLibcHeapGetTraceInfo);
LIB_FUNCTION("FxVZqBAA7ks", "libkernel", 1, "libkernel", 1, 1, ps4__write);
LIB_FUNCTION("6XG4B33N09g", "libScePosix", 1, "libkernel", 1, 1, sched_yield);
}
} // namespace Libraries::Kernel

View file

@ -90,10 +90,10 @@ s32 PS4_SYSV_ABI sceKernelVirtualQuery(const void* addr, int flags, OrbisVirtual
int PS4_SYSV_ABI sceKernelMapNamedDirectMemory(void** addr, u64 len, int prot, int flags,
s64 directMemoryStart, u64 alignment,
const char* name) {
LOG_INFO(
Kernel_Vmm,
"len = {:#x}, prot = {:#x}, flags = {:#x}, directMemoryStart = {:#x}, alignment = {:#x}",
len, prot, flags, directMemoryStart, alignment);
LOG_INFO(Kernel_Vmm,
"addr = {}, len = {:#x}, prot = {:#x}, flags = {:#x}, directMemoryStart = {:#x}, "
"alignment = {:#x}",
fmt::ptr(*addr), len, prot, flags, directMemoryStart, alignment);
if (len == 0 || !Common::Is16KBAligned(len)) {
LOG_ERROR(Kernel_Vmm, "Map size is either zero or not 16KB aligned!");
@ -120,11 +120,7 @@ int PS4_SYSV_ABI sceKernelMapNamedDirectMemory(void** addr, u64 len, int prot, i
int PS4_SYSV_ABI sceKernelMapDirectMemory(void** addr, u64 len, int prot, int flags,
s64 directMemoryStart, u64 alignment) {
LOG_INFO(Kernel_Vmm,
"redirected to sceKernelMapNamedDirectMemory: "
"len = {:#x}, prot = {:#x}, flags = {:#x}, directMemoryStart = {:#x}, alignment = "
"{:#x}",
len, prot, flags, directMemoryStart, alignment);
LOG_INFO(Kernel_Vmm, "called, redirected to sceKernelMapNamedDirectMemory");
return sceKernelMapNamedDirectMemory(addr, len, prot, flags, directMemoryStart, alignment, "");
}

View file

@ -5,6 +5,7 @@
#include <thread>
#include <semaphore.h>
#include "common/assert.h"
#include "common/error.h"
#include "common/logging/log.h"
#include "common/singleton.h"
#include "common/thread.h"
@ -138,9 +139,8 @@ int PS4_SYSV_ABI scePthreadAttrGetdetachstate(const ScePthreadAttr* attr, int* s
return SCE_KERNEL_ERROR_EINVAL;
}
// int result = pthread_attr_getdetachstate(&(*attr)->p, state);
// int result = pthread_attr_getdetachstate(&(*attr)->pth_attr, state);
int result = 0;
*state = ((*attr)->detached ? PTHREAD_CREATE_DETACHED : PTHREAD_CREATE_JOINABLE);
switch (*state) {
@ -174,12 +174,9 @@ int PS4_SYSV_ABI scePthreadAttrSetdetachstate(ScePthreadAttr* attr, int detachst
UNREACHABLE_MSG("Invalid detachstate: {}", detachstate);
}
// int result = pthread_attr_setdetachstate(&(*attr)->pth_attr, pstate); doesn't seem to work
// correctly
// int result = pthread_attr_setdetachstate(&(*attr)->pth_attr, pstate);
int result = 0;
(*attr)->detached = (pstate == PTHREAD_CREATE_DETACHED);
return result == 0 ? SCE_OK : SCE_KERNEL_ERROR_EINVAL;
}
@ -246,7 +243,6 @@ int PS4_SYSV_ABI scePthreadAttrSetschedparam(ScePthreadAttr* attr,
}
int PS4_SYSV_ABI scePthreadAttrGetschedpolicy(const ScePthreadAttr* attr, int* policy) {
if (policy == nullptr || attr == nullptr || *attr == nullptr) {
return SCE_KERNEL_ERROR_EINVAL;
}
@ -275,16 +271,26 @@ int PS4_SYSV_ABI scePthreadAttrSetschedpolicy(ScePthreadAttr* attr, int policy)
return SCE_KERNEL_ERROR_EINVAL;
}
int ppolicy = SCHED_OTHER; // winpthreads only supports SCHED_OTHER
if (policy != SCHED_OTHER) {
LOG_ERROR(Kernel_Pthread, "policy={} not supported by winpthreads\n", policy);
int ppolicy = SCHED_OTHER;
switch (policy) {
case 0:
ppolicy = SCHED_OTHER;
break;
case 1:
ppolicy = SCHED_FIFO;
break;
case 3:
ppolicy = SCHED_OTHER;
break;
default:
UNREACHABLE();
}
(*attr)->policy = policy;
int result = pthread_attr_setschedpolicy(&(*attr)->pth_attr, ppolicy);
return result == 0 ? SCE_OK : SCE_KERNEL_ERROR_EINVAL;
}
ScePthread PS4_SYSV_ABI scePthreadSelf() {
return g_pthread_self;
}
@ -298,7 +304,6 @@ int PS4_SYSV_ABI scePthreadAttrSetaffinity(ScePthreadAttr* pattr,
}
(*pattr)->affinity = mask;
return SCE_OK;
}
@ -391,16 +396,18 @@ int PS4_SYSV_ABI scePthreadSetaffinity(ScePthread thread, const /*SceKernelCpuma
return result;
}
void* createMutex(void* addr) {
if (addr == nullptr || *static_cast<ScePthreadMutex*>(addr) != nullptr) {
ScePthreadMutex* createMutex(ScePthreadMutex* addr) {
if (addr == nullptr || *addr != nullptr) {
return addr;
}
static std::mutex mutex;
std::scoped_lock lk{mutex};
auto vaddr = reinterpret_cast<u64>(addr);
if (*addr != nullptr) {
return addr;
}
const VAddr vaddr = reinterpret_cast<VAddr>(addr);
std::string name = fmt::format("mutex{:#x}", vaddr);
scePthreadMutexInit(static_cast<ScePthreadMutex*>(addr), nullptr, name.c_str());
scePthreadMutexInit(addr, nullptr, name.c_str());
return addr;
}
@ -468,7 +475,7 @@ int PS4_SYSV_ABI scePthreadMutexattrInit(ScePthreadMutexattr* attr) {
int result = pthread_mutexattr_init(&(*attr)->pth_mutex_attr);
result = (result == 0 ? scePthreadMutexattrSettype(attr, 2) : result);
result = (result == 0 ? scePthreadMutexattrSettype(attr, 1) : result);
result = (result == 0 ? scePthreadMutexattrSetprotocol(attr, 0) : result);
switch (result) {
@ -519,22 +526,20 @@ int PS4_SYSV_ABI scePthreadMutexattrSetprotocol(ScePthreadMutexattr* attr, int p
UNREACHABLE_MSG("Invalid protocol: {}", protocol);
}
int result = 0; // pthread_mutexattr_setprotocol(&(*attr)->p, pprotocol); //it appears that
// pprotocol has issues in winpthreads
int result = pthread_mutexattr_setprotocol(&(*attr)->pth_mutex_attr, pprotocol);
(*attr)->pprotocol = pprotocol;
return result == 0 ? SCE_OK : SCE_KERNEL_ERROR_EINVAL;
}
int PS4_SYSV_ABI scePthreadMutexLock(ScePthreadMutex* mutex) {
mutex = static_cast<ScePthreadMutex*>(createMutex(mutex));
int PS4_SYSV_ABI scePthreadMutexLock(ScePthreadMutex* mutex) {
mutex = createMutex(mutex);
if (mutex == nullptr) {
return SCE_KERNEL_ERROR_EINVAL;
}
int result = pthread_mutex_lock(&(*mutex)->pth_mutex);
if (result != 0) {
LOG_TRACE(Kernel_Pthread, "name={}, result={}", (*mutex)->name, result);
LOG_TRACE(Kernel_Pthread, "Locked name={}, result={}", (*mutex)->name, result);
}
switch (result) {
case 0:
@ -549,20 +554,20 @@ int PS4_SYSV_ABI scePthreadMutexLock(ScePthreadMutex* mutex) {
return SCE_KERNEL_ERROR_EINVAL;
}
}
int PS4_SYSV_ABI scePthreadMutexUnlock(ScePthreadMutex* mutex) {
mutex = static_cast<ScePthreadMutex*>(createMutex(mutex));
mutex = createMutex(mutex);
if (mutex == nullptr) {
return SCE_KERNEL_ERROR_EINVAL;
}
int result = pthread_mutex_unlock(&(*mutex)->pth_mutex);
if (result != 0) {
LOG_TRACE(Kernel_Pthread, "name={}, result={}", (*mutex)->name, result);
LOG_TRACE(Kernel_Pthread, "Unlocking name={}, result={}", (*mutex)->name, result);
}
switch (result) {
case 0:
return SCE_OK;
case EINVAL:
return SCE_KERNEL_ERROR_EINVAL;
case EPERM:
@ -573,7 +578,6 @@ int PS4_SYSV_ABI scePthreadMutexUnlock(ScePthreadMutex* mutex) {
}
int PS4_SYSV_ABI scePthreadMutexattrDestroy(ScePthreadMutexattr* attr) {
int result = pthread_mutexattr_destroy(&(*attr)->pth_mutex_attr);
delete *attr;
@ -589,12 +593,16 @@ int PS4_SYSV_ABI scePthreadMutexattrDestroy(ScePthreadMutexattr* attr) {
}
}
void* createCond(void* addr) {
if (addr == nullptr || *static_cast<ScePthreadCond*>(addr) != nullptr) {
ScePthreadCond* createCond(ScePthreadCond* addr) {
if (addr == nullptr || *addr != nullptr) {
return addr;
}
auto vaddr = reinterpret_cast<u64>(addr);
static std::mutex mutex;
std::scoped_lock lk{mutex};
if (*addr != nullptr) {
return addr;
}
const VAddr vaddr = reinterpret_cast<VAddr>(addr);
std::string name = fmt::format("cond{:#x}", vaddr);
scePthreadCondInit(static_cast<ScePthreadCond*>(addr), nullptr, name.c_str());
return addr;
@ -654,8 +662,7 @@ int PS4_SYSV_ABI scePthreadCondattrInit(ScePthreadCondattr* attr) {
}
int PS4_SYSV_ABI scePthreadCondBroadcast(ScePthreadCond* cond) {
cond = static_cast<ScePthreadCond*>(createCond(cond));
cond = createCond(cond);
if (cond == nullptr) {
return SCE_KERNEL_ERROR_EINVAL;
}
@ -668,7 +675,7 @@ int PS4_SYSV_ABI scePthreadCondBroadcast(ScePthreadCond* cond) {
}
int PS4_SYSV_ABI scePthreadCondTimedwait(ScePthreadCond* cond, ScePthreadMutex* mutex, u64 usec) {
cond = static_cast<ScePthreadCond*>(createCond(cond));
cond = createCond(cond);
if (cond == nullptr) {
return SCE_KERNEL_ERROR_EINVAL;
}
@ -1032,9 +1039,9 @@ int PS4_SYSV_ABI scePthreadCondSignal(ScePthreadCond* cond) {
}
int PS4_SYSV_ABI scePthreadCondWait(ScePthreadCond* cond, ScePthreadMutex* mutex) {
if (cond == nullptr || *cond == nullptr) {
// return SCE_KERNEL_ERROR_EINVAL;
cond = static_cast<ScePthreadCond*>(createCond(cond)); // check this. Kero Blaster.
cond = createCond(cond);
if (cond == nullptr) {
return SCE_KERNEL_ERROR_EINVAL;
}
if (mutex == nullptr || *mutex == nullptr) {
return SCE_KERNEL_ERROR_EINVAL;
@ -1074,7 +1081,7 @@ int PS4_SYSV_ABI scePthreadCondattrDestroy(ScePthreadCondattr* attr) {
}
int PS4_SYSV_ABI scePthreadMutexTrylock(ScePthreadMutex* mutex) {
mutex = reinterpret_cast<ScePthreadMutex*>(createMutex(mutex));
mutex = createMutex(mutex);
if (mutex == nullptr) {
return ORBIS_KERNEL_ERROR_EINVAL;
}
@ -1250,7 +1257,7 @@ void pthreadSymbolsRegister(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("4qGrR6eoP9Y", "libkernel", 1, "libkernel", 1, 1, scePthreadDetach);
LIB_FUNCTION("3PtV6p3QNX4", "libkernel", 1, "libkernel", 1, 1, scePthreadEqual);
LIB_FUNCTION("7Xl257M4VNI", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_equal);
LIB_FUNCTION("7Xl257M4VNI", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_join);
LIB_FUNCTION("h9CcP3J0oVM", "libScePosix", 1, "libkernel", 1, 1, posix_pthread_join);
LIB_FUNCTION("aI+OeCz8xrQ", "libkernel", 1, "libkernel", 1, 1, scePthreadSelf);
LIB_FUNCTION("EotR8a3ASf4", "libkernel", 1, "libkernel", 1, 1, posix_pthread_self);
@ -1331,6 +1338,4 @@ void pthreadSymbolsRegister(Core::Loader::SymbolsResolver* sym) {
SemaphoreSymbolsRegister(sym);
}
} // namespace Libraries::Kernel

View file

@ -10,7 +10,6 @@
#include <pthread.h>
#include <sched.h>
#include "common/types.h"
#include <mutex>
namespace Core::Loader {
class SymbolsResolver;

View file

@ -1,10 +1,11 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <thread>
#include "common/logging/log.h"
#include "core/libraries/error_codes.h"
#include "core/libraries/kernel/threads/threads.h"
#include "core/libraries/libs.h"
#include "threads.h"
namespace Libraries::Kernel {
@ -25,6 +26,7 @@ bool PthreadKeys::CreateKey(int* key, PthreadKeyDestructor destructor) {
return false;
}
bool PthreadKeys::GetKey(int key, int thread_id, void** data) {
std::scoped_lock lk{m_mutex};
@ -88,7 +90,6 @@ void* PS4_SYSV_ABI scePthreadGetspecific(OrbisPthreadKey key) {
}
int PS4_SYSV_ABI scePthreadSetspecific(OrbisPthreadKey key, /* const*/ void* value) {
auto id = std::this_thread::get_id();
int thread_id = *(unsigned*)&id;
@ -99,4 +100,4 @@ int PS4_SYSV_ABI scePthreadSetspecific(OrbisPthreadKey key, /* const*/ void* val
return ORBIS_OK;
}
} // namespace Libraries::Kernel
} // namespace Libraries::Kernel

View file

@ -34,10 +34,23 @@ int PS4_SYSV_ABI posix_pthread_rwlock_init(OrbisPthreadRwlock* rwlock,
return ORBIS_OK;
}
int PS4_SYSV_ABI posix_pthread_rwlock_rdlock(OrbisPthreadRwlock* rwlock) {
if (*rwlock == nullptr) {
posix_pthread_rwlock_init(rwlock, nullptr, nullptr);
OrbisPthreadRwlock* createRwlock(OrbisPthreadRwlock* rwlock) {
if (rwlock == nullptr || *rwlock != nullptr) {
return rwlock;
}
static std::mutex mutex;
std::scoped_lock lk{mutex};
if (*rwlock != nullptr) {
return rwlock;
}
const VAddr addr = std::bit_cast<VAddr>(rwlock);
const auto name = fmt::format("rwlock{:#x}", addr);
posix_pthread_rwlock_init(rwlock, nullptr, name.c_str());
return rwlock;
}
int PS4_SYSV_ABI posix_pthread_rwlock_rdlock(OrbisPthreadRwlock* rwlock) {
rwlock = createRwlock(rwlock);
int result = pthread_rwlock_rdlock(&(*rwlock)->pth_rwlock);
if (result != 0) {
LOG_ERROR(Kernel_Pthread, "posix_pthread_rwlock_rdlock: error = {}", result);
@ -72,6 +85,10 @@ int PS4_SYSV_ABI posix_pthread_rwlock_timedwrlock() {
}
int PS4_SYSV_ABI posix_pthread_rwlock_tryrdlock(OrbisPthreadRwlock* rwlock) {
rwlock = createRwlock(rwlock);
if (rwlock == nullptr) {
return ORBIS_KERNEL_ERROR_EINVAL;
}
int result = pthread_rwlock_tryrdlock(&(*rwlock)->pth_rwlock);
if (result != 0) {
LOG_ERROR(Kernel_Pthread, "posix_pthread_rwlock_tryrdlock: error = {}", result);
@ -80,6 +97,10 @@ int PS4_SYSV_ABI posix_pthread_rwlock_tryrdlock(OrbisPthreadRwlock* rwlock) {
}
int PS4_SYSV_ABI posix_pthread_rwlock_trywrlock(OrbisPthreadRwlock* rwlock) {
rwlock = createRwlock(rwlock);
if (rwlock == nullptr) {
return ORBIS_KERNEL_ERROR_EINVAL;
}
int result = pthread_rwlock_trywrlock(&(*rwlock)->pth_rwlock);
if (result != 0) {
LOG_ERROR(Kernel_Pthread, "posix_pthread_rwlock_trywrlock: error = {}", result);
@ -88,6 +109,10 @@ int PS4_SYSV_ABI posix_pthread_rwlock_trywrlock(OrbisPthreadRwlock* rwlock) {
}
int PS4_SYSV_ABI posix_pthread_rwlock_unlock(OrbisPthreadRwlock* rwlock) {
rwlock = createRwlock(rwlock);
if (rwlock == nullptr) {
return ORBIS_KERNEL_ERROR_EINVAL;
}
int result = pthread_rwlock_unlock(&(*rwlock)->pth_rwlock);
if (result != 0) {
LOG_ERROR(Kernel_Pthread, "posix_pthread_rwlock_unlock: error = {}", result);
@ -96,6 +121,10 @@ int PS4_SYSV_ABI posix_pthread_rwlock_unlock(OrbisPthreadRwlock* rwlock) {
}
int PS4_SYSV_ABI posix_pthread_rwlock_wrlock(OrbisPthreadRwlock* rwlock) {
rwlock = createRwlock(rwlock);
if (rwlock == nullptr) {
return ORBIS_KERNEL_ERROR_EINVAL;
}
int result = pthread_rwlock_wrlock(&(*rwlock)->pth_rwlock);
if (result != 0) {
LOG_ERROR(Kernel_Pthread, "posix_pthread_rwlock_wrlock: error = {}", result);
@ -274,9 +303,7 @@ int PS4_SYSV_ABI scePthreadRwlockUnlock(OrbisPthreadRwlock* rwlock) {
}
int PS4_SYSV_ABI scePthreadRwlockWrlock(OrbisPthreadRwlock* rwlock) {
if (rwlock == nullptr || *rwlock == nullptr) {
return ORBIS_KERNEL_ERROR_EINVAL;
}
rwlock = createRwlock(rwlock);
int result = pthread_rwlock_wrlock(&(*rwlock)->pth_rwlock);
if (result != 0) {
LOG_ERROR(Kernel_Pthread, "scePthreadRwlockWrlock: error = {}", result);

View file

@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include <condition_variable>
#include <mutex>
#include <boost/intrusive/list.hpp>
#include <pthread.h>
#include "common/assert.h"
@ -17,8 +18,8 @@ using ListBaseHook =
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} {}
Semaphore(s32 init_count, s32 max_count, const char* name, bool is_fifo)
: name{name}, 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)) {
@ -131,6 +132,7 @@ private:
boost::intrusive::list<WaitingThread, boost::intrusive::base_hook<ListBaseHook>,
boost::intrusive::constant_time_size<false>>;
WaitingThreads wait_list;
std::string name;
std::atomic<s32> token_count;
std::mutex mutex;
s32 max_count;
@ -145,7 +147,7 @@ s32 PS4_SYSV_ABI sceKernelCreateSema(OrbisKernelSema* sem, const char* pName, u3
LOG_ERROR(Lib_Kernel, "Semaphore creation parameters are invalid!");
return ORBIS_KERNEL_ERROR_EINVAL;
}
*sem = new Semaphore(initCount, maxCount, attr == 1);
*sem = new Semaphore(initCount, maxCount, pName, attr == 1);
return ORBIS_OK;
}

View file

@ -63,9 +63,13 @@ int PS4_SYSV_ABI sceKernelUsleep(u32 microseconds) {
}
int PS4_SYSV_ABI posix_usleep(u32 microseconds) {
ASSERT(microseconds >= 1000);
#ifdef _WIN64
ASSERT(microseconds >= 1000 || microseconds == 0);
std::this_thread::sleep_for(std::chrono::microseconds(microseconds));
return 0;
#else
return usleep(microseconds);
#endif
}
u32 PS4_SYSV_ABI sceKernelSleep(u32 seconds) {
@ -152,6 +156,7 @@ int PS4_SYSV_ABI gettimeofday(OrbisKernelTimeval* tp, OrbisKernelTimezone* tz) {
}
s32 PS4_SYSV_ABI sceKernelGettimezone(OrbisKernelTimezone* tz) {
#ifdef _WIN64
ASSERT(tz);
static int tzflag = 0;
if (!tzflag) {
@ -160,6 +165,13 @@ s32 PS4_SYSV_ABI sceKernelGettimezone(OrbisKernelTimezone* tz) {
}
tz->tz_minuteswest = _timezone / 60;
tz->tz_dsttime = _daylight;
#else
struct timezone tzz;
struct timeval tv;
gettimeofday(&tv, &tzz);
tz->tz_dsttime = tzz.tz_dsttime;
tz->tz_minuteswest = tzz.tz_minuteswest;
#endif
return ORBIS_OK;
}
@ -176,6 +188,7 @@ void timeSymbolsRegister(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("n88vx3C5nW8", "libkernel", 1, "libkernel", 1, 1, gettimeofday);
LIB_FUNCTION("n88vx3C5nW8", "libScePosix", 1, "libkernel", 1, 1, gettimeofday);
LIB_FUNCTION("1jfXLRVzisc", "libkernel", 1, "libkernel", 1, 1, sceKernelUsleep);
LIB_FUNCTION("QcteRwbsnV0", "libkernel", 1, "libkernel", 1, 1, posix_usleep);
LIB_FUNCTION("QcteRwbsnV0", "libScePosix", 1, "libkernel", 1, 1, posix_usleep);
LIB_FUNCTION("-ZR+hG7aDHw", "libkernel", 1, "libkernel", 1, 1, sceKernelSleep);
LIB_FUNCTION("0wu33hunNdE", "libScePosix", 1, "libkernel", 1, 1, sceKernelSleep);

View file

@ -24,15 +24,13 @@ template <StringLiteral name, class R, class... Args, PS4_SYSV_ABI R (*f)(Args..
struct wrapper_impl<name, PS4_SYSV_ABI R (*)(Args...), f> {
static R PS4_SYSV_ABI wrap(Args... args) {
if (std::string_view(name.value) != "scePthreadEqual" &&
std::string_view(name.value) != "sceUserServiceGetEvent" &&
!std::string_view(name.value).contains("mutex") &&
!std::string_view(name.value).contains("Mutex")) {
// LOG_WARNING(Core_Linker, "Function {} called", name.value);
std::string_view(name.value) != "sceUserServiceGetEvent") {
LOG_WARNING(Core_Linker, "Function {} called", name.value);
}
if constexpr (std::is_same_v<R, s32> || std::is_same_v<R, u32>) {
const int ret = f(args...);
const u32 ret = f(args...);
if (ret != 0 && std::string_view(name.value) != "scePthreadEqual") {
LOG_WARNING(Core_Linker, "Function {} returned {}", name.value, ret);
LOG_WARNING(Core_Linker, "Function {} returned {:#x}", name.value, ret);
}
return ret;
}
@ -44,7 +42,7 @@ struct wrapper_impl<name, PS4_SYSV_ABI R (*)(Args...), f> {
template <StringLiteral name, class F, F f>
constexpr auto wrapper = wrapper_impl<name, F, f>::wrap;
//#define W(foo) wrapper<#foo, decltype(&foo), foo>
// #define W(foo) wrapper<#foo, decltype(&foo), foo>
#define W(foo) foo
#define LIB_FUNCTION(nid, lib, libversion, mod, moduleVersionMajor, moduleVersionMinor, function) \

View file

@ -733,4 +733,4 @@ void RegisterlibSceSaveData(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("AuTE0gFxZCI", "libSceSaveData", 1, "libSceSaveData", 1, 1, Func_02E4C4D201716422);
};
} // namespace Libraries::SaveData
} // namespace Libraries::SaveData

View file

@ -3,6 +3,7 @@
#pragma once
#include <algorithm>
#include <mutex>
#include <vector>
#include "core/module.h"

View file

@ -91,6 +91,7 @@ int MemoryManager::MapMemory(void** out_addr, VAddr virtual_addr, size_t size, M
// When virtual addr is zero, force it to virtual_base. The guest cannot pass Fixed
// flag so we will take the branch that searches for free (or reserved) mappings.
virtual_addr = (virtual_addr == 0) ? impl.VirtualBase() : virtual_addr;
alignment = alignment > 0 ? alignment : 16_KB;
VAddr mapped_addr = alignment > 0 ? Common::AlignUp(virtual_addr, alignment) : virtual_addr;
SCOPE_EXIT {
@ -141,7 +142,7 @@ int MemoryManager::MapMemory(void** out_addr, VAddr virtual_addr, size_t size, M
}
int MemoryManager::MapFile(void** out_addr, VAddr virtual_addr, size_t size, MemoryProt prot,
MemoryMapFlags flags, void* fd, size_t offset) {
MemoryMapFlags flags, uintptr_t fd, size_t offset) {
ASSERT(virtual_addr == 0);
virtual_addr = impl.VirtualBase();
const size_t size_aligned = Common::AlignUp(size, 16_KB);
@ -155,7 +156,7 @@ int MemoryManager::MapFile(void** out_addr, VAddr virtual_addr, size_t size, Mem
// Map the file.
const VAddr mapped_addr = it->second.base;
impl.MapFile(mapped_addr, Common::AlignDown(size, 4_KB), offset, fd);
impl.MapFile(mapped_addr, size, offset, fd);
// Add virtual memory area
auto& new_vma = AddMapping(mapped_addr, size_aligned);

View file

@ -86,7 +86,7 @@ struct VirtualMemoryArea {
MemoryProt prot = MemoryProt::NoAccess;
bool disallow_merge = false;
std::string name = "";
void* fd = nullptr;
uintptr_t fd = 0;
bool Contains(VAddr addr, size_t size) const {
return addr >= base && (addr + size) < (base + this->size);
@ -134,7 +134,7 @@ public:
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);
MemoryMapFlags flags, uintptr_t fd, size_t offset);
void UnmapMemory(VAddr virtual_addr, size_t size);

View file

@ -17,7 +17,7 @@ static constexpr size_t SCE_DBG_NUM_FINGERPRINT = 20;
struct OrbisKernelModuleSegmentInfo {
VAddr address;
u64 size;
u32 size;
s32 prot;
};

View file

@ -125,7 +125,8 @@ static void PatchFsAccess(u8* code, const TLSPattern& tls_pattern, Xbyak::CodeGe
const auto target_reg = Xbyak::Reg64(tls_pattern.target_reg);
c.putSeg(fs);
c.mov(target_reg, qword[SelfInTcbheadOffset]); // Load self member pointer of tcbhead_t.
c.add(target_reg, SpecificFirstBlockOffset + sizeof(uintptr_t) + slot * PthreadKeyDataSize);
c.add(target_reg, SpecificFirstBlockOffset + sizeof(uintptr_t) * 2 + slot * PthreadKeyDataSize);
c.mov(target_reg, qword[target_reg]);
c.jmp(code + total_size); // Return to the instruction right after the mov.
}

View file

@ -94,11 +94,11 @@ void Emulator::Run(const std::filesystem::path& file) {
if (std::filesystem::is_directory(sce_module_folder)) {
for (const auto& entry : std::filesystem::directory_iterator(sce_module_folder)) {
if (entry.path().filename() == "libc.prx" ||
entry.path().filename() == "libSceFios2.prx" /*||
entry.path().filename() == "libSceFios2.prx" ||
entry.path().filename() == "libSceAudioLatencyEstimation.prx" ||
entry.path().filename() == "libSceJobManager.prx" ||
entry.path().filename() == "libSceNpToolkit2.prx" ||
entry.path().filename() == "libSceS3DConversion.prx"*/) {
entry.path().filename() == "libSceS3DConversion.prx") {
found = true;
LOG_INFO(Loader, "Loading {}", entry.path().string().c_str());
linker->LoadModule(entry.path());
@ -115,15 +115,10 @@ void Emulator::Run(const std::filesystem::path& file) {
std::jthread([this](std::stop_token stop_token) { linker->Execute(); });
// Begin main window loop until the application exits
<<<<<<< HEAD
static constexpr std::chrono::milliseconds FlipPeriod{16};
=======
static constexpr std::chrono::microseconds FlipPeriod{10};
>>>>>>> 31bd502764f1ac975fc55bd2a788a7e08a9f34ec
while (window.isOpen()) {
window.waitEvent();
std::this_thread::sleep_for(FlipPeriod);
Libraries::VideoOut::Flip(FlipPeriod);
Libraries::VideoOut::Vblank();
FRAME_END;
@ -135,7 +130,8 @@ 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() == "libSceLibcInternal.sprx") {
LOG_INFO(Loader, "Loading {}", entry.path().string().c_str());
linker->LoadModule(entry.path());
}

View file

@ -1,6 +1,7 @@
// SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <sys/mman.h>
#include "common/assert.h"
#include "common/debug.h"
#include "common/thread.h"
@ -22,8 +23,6 @@ Liverpool::Liverpool() {
Liverpool::~Liverpool() {
process_thread.request_stop();
num_submits = -1;
num_submits.notify_one();
process_thread.join();
}
@ -31,8 +30,10 @@ void Liverpool::Process(std::stop_token stoken) {
Common::SetCurrentThreadName("GPU_CommandProcessor");
while (!stoken.stop_requested()) {
num_submits.wait(0);
{
std::unique_lock lk{submit_mutex};
submit_cv.wait(lk, stoken, [this] { return num_submits != 0; });
}
if (stoken.stop_requested()) {
break;
}
@ -67,7 +68,8 @@ void Liverpool::Process(std::stop_token stoken) {
}
if (submit_done) {
num_submits.notify_all();
std::scoped_lock lk{submit_mutex};
submit_cv.notify_all();
submit_done = false;
}
}
@ -76,9 +78,8 @@ void Liverpool::Process(std::stop_token stoken) {
void Liverpool::WaitGpuIdle() {
RENDERER_TRACE;
while (const auto old = num_submits.load()) {
num_submits.wait(old);
}
std::unique_lock lk{submit_mutex};
submit_cv.wait(lk, [this] { return num_submits == 0; });
}
Liverpool::Task Liverpool::ProcessCeUpdate(std::span<const u32> ccb) {
@ -369,7 +370,6 @@ Liverpool::Task Liverpool::ProcessGraphics(std::span<const u32> dcb, std::span<c
UNREACHABLE_MSG("Unknown PM4 type 3 opcode {:#x} with count {}",
static_cast<u32>(opcode), count);
}
dcb = dcb.subspan(header->type3.NumWords() + 1);
}
@ -415,8 +415,9 @@ void Liverpool::SubmitGfx(std::span<const u32> dcb, std::span<const u32> ccb) {
queue.submits.emplace(task.handle);
}
std::scoped_lock lk{submit_mutex};
++num_submits;
num_submits.notify_one();
submit_cv.notify_one();
}
void Liverpool::SubmitAsc(u32 vqid, std::span<const u32> acb) {
@ -429,8 +430,9 @@ void Liverpool::SubmitAsc(u32 vqid, std::span<const u32> acb) {
queue.submits.emplace(task.handle);
}
std::scoped_lock lk{submit_mutex};
++num_submits;
num_submits.notify_one();
submit_cv.notify_one();
}
} // namespace AmdGpu

View file

@ -10,6 +10,7 @@
#include "video_core/amdgpu/pixel_format.h"
#include <array>
#include <condition_variable>
#include <coroutine>
#include <mutex>
#include <span>
@ -865,13 +866,15 @@ public:
void SubmitAsc(u32 vqid, std::span<const u32> acb);
void WaitGpuIdle();
bool IsGpuIdle() const {
return num_submits == 0;
}
void NotifySubmitDone() {
std::scoped_lock lk{submit_mutex};
submit_done = true;
num_submits.notify_all();
submit_cv.notify_all();
}
void BindRasterizer(Vulkan::Rasterizer* rasterizer_) {
@ -939,7 +942,9 @@ private:
Vulkan::Rasterizer* rasterizer{};
std::jthread process_thread{};
std::atomic<u32> num_submits{};
u32 num_submits{};
std::mutex submit_mutex;
std::condition_variable_any submit_cv;
std::atomic<bool> submit_done{};
};