Files
ARMSX2/common/HostSys.h
T
Brian Degenhardt 3e077eff9b Merge yaps2: arm64 JIT transplant + test/perf/libretro infrastructure
Merges yaps2/main (github.com/yaps2/yaps2, c16b88cb7) into ARMSX2,
replacing the arm64 recompiler family with the yaps2 JITs and importing
the yaps2 testing, perf, and libretro infrastructure. Common ancestor is
upstream PCSX2 342db5152 (2026-06-19); git auto-merged all but 38 files.

Replaced (deleted in this merge, recoverable from history):
- arm64/aR5900*, aR3000A*, aVU* -> arm64/iR5900*/iR3000A*/microVU*-arm64:
  EE static-pin register file with lazy dirty tracking, dual-residence
  allocator, IOP block linking, native COP2 macro ops, inline unaligned
  fastmem, persisted VU program cache, call-ret shadow ring, VU0 spin
  fast-forward.
- MVU_DIFF shadow-run hooks in shared VU interpreter TUs (superseded by
  the offline vurunner JIT-vs-interp oracle).

Imported from yaps2:
- tests/ctest/core/recompilers: ~80 gtest suites (EE/IOP/VU differential
  harnesses, fuzzers, ABI digest tripwire, capture format pins) plus the
  gs_vertex_tests kernel oracle.
- pcsx2-vurunner / pcsx2-eerunner headless capture-replay runners.
- tools/perf counter-based A/B rigs, perf jitdump productionization,
  PmuCounters, clang-perf/clang-handheld presets.
- pcsx2-libretro core (ENABLE_LIBRETRO, default OFF; rename pending).
- GS vertex-kick fast path (GV series): TBL-based packed parse,
  register-resident kick, scalar-outcode cull, fused draw-rect/FindMinMax.
- Null renderer, VK_KHR_display direct WSI, swapchain PresentStats.
- SPU2 NEON mixer vectorization, EE timer read clamp (NFL 2K5 hang),
  IOP ioman signed-compare fix, assorted UB fixes.

Kept from ARMSX2 in the both-touched files:
- iOS dual-map W^X and fastmem-unavailable resilience (Memory, HostSys,
  vtlb). The split data/code area model is retained; both areas now take
  fixed VA hints so cached VU JIT code stays deterministic on Linux.
- Android thread-affinity model, VMState shutdown early-outs, all
  platform frontends, branding, CI, RetroAchievements identity/policy.
- GSDeviceVK: ARMSX2's push-descriptor decision logic (Mali crash gate,
  proprietary-vs-turnip Adreno split) merged with yaps2's descriptor-pool
  exhaustion recovery (flush + render-pass restart instead of dropped
  binds). Vendor feature policy is the union: Mali fbfetch policy with
  MediaTek/G57/Xclipse gates from ARMSX2; Adreno stencil/ROV/
  test-and-sample-depth hang avoidance and no_ps2_z_quantization from
  yaps2.

Build-system notes:
- The Qt debugger is now gated behind ENABLE_QT_DEBUGGER (default off on
  arm64) so handheld builds drop the KDDockWidgets dependency.
- GSDeviceNone and remaining yaps2 GS code were ported to the newer
  upstream GSTexture Usage-flags API.

The replaced backend's interpreter-fallback glue (intExecuteOneInst,
AndroidEEOpHist) and the EEDiffVerify runtime differ are retained for
now; dead pieces will be removed in a follow-up commit.
2026-07-19 10:24:29 -07:00

219 lines
6.1 KiB
C++

// SPDX-FileCopyrightText: 2002-2026 PCSX2 Dev Team
// SPDX-License-Identifier: GPL-3.0+
#pragma once
#include "common/Pcsx2Defs.h"
#include <atomic>
#include <functional>
#include <map>
#include <memory>
#include <string>
class Error;
// --------------------------------------------------------------------------------------
// PageProtectionMode
// --------------------------------------------------------------------------------------
class PageProtectionMode
{
protected:
bool m_read = false;
bool m_write = false;
bool m_exec = false;
public:
__fi constexpr PageProtectionMode() = default;
__fi constexpr PageProtectionMode& Read(bool allow = true)
{
m_read = allow;
return *this;
}
__fi constexpr PageProtectionMode& Write(bool allow = true)
{
m_write = allow;
return *this;
}
__fi constexpr PageProtectionMode& Execute(bool allow = true)
{
m_exec = allow;
return *this;
}
__fi constexpr PageProtectionMode& All(bool allow = true)
{
m_read = m_write = m_exec = allow;
return *this;
}
__fi constexpr bool CanRead() const { return m_read; }
__fi constexpr bool CanWrite() const { return m_write; }
__fi constexpr bool CanExecute() const { return m_exec && m_read; }
__fi constexpr bool IsNone() const { return !m_read && !m_write; }
};
static __fi PageProtectionMode PageAccess_None()
{
return PageProtectionMode();
}
static __fi PageProtectionMode PageAccess_ReadOnly()
{
return PageProtectionMode().Read();
}
static __fi PageProtectionMode PageAccess_WriteOnly()
{
return PageProtectionMode().Write();
}
static __fi PageProtectionMode PageAccess_ReadWrite()
{
return PageAccess_ReadOnly().Write();
}
static __fi PageProtectionMode PageAccess_ExecOnly()
{
return PageAccess_ReadOnly().Execute();
}
static __fi PageProtectionMode PageAccess_Any()
{
return PageProtectionMode().All();
}
// --------------------------------------------------------------------------------------
// HostSys
// --------------------------------------------------------------------------------------
namespace HostSys
{
extern void MemProtect(void* baseaddr, size_t size, const PageProtectionMode& mode);
extern std::string GetFileMappingName(const char* prefix);
extern void* CreateSharedMemory(const char* name, size_t size);
extern void DestroySharedMemory(void* ptr);
/// JIT write protect for Apple Silicon. Needs to be called prior to writing to any RWX pages.
#if !defined(__APPLE__) || !defined(ARCH_ARM64)
// clang-format -off
[[maybe_unused]] __fi static void BeginCodeWrite() {}
[[maybe_unused]] __fi static void EndCodeWrite() {}
[[maybe_unused]] __fi static void BeginCodeWriteRange(void*, size_t) {}
[[maybe_unused]] __fi static void EndCodeWriteRange(void*, size_t) {}
// clang-format on
#else
void BeginCodeWrite();
void EndCodeWrite();
void BeginCodeWriteRange(void* address, size_t size);
void EndCodeWriteRange(void* address, size_t size);
#endif
/// Flushes the instruction cache on the host for the specified range.
/// Only needed on ARM64, X86 has coherent D/I cache.
#ifdef ARCH_X86
[[maybe_unused]] __fi static void FlushInstructionCache(void* address, u32 size) {}
#else
void FlushInstructionCache(void* address, u32 size);
#endif
/// Returns the size of pages for the current host.
size_t GetRuntimePageSize();
/// Returns the size of a cache line for the current host.
size_t GetRuntimeCacheLineSize();
} // namespace HostSys
namespace PageFaultHandler
{
enum class HandlerResult
{
ContinueExecution,
ExecuteNextHandler,
};
HandlerResult HandlePageFault(void* exception_pc, void* fault_address, bool is_write);
bool Install(Error* error = nullptr);
bool InstallSecondaryThread();
} // namespace PageFaultHandler
class SharedMemoryMappingArea
{
public:
// fixed_base_hint: when non-zero, the area is placed at that VA (256MB-stride
// fallback slots, then kernel placement) so the reserved region — and any JIT
// code mapped inside it — lands at the same address every run, which a caller
// can rely on for address-stable code caching. Zero = kernel-chosen placement
// (the default).
static std::unique_ptr<SharedMemoryMappingArea> Create(size_t size, bool jit = false, uptr fixed_base_hint = 0);
~SharedMemoryMappingArea();
__fi size_t GetSize() const { return m_size; }
__fi size_t GetNumPages() const { return m_num_pages; }
__fi u8* BasePointer() const { return m_base_ptr; }
__fi u8* OffsetPointer(size_t offset) const { return m_base_ptr + offset; }
__fi u8* PagePointer(size_t page) const { return m_base_ptr + __pagesize * page; }
u8* Map(void* file_handle, size_t file_offset, void* map_base, size_t map_size, const PageProtectionMode& mode);
bool Unmap(void* map_base, size_t map_size, bool is_file = true);
private:
SharedMemoryMappingArea(u8* base_ptr, size_t size, size_t num_pages);
u8* m_base_ptr;
size_t m_size;
size_t m_num_pages;
size_t m_num_mappings = 0;
#ifdef _WIN32
using PlaceholderMap = std::map<size_t, size_t>;
PlaceholderMap::iterator FindPlaceholder(size_t page);
PlaceholderMap m_placeholder_ranges;
#endif
};
extern u64 GetTickFrequency();
extern u64 GetCPUTicks();
extern u64 GetPhysicalMemory();
extern u64 GetAvailablePhysicalMemory();
/// Spin for a short period of time (call while spinning waiting for a lock)
/// Returns the approximate number of ns that passed
extern u32 ShortSpin();
/// Number of ns to spin for before sleeping a thread
extern const u32 SPIN_TIME_NS;
/// Like C abort() but adds the given message to the crashlog
[[noreturn]] void AbortWithMessage(const char* msg);
extern std::string GetOSVersionString();
struct CPUInfo {
std::string name;
u32 num_big_cores;
u32 num_small_cores;
u32 num_threads;
u32 num_clusters;
};
const CPUInfo& GetCPUInfo();
namespace Common
{
/// Enables or disables the screen saver from starting.
bool InhibitScreensaver(bool inhibit);
/// Abstracts platform-specific code for asynchronously playing a sound.
/// On Windows, this will use PlaySound(). On Linux, it will shell out to aplay. On MacOS, it uses NSSound.
bool PlaySoundAsync(const char* path);
void SetMousePosition(int x, int y);
bool AttachMousePositionCb(std::function<void(int,int)> cb);
void DetachMousePositionCb();
} // namespace Common