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/debug.h
src/common/disassembler.cpp src/common/disassembler.cpp
src/common/disassembler.h src/common/disassembler.h
src/common/discord.cpp
src/common/discord.h
src/common/endian.h src/common/endian.h
src/common/enum.h src/common/enum.h
src/common/io_file.cpp src/common/io_file.cpp
@ -509,7 +507,7 @@ endif()
create_target_directory_groups(shadps4) 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 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) if (NOT ENABLE_QT_GUI)
target_link_libraries(shadps4 PRIVATE SDL3-shared) target_link_libraries(shadps4 PRIVATE SDL3-shared)

View File

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

View File

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

View File

@ -255,13 +255,14 @@ struct AddressSpace::Impl {
m_free_regions.insert({start_addr, start_addr + virtual_size}); 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}); m_free_regions.subtract({virtual_addr, virtual_addr + size});
const int fd = phys_addr != -1 ? backing_fd : -1; const int handle = phys_addr != -1 ? (fd == -1 ? backing_fd : fd) : -1;
const int host_offset = phys_addr != -1 ? phys_addr : 0; const off_t host_offset = phys_addr != -1 ? phys_addr : 0;
const int flag = phys_addr != -1 ? MAP_SHARED : (MAP_ANONYMOUS | MAP_PRIVATE); 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, void* ret = mmap(reinterpret_cast<void*>(virtual_addr), size, prot, MAP_FIXED | flag,
host_offset); handle, host_offset);
ASSERT_MSG(ret != MAP_FAILED, "mmap failed: {}", strerror(errno)); ASSERT_MSG(ret != MAP_FAILED, "mmap failed: {}", strerror(errno));
return ret; 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); 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); 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 SYSTEM_RESERVED = 0x800000000ULL;
constexpr VAddr CODE_BASE_OFFSET = 0x100000000ULL; 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 SYSTEM_MANAGED_MAX = 0x07FFFFBFFFULL;
constexpr VAddr USER_MIN = 0x1000000000ULL; constexpr VAddr USER_MIN = 0x1000000000ULL;
constexpr VAddr USER_MAX = 0xFBFFFFFFFFULL; constexpr VAddr USER_MAX = 0xFBFFFFFFFFULL;
@ -63,7 +63,7 @@ public:
bool exec = false); bool exec = false);
/// Memory maps a specified file descriptor. /// 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. /// Unmaps specified virtual memory area.
void Unmap(VAddr virtual_addr, size_t size, bool has_backing); 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 // 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 // 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. // 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 = cmdbuf =
PM4CmdSetData::SetShReg(cmdbuf, 0x4au, vs_regs[2], vs_regs[3]); // SPI_SHADER_PGM_RSRC1_VS 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 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 direct = (flags & ORBIS_KERNEL_O_DIRECT) != 0;
bool directory = (flags & ORBIS_KERNEL_O_DIRECTORY) != 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) { if (directory) {
LOG_ERROR(Kernel_Fs, "called on directory"); LOG_ERROR(Kernel_Fs, "called on directory");
} else { } 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); fmt::ptr(addr), len, prot, flags, fd, offset);
auto* h = Common::Singleton<Core::FileSys::HandleTable>::Instance(); auto* h = Common::Singleton<Core::FileSys::HandleTable>::Instance();
auto* memory = Core::Memory::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_prot = static_cast<Core::MemoryProt>(prot);
const auto mem_flags = static_cast<Core::MemoryMapFlags>(flags); const auto mem_flags = static_cast<Core::MemoryMapFlags>(flags);
return memory->MapFile(res, std::bit_cast<VAddr>(addr), len, mem_prot, mem_flags, handle, if (fd == -1) {
offset); 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) { 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; 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() { int PS4_SYSV_ABI sceKernelDebugRaiseException() {
UNREACHABLE(); UNREACHABLE();
return 0; return 0;
@ -267,6 +275,10 @@ int PS4_SYSV_ABI sceKernelGetCpumode() {
return 5; return 5;
} }
void PS4_SYSV_ABI sched_yield() {
return std::this_thread::yield();
}
void LibKernel_Register(Core::Loader::SymbolsResolver* sym) { void LibKernel_Register(Core::Loader::SymbolsResolver* sym) {
// obj // obj
LIB_OBJ("f7uOxY9mM1U", "libkernel", 1, "libkernel", 1, 1, &g_stack_chk_guard); 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("wzvqT4UqKX8", "libkernel", 1, "libkernel", 1, 1, sceKernelLoadStartModule);
LIB_FUNCTION("LwG8g3niqwA", "libkernel", 1, "libkernel", 1, 1, sceKernelDlsym); LIB_FUNCTION("LwG8g3niqwA", "libkernel", 1, "libkernel", 1, 1, sceKernelDlsym);
LIB_FUNCTION("RpQJJVKTiFM", "libkernel", 1, "libkernel", 1, 1, sceKernelGetModuleInfoForUnwind); 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); LIB_FUNCTION("VOx8NGmHXTs", "libkernel", 1, "libkernel", 1, 1, sceKernelGetCpumode);
// equeue // equeue
@ -326,6 +339,7 @@ void LibKernel_Register(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("NWtTN10cJzE", "libSceLibcInternalExt", 1, "libSceLibcInternal", 1, 1, LIB_FUNCTION("NWtTN10cJzE", "libSceLibcInternalExt", 1, "libSceLibcInternal", 1, 1,
sceLibcHeapGetTraceInfo); sceLibcHeapGetTraceInfo);
LIB_FUNCTION("FxVZqBAA7ks", "libkernel", 1, "libkernel", 1, 1, ps4__write); LIB_FUNCTION("FxVZqBAA7ks", "libkernel", 1, "libkernel", 1, 1, ps4__write);
LIB_FUNCTION("6XG4B33N09g", "libScePosix", 1, "libkernel", 1, 1, sched_yield);
} }
} // namespace Libraries::Kernel } // 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, int PS4_SYSV_ABI sceKernelMapNamedDirectMemory(void** addr, u64 len, int prot, int flags,
s64 directMemoryStart, u64 alignment, s64 directMemoryStart, u64 alignment,
const char* name) { const char* name) {
LOG_INFO( LOG_INFO(Kernel_Vmm,
Kernel_Vmm, "addr = {}, len = {:#x}, prot = {:#x}, flags = {:#x}, directMemoryStart = {:#x}, "
"len = {:#x}, prot = {:#x}, flags = {:#x}, directMemoryStart = {:#x}, alignment = {:#x}", "alignment = {:#x}",
len, prot, flags, directMemoryStart, alignment); fmt::ptr(*addr), len, prot, flags, directMemoryStart, alignment);
if (len == 0 || !Common::Is16KBAligned(len)) { if (len == 0 || !Common::Is16KBAligned(len)) {
LOG_ERROR(Kernel_Vmm, "Map size is either zero or not 16KB aligned!"); 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, int PS4_SYSV_ABI sceKernelMapDirectMemory(void** addr, u64 len, int prot, int flags,
s64 directMemoryStart, u64 alignment) { s64 directMemoryStart, u64 alignment) {
LOG_INFO(Kernel_Vmm, LOG_INFO(Kernel_Vmm, "called, redirected to sceKernelMapNamedDirectMemory");
"redirected to sceKernelMapNamedDirectMemory: "
"len = {:#x}, prot = {:#x}, flags = {:#x}, directMemoryStart = {:#x}, alignment = "
"{:#x}",
len, prot, flags, directMemoryStart, alignment);
return sceKernelMapNamedDirectMemory(addr, len, prot, flags, directMemoryStart, alignment, ""); return sceKernelMapNamedDirectMemory(addr, len, prot, flags, directMemoryStart, alignment, "");
} }

View File

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

View File

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

View File

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

View File

@ -34,10 +34,23 @@ int PS4_SYSV_ABI posix_pthread_rwlock_init(OrbisPthreadRwlock* rwlock,
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI posix_pthread_rwlock_rdlock(OrbisPthreadRwlock* rwlock) { OrbisPthreadRwlock* createRwlock(OrbisPthreadRwlock* rwlock) {
if (*rwlock == nullptr) { if (rwlock == nullptr || *rwlock != nullptr) {
posix_pthread_rwlock_init(rwlock, nullptr, 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); int result = pthread_rwlock_rdlock(&(*rwlock)->pth_rwlock);
if (result != 0) { if (result != 0) {
LOG_ERROR(Kernel_Pthread, "posix_pthread_rwlock_rdlock: error = {}", result); 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) { 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); int result = pthread_rwlock_tryrdlock(&(*rwlock)->pth_rwlock);
if (result != 0) { if (result != 0) {
LOG_ERROR(Kernel_Pthread, "posix_pthread_rwlock_tryrdlock: error = {}", result); 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) { 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); int result = pthread_rwlock_trywrlock(&(*rwlock)->pth_rwlock);
if (result != 0) { if (result != 0) {
LOG_ERROR(Kernel_Pthread, "posix_pthread_rwlock_trywrlock: error = {}", result); 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) { 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); int result = pthread_rwlock_unlock(&(*rwlock)->pth_rwlock);
if (result != 0) { if (result != 0) {
LOG_ERROR(Kernel_Pthread, "posix_pthread_rwlock_unlock: error = {}", result); 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) { 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); int result = pthread_rwlock_wrlock(&(*rwlock)->pth_rwlock);
if (result != 0) { if (result != 0) {
LOG_ERROR(Kernel_Pthread, "posix_pthread_rwlock_wrlock: error = {}", result); 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) { int PS4_SYSV_ABI scePthreadRwlockWrlock(OrbisPthreadRwlock* rwlock) {
if (rwlock == nullptr || *rwlock == nullptr) { rwlock = createRwlock(rwlock);
return ORBIS_KERNEL_ERROR_EINVAL;
}
int result = pthread_rwlock_wrlock(&(*rwlock)->pth_rwlock); int result = pthread_rwlock_wrlock(&(*rwlock)->pth_rwlock);
if (result != 0) { if (result != 0) {
LOG_ERROR(Kernel_Pthread, "scePthreadRwlockWrlock: error = {}", result); LOG_ERROR(Kernel_Pthread, "scePthreadRwlockWrlock: error = {}", result);

View File

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

View File

@ -63,9 +63,13 @@ int PS4_SYSV_ABI sceKernelUsleep(u32 microseconds) {
} }
int PS4_SYSV_ABI posix_usleep(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)); std::this_thread::sleep_for(std::chrono::microseconds(microseconds));
return 0; return 0;
#else
return usleep(microseconds);
#endif
} }
u32 PS4_SYSV_ABI sceKernelSleep(u32 seconds) { 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) { s32 PS4_SYSV_ABI sceKernelGettimezone(OrbisKernelTimezone* tz) {
#ifdef _WIN64
ASSERT(tz); ASSERT(tz);
static int tzflag = 0; static int tzflag = 0;
if (!tzflag) { if (!tzflag) {
@ -160,6 +165,13 @@ s32 PS4_SYSV_ABI sceKernelGettimezone(OrbisKernelTimezone* tz) {
} }
tz->tz_minuteswest = _timezone / 60; tz->tz_minuteswest = _timezone / 60;
tz->tz_dsttime = _daylight; 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; 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", "libkernel", 1, "libkernel", 1, 1, gettimeofday);
LIB_FUNCTION("n88vx3C5nW8", "libScePosix", 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("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("QcteRwbsnV0", "libScePosix", 1, "libkernel", 1, 1, posix_usleep);
LIB_FUNCTION("-ZR+hG7aDHw", "libkernel", 1, "libkernel", 1, 1, sceKernelSleep); LIB_FUNCTION("-ZR+hG7aDHw", "libkernel", 1, "libkernel", 1, 1, sceKernelSleep);
LIB_FUNCTION("0wu33hunNdE", "libScePosix", 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> { struct wrapper_impl<name, PS4_SYSV_ABI R (*)(Args...), f> {
static R PS4_SYSV_ABI wrap(Args... args) { static R PS4_SYSV_ABI wrap(Args... args) {
if (std::string_view(name.value) != "scePthreadEqual" && if (std::string_view(name.value) != "scePthreadEqual" &&
std::string_view(name.value) != "sceUserServiceGetEvent" && std::string_view(name.value) != "sceUserServiceGetEvent") {
!std::string_view(name.value).contains("mutex") && LOG_WARNING(Core_Linker, "Function {} called", name.value);
!std::string_view(name.value).contains("Mutex")) {
// LOG_WARNING(Core_Linker, "Function {} called", name.value);
} }
if constexpr (std::is_same_v<R, s32> || std::is_same_v<R, u32>) { 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") { 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; return ret;
} }
@ -44,7 +42,7 @@ struct wrapper_impl<name, PS4_SYSV_ABI R (*)(Args...), f> {
template <StringLiteral name, class F, F f> template <StringLiteral name, class F, F f>
constexpr auto wrapper = wrapper_impl<name, F, f>::wrap; 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 W(foo) foo
#define LIB_FUNCTION(nid, lib, libversion, mod, moduleVersionMajor, moduleVersionMinor, function) \ #define LIB_FUNCTION(nid, lib, libversion, mod, moduleVersionMajor, moduleVersionMinor, function) \

View File

@ -3,6 +3,7 @@
#pragma once #pragma once
#include <algorithm>
#include <mutex> #include <mutex>
#include <vector> #include <vector>
#include "core/module.h" #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 // 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. // flag so we will take the branch that searches for free (or reserved) mappings.
virtual_addr = (virtual_addr == 0) ? impl.VirtualBase() : virtual_addr; 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; VAddr mapped_addr = alignment > 0 ? Common::AlignUp(virtual_addr, alignment) : virtual_addr;
SCOPE_EXIT { 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, 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); ASSERT(virtual_addr == 0);
virtual_addr = impl.VirtualBase(); virtual_addr = impl.VirtualBase();
const size_t size_aligned = Common::AlignUp(size, 16_KB); 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. // Map the file.
const VAddr mapped_addr = it->second.base; 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 // Add virtual memory area
auto& new_vma = AddMapping(mapped_addr, size_aligned); auto& new_vma = AddMapping(mapped_addr, size_aligned);

View File

@ -86,7 +86,7 @@ struct VirtualMemoryArea {
MemoryProt prot = MemoryProt::NoAccess; MemoryProt prot = MemoryProt::NoAccess;
bool disallow_merge = false; bool disallow_merge = false;
std::string name = ""; std::string name = "";
void* fd = nullptr; uintptr_t fd = 0;
bool Contains(VAddr addr, size_t size) const { bool Contains(VAddr addr, size_t size) const {
return addr >= base && (addr + size) < (base + this->size); return addr >= base && (addr + size) < (base + this->size);
@ -134,7 +134,7 @@ public:
bool is_exec = false, PAddr phys_addr = -1, u64 alignment = 0); bool is_exec = false, PAddr phys_addr = -1, u64 alignment = 0);
int MapFile(void** out_addr, VAddr virtual_addr, size_t size, MemoryProt prot, 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); 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 { struct OrbisKernelModuleSegmentInfo {
VAddr address; VAddr address;
u64 size; u32 size;
s32 prot; 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); const auto target_reg = Xbyak::Reg64(tls_pattern.target_reg);
c.putSeg(fs); c.putSeg(fs);
c.mov(target_reg, qword[SelfInTcbheadOffset]); // Load self member pointer of tcbhead_t. 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. 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)) { if (std::filesystem::is_directory(sce_module_folder)) {
for (const auto& entry : std::filesystem::directory_iterator(sce_module_folder)) { for (const auto& entry : std::filesystem::directory_iterator(sce_module_folder)) {
if (entry.path().filename() == "libc.prx" || if (entry.path().filename() == "libc.prx" ||
entry.path().filename() == "libSceFios2.prx" /*|| entry.path().filename() == "libSceFios2.prx" ||
entry.path().filename() == "libSceAudioLatencyEstimation.prx" || entry.path().filename() == "libSceAudioLatencyEstimation.prx" ||
entry.path().filename() == "libSceJobManager.prx" || entry.path().filename() == "libSceJobManager.prx" ||
entry.path().filename() == "libSceNpToolkit2.prx" || entry.path().filename() == "libSceNpToolkit2.prx" ||
entry.path().filename() == "libSceS3DConversion.prx"*/) { entry.path().filename() == "libSceS3DConversion.prx") {
found = true; found = true;
LOG_INFO(Loader, "Loading {}", entry.path().string().c_str()); LOG_INFO(Loader, "Loading {}", entry.path().string().c_str());
linker->LoadModule(entry.path()); 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(); }); std::jthread([this](std::stop_token stop_token) { linker->Execute(); });
// Begin main window loop until the application exits // Begin main window loop until the application exits
<<<<<<< HEAD
static constexpr std::chrono::milliseconds FlipPeriod{16};
=======
static constexpr std::chrono::microseconds FlipPeriod{10}; static constexpr std::chrono::microseconds FlipPeriod{10};
>>>>>>> 31bd502764f1ac975fc55bd2a788a7e08a9f34ec
while (window.isOpen()) { while (window.isOpen()) {
window.waitEvent(); window.waitEvent();
std::this_thread::sleep_for(FlipPeriod);
Libraries::VideoOut::Flip(FlipPeriod); Libraries::VideoOut::Flip(FlipPeriod);
Libraries::VideoOut::Vblank(); Libraries::VideoOut::Vblank();
FRAME_END; FRAME_END;
@ -135,7 +130,8 @@ void Emulator::Run(const std::filesystem::path& file) {
void Emulator::LoadSystemModules(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); const auto& sys_module_path = Common::FS::GetUserPath(Common::FS::PathType::SysModuleDir);
for (const auto& entry : std::filesystem::directory_iterator(sys_module_path)) { 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()); LOG_INFO(Loader, "Loading {}", entry.path().string().c_str());
linker->LoadModule(entry.path()); linker->LoadModule(entry.path());
} }

View File

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

View File

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