From 4922d526feb41bae0353994e907e343972acd4ef Mon Sep 17 00:00:00 2001 From: oltolm Date: Sat, 22 Nov 2025 09:32:29 +0100 Subject: [PATCH 1/5] msys2: fix build (#3818) * cmake: fix mingw-w64 build * time.cpp: fix build with Clang on Windows * tls.h: include malloc.h for alloca --- CMakeLists.txt | 18 +++++++++++------- externals/CMakeLists.txt | 2 +- src/core/libraries/kernel/time.cpp | 23 ++++++++++++++++++++--- src/core/tls.h | 3 +++ 4 files changed, 35 insertions(+), 11 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index ddaf2422c..7c1ebca79 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -228,8 +228,10 @@ find_package(half 1.12.0 MODULE) find_package(magic_enum 0.9.7 CONFIG) find_package(PNG 1.6 MODULE) find_package(RenderDoc 1.6.0 MODULE) -find_package(SDL3 3.1.2 CONFIG) find_package(SDL3_mixer 2.8.1 CONFIG) +if (SDL3_mixer_FOUND) + find_package(SDL3 3.1.2 CONFIG) +endif() find_package(stb MODULE) find_package(toml11 4.2.0 CONFIG) find_package(tsl-robin-map 1.3.0 CONFIG) @@ -554,6 +556,8 @@ set(FIBER_LIB src/core/libraries/fiber/fiber_context.s src/core/libraries/fiber/fiber_error.h ) +set_source_files_properties(src/core/libraries/fiber/fiber_context.s PROPERTIES COMPILE_OPTIONS -Wno-unused-command-line-argument) + set(VDEC_LIB src/core/libraries/videodec/videodec2_impl.cpp src/core/libraries/videodec/videodec2_impl.h src/core/libraries/videodec/videodec2.cpp @@ -1122,22 +1126,22 @@ if (APPLE) endif() if (WIN32) - target_link_libraries(shadps4 PRIVATE mincore wepoll) + target_link_libraries(shadps4 PRIVATE mincore wepoll wbemuuid) if (MSVC) # MSVC likes putting opinions on what people can use, disable: - add_definitions(-D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE -D_SCL_SECURE_NO_WARNINGS) + add_compile_definitions(_CRT_SECURE_NO_WARNINGS _CRT_NONSTDC_NO_DEPRECATE _SCL_SECURE_NO_WARNINGS) endif() - add_definitions(-DNOMINMAX -DWIN32_LEAN_AND_MEAN) + add_compile_definitions(NOMINMAX WIN32_LEAN_AND_MEAN) if (MSVC) # Needed for conflicts with time.h of windows.h - add_definitions(-D_TIMESPEC_DEFINED) + add_compile_definitions(_TIMESPEC_DEFINED) endif() # Target Windows 10 RS5 - add_definitions(-DNTDDI_VERSION=0x0A000006 -D_WIN32_WINNT=0x0A00 -DWINVER=0x0A00) + add_compile_definitions(NTDDI_VERSION=0x0A000006 _WIN32_WINNT=0x0A00 WINVER=0x0A00) if (MSVC) target_link_libraries(shadps4 PRIVATE clang_rt.builtins-x86_64.lib) @@ -1169,7 +1173,7 @@ if (WIN32) target_sources(shadps4 PRIVATE src/shadps4.rc) endif() -add_definitions(-DBOOST_ASIO_STANDALONE) +add_compile_definitions(BOOST_ASIO_STANDALONE) target_include_directories(shadps4 PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt index 5f7ae94c4..b6c7c746e 100644 --- a/externals/CMakeLists.txt +++ b/externals/CMakeLists.txt @@ -152,7 +152,7 @@ endif() # sirit add_subdirectory(sirit) if (WIN32) - target_compile_options(sirit PUBLIC "-Wno-error=unused-command-line-argument") + target_compile_options(sirit PRIVATE "-Wno-error=unused-command-line-argument") endif() # half diff --git a/src/core/libraries/kernel/time.cpp b/src/core/libraries/kernel/time.cpp index ad07678b2..51f86e2c7 100644 --- a/src/core/libraries/kernel/time.cpp +++ b/src/core/libraries/kernel/time.cpp @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: Copyright 2024 shadPS4 Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include #include #include "common/assert.h" @@ -485,25 +486,41 @@ Common::NativeClock* GetClock() { s32 PS4_SYSV_ABI sceKernelConvertUtcToLocaltime(time_t time, time_t* local_time, struct OrbisTimesec* st, u64* dst_sec) { LOG_TRACE(Kernel, "Called"); +#ifdef _WIN32 + TIME_ZONE_INFORMATION tz{}; + DWORD res = GetTimeZoneInformation(&tz); + *local_time = time - tz.Bias; + + if (st != nullptr) { + st->t = time; + st->west_sec = -tz.Bias * 60; + st->dst_sec = res == TIME_ZONE_ID_DAYLIGHT ? -_dstbias : 0; + } + + if (dst_sec != nullptr) { + *dst_sec = res == TIME_ZONE_ID_DAYLIGHT ? -_dstbias : 0; + } +#else #ifdef __APPLE__ // std::chrono::current_zone() not available yet. const auto* time_zone = date::current_zone(); #else const auto* time_zone = std::chrono::current_zone(); -#endif +#endif // __APPLE__ auto info = time_zone->get_info(std::chrono::system_clock::now()); *local_time = info.offset.count() + info.save.count() * 60 + time; if (st != nullptr) { st->t = time; - st->west_sec = info.offset.count() * 60; + st->west_sec = info.offset.count(); st->dst_sec = info.save.count() * 60; } if (dst_sec != nullptr) { *dst_sec = info.save.count() * 60; } +#endif // _WIN32 return ORBIS_OK; } @@ -565,4 +582,4 @@ void RegisterTime(Core::Loader::SymbolsResolver* sym) { LIB_FUNCTION("-o5uEDpN+oY", "libkernel", 1, "libkernel", sceKernelConvertUtcToLocaltime); } -} // namespace Libraries::Kernel \ No newline at end of file +} // namespace Libraries::Kernel diff --git a/src/core/tls.h b/src/core/tls.h index 6be9752b0..0ae512a04 100644 --- a/src/core/tls.h +++ b/src/core/tls.h @@ -5,6 +5,9 @@ #include #include "common/types.h" +#ifdef _WIN32 +#include +#endif namespace Xbyak { class CodeGenerator; From f6ae5544fdcf781d9578d4a7b6c5089705929c8f Mon Sep 17 00:00:00 2001 From: Stephen Miller <56742918+StevenMiller123@users.noreply.github.com> Date: Sat, 22 Nov 2025 02:32:53 -0600 Subject: [PATCH 2/5] Kernel.Vmm: Protect Fixes (#3822) * Some mprotect fixes The biggest thing here is preventing mprotect on memory that isn't mapped in address space. This would cause exceptions before, but succeeds on real hardware. I've also included a couple other minor fixes, mostly based around some tests I recently performed. Note: All changes to memory pools in this PR are assumed. I have not yet tested memory pools with any of this logic, but I do at least want to prevent mprotect on pool reserved memory to avoid crashes. * Update memory.cpp * clang --- src/core/memory.cpp | 48 ++++++++++++++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 16 deletions(-) diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 7db25391a..b9fd7fd7d 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -587,6 +587,10 @@ s32 MemoryManager::MapFile(void** out_addr, VAddr virtual_addr, u64 size, Memory // On real hardware, GPU file mmaps cause a full system crash due to an internal error. ASSERT_MSG(false, "Files cannot be mapped to GPU memory"); } + if (True(prot & MemoryProt::CpuExec)) { + // On real hardware, execute permissions are silently removed. + prot &= ~MemoryProt::CpuExec; + } // Add virtual memory area auto& new_vma = CarveVMA(mapped_addr, size)->second; @@ -793,10 +797,9 @@ s32 MemoryManager::QueryProtection(VAddr addr, void** start, void** end, u32* pr s64 MemoryManager::ProtectBytes(VAddr addr, VirtualMemoryArea& vma_base, u64 size, MemoryProt prot) { const auto start_in_vma = addr - vma_base.base; - const auto adjusted_size = - vma_base.size - start_in_vma < size ? vma_base.size - start_in_vma : size; + const auto adjusted_size = std::min(vma_base.size - start_in_vma, size); - if (vma_base.type == VMAType::Free) { + if (vma_base.type == VMAType::Free || vma_base.type == VMAType::PoolReserved) { // On PS4, protecting freed memory does nothing. return adjusted_size; } @@ -828,8 +831,9 @@ s64 MemoryManager::ProtectBytes(VAddr addr, VirtualMemoryArea& vma_base, u64 siz perms |= Core::MemoryPermission::ReadWrite; } - if (vma_base.type == VMAType::Direct || vma_base.type == VMAType::Pooled) { - // On PS4, execute permissions are hidden from direct memory mappings. + if (vma_base.type == VMAType::Direct || vma_base.type == VMAType::Pooled || + vma_base.type == VMAType::File) { + // On PS4, execute permissions are hidden from direct memory and file mappings. // Tests show that execute permissions still apply, so handle this after reading perms. prot &= ~MemoryProt::CpuExec; } @@ -837,6 +841,12 @@ s64 MemoryManager::ProtectBytes(VAddr addr, VirtualMemoryArea& vma_base, u64 siz // Change protection vma_base.prot = prot; + if (vma_base.type == VMAType::Reserved) { + // On PS4, protections change vma_map, but don't apply. + // Return early to avoid protecting memory that isn't mapped in address space. + return adjusted_size; + } + impl.Protect(addr, size, perms); return adjusted_size; @@ -853,22 +863,20 @@ s32 MemoryManager::Protect(VAddr addr, u64 size, MemoryProt prot) { // Ensure the range to modify is valid ASSERT_MSG(IsValidMapping(addr, size), "Attempted to access invalid address {:#x}", addr); - // Validate protection flags - constexpr static MemoryProt valid_flags = - MemoryProt::NoAccess | MemoryProt::CpuRead | MemoryProt::CpuWrite | MemoryProt::CpuExec | - MemoryProt::GpuRead | MemoryProt::GpuWrite | MemoryProt::GpuReadWrite; - - MemoryProt invalid_flags = prot & ~valid_flags; - if (invalid_flags != MemoryProt::NoAccess) { - LOG_ERROR(Kernel_Vmm, "Invalid protection flags"); - return ORBIS_KERNEL_ERROR_EINVAL; - } + // Appropriately restrict flags. + constexpr static MemoryProt flag_mask = + MemoryProt::CpuReadWrite | MemoryProt::CpuExec | MemoryProt::GpuReadWrite; + MemoryProt valid_flags = prot & flag_mask; // Protect all VMAs between addr and addr + size. s64 protected_bytes = 0; while (protected_bytes < size) { auto it = FindVMA(addr + protected_bytes); auto& vma_base = it->second; + if (vma_base.base > addr + protected_bytes) { + // Account for potential gaps in memory map. + protected_bytes += vma_base.base - (addr + protected_bytes); + } auto result = ProtectBytes(addr + protected_bytes, vma_base, size - protected_bytes, prot); if (result < 0) { // ProtectBytes returned an error, return it @@ -904,13 +912,21 @@ s32 MemoryManager::VirtualQuery(VAddr addr, s32 flags, const auto& vma = it->second; info->start = vma.base; info->end = vma.base + vma.size; - info->offset = vma.type == VMAType::Flexible ? 0 : vma.phys_base; + info->offset = 0; info->protection = static_cast(vma.prot); info->is_flexible = vma.type == VMAType::Flexible ? 1 : 0; info->is_direct = vma.type == VMAType::Direct ? 1 : 0; info->is_stack = vma.type == VMAType::Stack ? 1 : 0; info->is_pooled = vma.type == VMAType::PoolReserved || vma.type == VMAType::Pooled ? 1 : 0; info->is_committed = vma.IsMapped() ? 1 : 0; + if (vma.type == VMAType::Direct || vma.type == VMAType::Pooled) { + // Offset is only assigned for direct and pooled mappings. + info->offset = vma.phys_base; + } + if (vma.type == VMAType::Reserved || vma.type == VMAType::PoolReserved) { + // Protection is hidden from reserved mappings. + info->protection = 0; + } strncpy(info->name, vma.name.data(), ::Libraries::Kernel::ORBIS_KERNEL_MAXIMUM_NAME_LENGTH); From f1a8b7d85e4f8279f1ec59960c32dcfee0be3fb0 Mon Sep 17 00:00:00 2001 From: TheTurtle Date: Mon, 24 Nov 2025 03:26:34 +0200 Subject: [PATCH 3/5] vector_alu: Fix V_CMP_U64 (#3823) * vector_alu: Fix V_CMP_U64 * vector_alu: Also handle vcc in V_CMP_U64 --- .../frontend/translate/vector_alu.cpp | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/src/shader_recompiler/frontend/translate/vector_alu.cpp b/src/shader_recompiler/frontend/translate/vector_alu.cpp index 604efabbd..83633402c 100644 --- a/src/shader_recompiler/frontend/translate/vector_alu.cpp +++ b/src/shader_recompiler/frontend/translate/vector_alu.cpp @@ -1043,20 +1043,25 @@ void Translator::V_CMP_U32(ConditionOp op, bool is_signed, bool set_exec, const } void Translator::V_CMP_U64(ConditionOp op, bool is_signed, bool set_exec, const GcnInst& inst) { - const IR::U64 src0{GetSrc64(inst.src[0])}; - const IR::U64 src1{GetSrc64(inst.src[1])}; + ASSERT(inst.src[1].field == OperandField::ConstZero); + const IR::U1 src0 = [&] { + switch (inst.src[0].field) { + case OperandField::ScalarGPR: + return ir.GetThreadBitScalarReg(IR::ScalarReg(inst.src[0].code)); + case OperandField::VccLo: + return ir.GetVcc(); + default: + UNREACHABLE_MSG("src0 = {}", u32(inst.src[0].field)); + } + }(); const IR::U1 result = [&] { switch (op) { case ConditionOp::EQ: - return ir.IEqual(src0, src1); + return ir.LogicalNot(src0); case ConditionOp::LG: // NE - return ir.INotEqual(src0, src1); + return src0; case ConditionOp::GT: - if (src1.IsImmediate() && src1.U64() == 0) { - ASSERT(inst.src[0].field == OperandField::ScalarGPR); - return ir.GroupAny(ir.GetThreadBitScalarReg(IR::ScalarReg(inst.src[0].code))); - } - return ir.IGreaterThan(src0, src1, is_signed); + return ir.GroupAny(ir.GetThreadBitScalarReg(IR::ScalarReg(inst.src[0].code))); default: UNREACHABLE_MSG("Unsupported V_CMP_U64 condition operation: {}", u32(op)); } From 8123c44ad172acb1e85a143e517dfd54cc9b8ba4 Mon Sep 17 00:00:00 2001 From: Missake Date: Mon, 24 Nov 2025 02:28:48 +0100 Subject: [PATCH 4/5] Make FSR off by default (#3801) * Make FSR and RCAS off by default * Update config.cpp --- src/common/config.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/config.cpp b/src/common/config.cpp index 4d3e1d877..b0f068142 100644 --- a/src/common/config.cpp +++ b/src/common/config.cpp @@ -177,7 +177,7 @@ static ConfigEntry isFullscreen(false); static ConfigEntry fullscreenMode("Windowed"); static ConfigEntry presentMode("Mailbox"); static ConfigEntry isHDRAllowed(false); -static ConfigEntry fsrEnabled(true); +static ConfigEntry fsrEnabled(false); static ConfigEntry rcasEnabled(true); static ConfigEntry rcasAttenuation(250); From 2577dfde7e5e26dd6a38b8093c774eea02c27eab Mon Sep 17 00:00:00 2001 From: kalaposfos13 <153381648+kalaposfos13@users.noreply.github.com> Date: Mon, 24 Nov 2025 02:30:09 +0100 Subject: [PATCH 5/5] Add assert on SFO file being empty (#3815) --- src/core/file_format/psf.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/file_format/psf.cpp b/src/core/file_format/psf.cpp index 047828330..e647059f0 100644 --- a/src/core/file_format/psf.cpp +++ b/src/core/file_format/psf.cpp @@ -36,6 +36,7 @@ bool PSF::Open(const std::filesystem::path& filepath) { } const u64 psfSize = file.GetSize(); + ASSERT_MSG(psfSize != 0, "SFO file at {} is empty!", filepath.string()); std::vector psf(psfSize); file.Seek(0); file.Read(psf);