diff --git a/src/common/path_util.cpp b/src/common/path_util.cpp index 7210f2122..293ee1b74 100644 --- a/src/common/path_util.cpp +++ b/src/common/path_util.cpp @@ -1,10 +1,7 @@ // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include -#include #include - #include "common/logging/log.h" #include "common/path_util.h" diff --git a/src/core/file_format/pkg.cpp b/src/core/file_format/pkg.cpp index 5150e1286..6d5fb0d4a 100644 --- a/src/core/file_format/pkg.cpp +++ b/src/core/file_format/pkg.cpp @@ -1,11 +1,10 @@ // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include #include #include "common/io_file.h" -#include "pkg.h" -#include "pkg_type.h" +#include "core/file_format/pkg.h" +#include "core/file_format/pkg_type.h" static void DecompressPFSC(std::span compressed_data, std::span decompressed_data) { diff --git a/src/core/file_format/pkg.h b/src/core/file_format/pkg.h index f77a78046..3fef6c1c4 100644 --- a/src/core/file_format/pkg.h +++ b/src/core/file_format/pkg.h @@ -4,7 +4,6 @@ #pragma once #include -#include #include #include #include diff --git a/src/core/file_format/psf.cpp b/src/core/file_format/psf.cpp index 4a7f62159..dd9da71ad 100644 --- a/src/core/file_format/psf.cpp +++ b/src/core/file_format/psf.cpp @@ -2,11 +2,8 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include -#include -#include - #include "common/io_file.h" -#include "psf.h" +#include "core/file_format/psf.h" PSF::PSF() = default; diff --git a/src/core/tls.cpp b/src/core/tls.cpp index 151477882..270f656bc 100644 --- a/src/core/tls.cpp +++ b/src/core/tls.cpp @@ -8,6 +8,8 @@ #ifdef _WIN32 #include +#else +#include #endif namespace Core { @@ -53,9 +55,83 @@ Tcb* GetTcbBase() { return reinterpret_cast(TlsGetValue(slot)); } -void PatchTLS(u64 segment_addr, u64 segment_size, Xbyak::CodeGenerator& c) { - using namespace Xbyak::util; +static void AllocTcbKey() { + slot = TlsAlloc(); +} +static void PatchFsAccess(u8* code, const TLSPattern& tls_pattern, Xbyak::CodeGenerator& c) { + using namespace Xbyak::util; + const auto total_size = tls_pattern.pattern_size + tls_pattern.imm_size; + + // Replace mov instruction with near jump to the trampoline. + static constexpr u32 NearJmpSize = 5; + auto patch = Xbyak::CodeGenerator(total_size, code); + patch.jmp(c.getCurr(), Xbyak::CodeGenerator::LabelType::T_NEAR); + patch.nop(total_size - NearJmpSize); + + // Write the trampoline. + // The following logic is based on the wine implementation of TlsGetValue + // https://github.com/wine-mirror/wine/blob/a27b9551/dlls/kernelbase/thread.c#L719 + static constexpr u32 TlsSlotsOffset = 0x1480; + static constexpr u32 TlsExpansionSlotsOffset = 0x1780; + static constexpr u32 TlsMinimumAvailable = 64; + const u32 teb_offset = slot < TlsMinimumAvailable ? TlsSlotsOffset : TlsExpansionSlotsOffset; + const u32 tls_index = slot < TlsMinimumAvailable ? slot : slot - TlsMinimumAvailable; + + const auto target_reg = Xbyak::Reg64(tls_pattern.target_reg); + c.mov(target_reg, teb_offset); + c.putSeg(gs); + c.mov(target_reg, ptr[target_reg]); // Load the pointer to the table of tls slots. + c.mov(target_reg, + qword[target_reg + tls_index * sizeof(LPVOID)]); // Load the pointer to our buffer. + c.jmp(code + total_size); // Return to the instruction right after the mov. +} + +#else + +static pthread_key_t slot = 0; + +void SetTcbBase(void* image_address) { + ASSERT(pthread_setspecific(slot, image_address) == 0); +} + +Tcb* GetTcbBase() { + return reinterpret_cast(pthread_getspecific(slot)); +} + +static void AllocTcbKey() { + slot = pthread_key_create(&slot, nullptr); +} + +static void PatchFsAccess(u8* code, const TLSPattern& tls_pattern, Xbyak::CodeGenerator& c) { + using namespace Xbyak::util; + const auto total_size = tls_pattern.pattern_size + tls_pattern.imm_size; + + // Replace mov instruction with near jump to the trampoline. + static constexpr u32 NearJmpSize = 5; + auto patch = Xbyak::CodeGenerator(total_size, code); + patch.jmp(c.getCurr(), Xbyak::CodeGenerator::LabelType::T_NEAR); + patch.nop(total_size - NearJmpSize); + + // Write the trampoline. + // The following logic is based on the glibc implementation of pthread_getspecific + // https://github.com/bminor/glibc/blob/29807a27/nptl/pthread_getspecific.c#L23 + static constexpr u32 PthreadKeySecondLevelSize = 32; + static constexpr u32 SpecificFirstBlockOffset = 0x308; + static constexpr u32 SelfInTcbheadOffset = 16; + static constexpr u32 PthreadKeyDataSize = 16; + ASSERT(slot < PthreadKeySecondLevelSize); + + 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.lea(target_reg, + ptr[SpecificFirstBlockOffset + slot * PthreadKeyDataSize + + sizeof(uintptr_t)]); // Load the pointer to our data. + c.jmp(code + total_size); // Return to the instruction right after the mov. +} + +void PatchTLS(u64 segment_addr, u64 segment_size, Xbyak::CodeGenerator& c) { u8* code = reinterpret_cast(segment_addr); auto remaining_size = segment_size; @@ -89,7 +165,7 @@ void PatchTLS(u64 segment_addr, u64 segment_size, Xbyak::CodeGenerator& c) { // Allocate slot in the process if not done already. if (slot == 0) { - slot = TlsAlloc(); + AllocTcbKey(); } // Replace bogus instruction prefix with nops if it exists. @@ -98,30 +174,8 @@ void PatchTLS(u64 segment_addr, u64 segment_size, Xbyak::CodeGenerator& c) { patch.nop(BadPrefix.size()); } - // Replace mov instruction with near jump to the trampoline. - static constexpr u32 NearJmpSize = 5; - auto patch = Xbyak::CodeGenerator(total_size, code); - patch.jmp(c.getCurr(), Xbyak::CodeGenerator::LabelType::T_NEAR); - patch.nop(total_size - NearJmpSize); - - // Write the trampoline. - // The following logic is based on the wine implementation of TlsGetValue - // https://github.com/wine-mirror/wine/blob/a27b9551/dlls/kernelbase/thread.c#L719 - static constexpr u32 TlsSlotsOffset = 0x1480; - static constexpr u32 TlsExpansionSlotsOffset = 0x1780; - static constexpr u32 TlsMinimumAvailable = 64; - const u32 teb_offset = - slot < TlsMinimumAvailable ? TlsSlotsOffset : TlsExpansionSlotsOffset; - const u32 tls_index = slot < TlsMinimumAvailable ? slot : slot - TlsMinimumAvailable; - - const auto target_reg = Xbyak::Reg64(tls_pattern.target_reg); - c.mov(target_reg, teb_offset); - c.putSeg(gs); - c.mov(target_reg, ptr[target_reg]); // Load the pointer to the table of tls slots. - c.mov( - target_reg, - qword[target_reg + tls_index * sizeof(LPVOID)]); // Load the pointer to our buffer. - c.jmp(code + total_size); // Return to the instruction right after the mov. + // Patch access to FS register to a trampoline. + PatchFsAccess(code, tls_pattern, c); // Move ahead in module. code += total_size - 1; @@ -133,20 +187,6 @@ void PatchTLS(u64 segment_addr, u64 segment_size, Xbyak::CodeGenerator& c) { } } -#else - -void SetTcbBase(void* image_address) { - UNREACHABLE_MSG("Thread local storage is unimplemented on posix platforms!"); -} - -Tcb* GetTcbBase() { - UNREACHABLE_MSG("Thread local storage is unimplemented on posix platforms!"); -} - -void PatchTLS(u64 segment_addr, u64 segment_size, Xbyak::CodeGenerator& c) { - UNREACHABLE_MSG("Thread local storage is unimplemented on posix platforms!"); -} - #endif } // namespace Core diff --git a/src/emulator.cpp b/src/emulator.cpp index c5facd191..a652e42be 100644 --- a/src/emulator.cpp +++ b/src/emulator.cpp @@ -40,10 +40,6 @@ Emulator::Emulator() : window{WindowWidth, WindowHeight, controller} { Common::Log::Initialize(); Common::Log::Start(); - // Start discord integration - discord_rpc.init(); - discord_rpc.update(Discord::RPCStatus::Idling, ""); - // Initialize kernel and library facilities. Libraries::Kernel::init_pthreads(); Libraries::InitHLELibs(&linker->GetHLESymbols()); @@ -52,7 +48,6 @@ Emulator::Emulator() : window{WindowWidth, WindowHeight, controller} { Emulator::~Emulator() { const auto config_dir = Common::FS::GetUserPath(Common::FS::PathType::UserDir); Config::save(config_dir / "config.toml"); - discord_rpc.stop(); } void Emulator::Run(const std::filesystem::path& file) { @@ -138,4 +133,4 @@ void Emulator::LoadSystemModules(const std::filesystem::path& file) { } } -} // namespace Core \ No newline at end of file +} // namespace Core diff --git a/src/emulator.h b/src/emulator.h index 7364af8c7..36faaad39 100644 --- a/src/emulator.h +++ b/src/emulator.h @@ -7,7 +7,6 @@ #include #include -#include "common/discord.h" #include "core/linker.h" #include "input/controller.h" #include "sdl_window.h" @@ -23,10 +22,9 @@ public: private: void LoadSystemModules(const std::filesystem::path& file); - Discord::RPC discord_rpc; Input::GameController* controller = Common::Singleton::Instance(); Core::Linker* linker = Common::Singleton::Instance(); Frontend::WindowSDL window; }; -} // namespace Core \ No newline at end of file +} // namespace Core diff --git a/src/video_core/amdgpu/liverpool.h b/src/video_core/amdgpu/liverpool.h index 22b59f740..0a427c91a 100644 --- a/src/video_core/amdgpu/liverpool.h +++ b/src/video_core/amdgpu/liverpool.h @@ -695,7 +695,7 @@ struct Liverpool { NumberFormat NumFormat() const { // There is a small difference between T# and CB number types, account for it. return info.number_type == AmdGpu::NumberFormat::SnormNz ? AmdGpu::NumberFormat::Srgb - : info.number_type; + : info.number_type.Value(); } }; diff --git a/src/video_core/amdgpu/resource.h b/src/video_core/amdgpu/resource.h index ba2231b0c..64721b629 100644 --- a/src/video_core/amdgpu/resource.h +++ b/src/video_core/amdgpu/resource.h @@ -32,7 +32,7 @@ struct Buffer { }; u32 GetStride() const noexcept { - return stride == 0 ? 1U : stride; + return stride == 0 ? 1U : stride.Value(); } u32 GetStrideElements(u32 element_size) const noexcept {