Browse Source

Make Windows NCE code actually compliable

remotes/1785372757367212240/tmp_refs/heads/variable-page-size
Exverge 1 month ago
parent
commit
8b0229eda0
No known key found for this signature in database GPG Key ID: DAD399BCC5FB77E4
  1. 42
      src/common/host_memory.cpp
  2. 4
      src/core/CMakeLists.txt
  3. 82
      src/core/arm/nce/arm_nce.cpp
  4. 22
      src/core/arm/nce/arm_nce.h
  5. 26
      src/core/arm/nce/guest_context.h
  6. 31
      src/core/arm/nce/patcher.cpp
  7. 4
      src/core/arm/nce/patcher.h
  8. 29
      src/core/arm/nce/win/exceptions.cpp
  9. 18
      src/core/arm/nce/win/exceptions.h
  10. 14
      src/core/arm/nce/win/nt_headers.h
  11. 2
      src/core/arm/nce/win/platform_visitor.h
  12. 2
      src/core/hle/kernel/k_thread.h

42
src/common/host_memory.cpp

@ -110,6 +110,9 @@ using PFN_MapViewOfFile3 = _Ret_maybenull_ PVOID(WINAPI*)(
using PFN_UnmapViewOfFile2 = BOOL(WINAPI*)(_In_ HANDLE Process, _In_ PVOID BaseAddress,
_In_ ULONG UnmapFlags);
using PFN_VirtualQuery = SIZE_T(WINAPI*) (
_In_opt_ LPCVOID lpAddress, _Out_ PMEMORY_BASIC_INFORMATION lpBuffer, _In_ SIZE_T dwLength);
template <typename T>
static void GetFuncAddress(Common::DynamicLibrary& dll, const char* name, T& pfn) {
if (!dll.GetSymbol(name, &pfn)) {
@ -134,10 +137,11 @@ public:
}
GetFuncAddress(kernelbase_dll, "CreateFileMapping2", pfn_CreateFileMapping2);
GetFuncAddress(kernelbase_dll, "VirtualAlloc2", pfn_VirtualAlloc2);
GetFuncAddress(kernelbase_dll, "VirtualQuery", pfn_VirtualQuery);
GetFuncAddress(kernelbase_dll, "MapViewOfFile3", pfn_MapViewOfFile3);
GetFuncAddress(kernelbase_dll, "UnmapViewOfFile2", pfn_UnmapViewOfFile2);
if (!pfn_CreateFileMapping2 || !pfn_VirtualAlloc2 || !pfn_MapViewOfFile3 || !pfn_UnmapViewOfFile2) {
if (!pfn_CreateFileMapping2 || !pfn_VirtualAlloc2 || !pfn_VirtualQuery || !pfn_MapViewOfFile3 || !pfn_UnmapViewOfFile2) {
LOG_CRITICAL(HW_Memory, "Failed to find functions for virtual allocs");
return false;
}
@ -162,8 +166,39 @@ public:
LOG_CRITICAL(HW_Memory, "Failed to map {} MiB of virtual memory", backing_size >> 20);
return false;
}
// Allocate virtual address placeholder
virtual_base = static_cast<u8*>(pfn_VirtualAlloc2(process, nullptr, virtual_size, MEM_RESERVE | MEM_RESERVE_PLACEHOLDER, PAGE_NOACCESS, nullptr, 0));
// Allocate virtual address placeholder within a 39-bit address space
SIZE_T cursor = 0;
while (cursor < (1ULL << 39) - virtual_size) {
MEMORY_BASIC_INFORMATION info{};
// find the next mapped region of memory
auto res = pfn_VirtualQuery(reinterpret_cast<LPCVOID>(cursor), &info, sizeof(info));
if (res == 0) {
LOG_WARNING(HW_Memory, "Failed to check memory region: {}", GetLastError());
continue;
}
auto start_aligned = AlignUp(reinterpret_cast<SIZE_T>(info.BaseAddress), HugePageSize);
// is this region free?
if (info.State == MEM_FREE && start_aligned < reinterpret_cast<SIZE_T>(info.BaseAddress) + info.RegionSize) {
// is this region big enough for us to use?
if (info.RegionSize - (start_aligned - reinterpret_cast<SIZE_T>(info.BaseAddress)) >= virtual_size) {
virtual_base = static_cast<u8*>(pfn_VirtualAlloc2
(process, reinterpret_cast<PVOID>(start_aligned), virtual_size, MEM_RESERVE | MEM_RESERVE_PLACEHOLDER, PAGE_NOACCESS, nullptr, 0));
}
}
cursor = reinterpret_cast<SIZE_T>(info.BaseAddress) + info.RegionSize;
}
// Check if we failed to allocate for direct-mapping, otherwise map normally
if (!virtual_base) {
LOG_WARNING(HW_Memory, "Failed to allocate within 39-bit address space, direct mapping is not supported");
virtual_base = static_cast<u8*>(pfn_VirtualAlloc2
(process, nullptr, virtual_size, MEM_RESERVE | MEM_RESERVE_PLACEHOLDER, PAGE_NOACCESS, nullptr, 0));
}
if (!virtual_base) {
Release();
LOG_CRITICAL(HW_Memory, "Failed to reserve {} GiB of virtual memory", virtual_size >> 30);
@ -383,6 +418,7 @@ private:
DynamicLibrary kernelbase_dll;
PFN_CreateFileMapping2 pfn_CreateFileMapping2{};
PFN_VirtualAlloc2 pfn_VirtualAlloc2{};
PFN_VirtualQuery pfn_VirtualQuery{};
PFN_MapViewOfFile3 pfn_MapViewOfFile3{};
PFN_UnmapViewOfFile2 pfn_UnmapViewOfFile2{};

4
src/core/CMakeLists.txt

@ -1251,9 +1251,7 @@ if (HAS_NCE)
if (WIN32)
target_sources(core PRIVATE
arm/nce/win/platform_visitor.h
arm/nce/win/platform_visitor.cpp
arm/nce/win/exceptions.h
arm/nce/win/exceptions.cpp)
arm/nce/win/platform_visitor.cpp)
endif ()
endif()

82
src/core/arm/nce/arm_nce.cpp

@ -37,19 +37,17 @@
#include "core/hle/kernel/k_process.h"
#ifndef __WIN32
#ifndef _WIN32
#include <unistd.h>
#include <sys/syscall.h>
#include <signal.h>
#else
#include "core/arm/nce/win/exceptions.h"
#endif
namespace Core {
namespace {
#ifndef __WIN32
#ifndef _WIN32
struct sigaction g_orig_bus_action;
struct sigaction g_orig_segv_action;
#endif
@ -72,7 +70,7 @@ void* ArmNce::GetGuestParameters() {
: [out] "=&r"(nep)
: [off] "i"((ContextKey - 1) * 8)
: "memory");
#elif defined(__WIN32)
#elif defined(_WIN32)
asm volatile(
"mrs %[out], TPIDR_EL0\n" // load windows TLS storage
"ldr %[out], [ %[out], #%[off] ]\n"
@ -106,7 +104,7 @@ void ArmNce::UnlockThreadParameters(void* tpidr) {
static_cast<NativeExecutionParameters*>(tpidr)->lock.store(SpinLockUnlocked, std::memory_order_release);
}
#ifndef __WIN32
#ifndef _WIN32
YUZU_NAKED
YUZU_NO_INLINE
HaltReason ArmNce::ReturnToRunCodeByExceptionLevelChange(int tid, void *tpidr) {
@ -143,10 +141,10 @@ HaltReason ArmNce::ReturnToRunCodeByExceptionLevelChange(int tid, void *tpidr) {
}
YUZU_NAKED_END
#else
HaltReason ArmNce::ReturnToRunCodeByExceptionLevelChange(int tid, void *tpidr) {
DEBUG_ASSERT(os::TlsGetValue(ContextKey) == tpidr);
HaltReason ArmNce::ReturnToRunCodeByExceptionLevelChange(void* tid, void *tpidr) {
DEBUG_ASSERT(TlsGetValue(ContextKey) == tpidr);
os::RaiseException(SIGUSR2, 0, 0, nullptr); // TODO: pass tpidr through arguments?
RaiseException(ExceptionLevelChangeSignal, 0, 0, nullptr); // TODO: pass tpidr through arguments?
__builtin_unreachable();
}
#endif
@ -154,7 +152,7 @@ HaltReason ArmNce::ReturnToRunCodeByExceptionLevelChange(int tid, void *tpidr) {
void ArmNce::ReturnToRunCodeByExceptionLevelChangeSignalHandler(int sig, void *info, void *raw_context) {
auto tpidr = static_cast<NativeExecutionParameters*>(RestoreGuestContext(raw_context));
#if !defined(__APPLE__) && !defined(__WIN32)
#if !defined(__APPLE__) && !defined(_WIN32)
// Save old value of TPIDR_EL0, load guest one
u64 tpidr_el0;
asm volatile("mrs %0, TPIDR_EL0\n"
@ -186,7 +184,7 @@ HaltReason ArmNce::ReturnToRunCodeByTrampoline(void *tpidr, u64 trampoline_addr)
"ldr x2, [ x0, #%[ctx_off] ]\n"
"add x5, x2, #%[host_ctx] \n"
#if !defined(__APPLE__) && !defined(__WIN32)
#if !defined(__APPLE__) && !defined(_WIN32)
// Load guest tpidr_el0
"mrs x4, TPIDR_EL0\n"
"msr TPIDR_EL0, x0\n"
@ -223,7 +221,7 @@ HaltReason ArmNce::ReturnToRunCodeByTrampoline(void *tpidr, u64 trampoline_addr)
:: [ctx_off] "i"(offsetof(NativeExecutionParameters, native_context)),
[sp_off] "i"(offsetof(GuestContext, sp)),
[host_ctx] "i"(offsetof(GuestContext, host_ctx))
#if defined(__APPLE__) || defined(__WIN32)
#if defined(__APPLE__) || defined(_WIN32)
,[is_running_off] "i"(offsetof(NativeExecutionParameters, is_actually_running))
#endif
);
@ -232,7 +230,7 @@ YUZU_NAKED_END
static_assert(offsetof(HostContext, host_sp) == 0xE0); // TODO: don't use magic number
#ifndef __WIN32
#ifndef _WIN32
void ArmNce::BreakFromRunCodeSignalHandler(int sig, void *info, void *raw_context) {
NativeExecutionParameters* tpidr = static_cast<NativeExecutionParameters *>(GetGuestParameters());
@ -255,11 +253,9 @@ void ArmNce::BreakFromRunCodeSignalHandler(int sig, void *info, void *raw_contex
#endif
void ArmNce::GuestMemoryFaultSignalHandler(int sig, void* raw_info, void* raw_context) {
DEBUG_ASSERT(sig == SIGSEGV || sig == SIGBUS);
NativeExecutionParameters* nep = static_cast<NativeExecutionParameters*>(GetGuestParameters());
#if defined(__APPLE__) || defined(__WIN32)
#if defined(__APPLE__) || defined(_WIN32)
if (nep->is_actually_running) {
nep->is_actually_running = false;
#else
@ -274,10 +270,14 @@ void ArmNce::GuestMemoryFaultSignalHandler(int sig, void* raw_info, void* raw_co
auto* guest_ctx = static_cast<GuestContext*>(nep->native_context);
auto& memory = guest_ctx->parent->m_running_thread->GetOwnerProcess()->GetMemory();
#ifndef _WIN32
if (sig == SIGSEGV) {
#else
if (sig == static_cast<int>(EXCEPTION_ACCESS_VIOLATION)) {
#endif
// Try to handle an invalid access.
// TODO: handle accesses which split a page?
#ifndef __WIN32
#ifndef _WIN32
const Common::ProcessAddress addr =
(reinterpret_cast<u64>(static_cast<siginfo_t*>(raw_info)->si_addr) & ~Memory::YUZU_PAGEMASK);
#else
@ -288,7 +288,11 @@ void ArmNce::GuestMemoryFaultSignalHandler(int sig, void* raw_info, void* raw_co
// We handled the access successfully and are returning to guest code.
goto ret;
}
#ifndef _WIN32
} else if (sig == SIGBUS) {
#else
} else if (sig == static_cast<int>(EXCEPTION_DATATYPE_MISALIGNMENT)) {
#endif
// Match and execute an instruction.
auto ctx = KernelContext(raw_context);
auto next_pc = MatchAndExecuteOneInstruction(memory, &ctx);
@ -318,7 +322,7 @@ void ArmNce::GuestMemoryFaultSignalHandler(int sig, void* raw_info, void* raw_co
nep->is_actually_running = true;
#endif
}
#ifndef __WIN32
#ifndef _WIN32
else {
// Host fault, call original handler
if (sig == SIGSEGV) {
@ -329,7 +333,7 @@ void ArmNce::GuestMemoryFaultSignalHandler(int sig, void* raw_info, void* raw_co
UNREACHABLE_MSG("unexpected signal {}", sig);
}
}
#elif
#else
is_host_fault = true;
#endif
}
@ -338,7 +342,7 @@ void* ArmNce::RestoreGuestContext(void* raw_context) {
// Retrieve the host context.
auto host_ctx = KernelContext(raw_context);
#ifndef __WIN32
#ifndef _WIN32
// Thread-local parameters will be located in x9.
auto* tpidr = reinterpret_cast<NativeExecutionParameters*>(host_ctx.regs()[9]);
#else
@ -401,7 +405,11 @@ bool ArmNce::HandleFailedGuestFault(GuestContext* guest_ctx, void* raw_info, voi
auto host_ctx = KernelContext(raw_context);
// We can't handle the access, so determine why we crashed.
#ifndef _WIN32
const bool is_prefetch_abort = *host_ctx.pc() == reinterpret_cast<u64>(static_cast<siginfo_t*>(raw_info)->si_addr);
#else
const bool is_prefetch_abort = *host_ctx.pc() == *static_cast<u64*>(raw_info);
#endif
// For data aborts, skip the instruction and return to guest code.
// This will allow games to continue in many scenarios where they would otherwise crash.
@ -453,7 +461,7 @@ HaltReason ArmNce::RunThread(Kernel::KThread* thread) {
#if defined(__APPLE__)
ASSERT(pthread_setspecific(ContextKey, &thread_params) == 0);
#elif defined(__WIN32)
#elif defined(_WIN32)
ASSERT(TlsSetValue(ContextKey, &thread_params) == 0);
#endif
@ -526,6 +534,27 @@ ArmNce::ArmNce(System& system, bool uses_wall_clock, std::size_t core_index)
ArmNce::~ArmNce() = default;
#ifdef _WIN32
LONG WINAPI ArmNce::VectoredExceptionHandler(PEXCEPTION_POINTERS info) {
DWORD code = info->ExceptionRecord->ExceptionCode;
if (code == EXCEPTION_ACCESS_VIOLATION || code == EXCEPTION_DATATYPE_MISALIGNMENT) {
GuestMemoryFaultSignalHandler(code, reinterpret_cast<void*>(&info->ExceptionRecord->ExceptionAddress), info->ContextRecord);
if (is_host_fault) {
is_host_fault = false;
return EXCEPTION_CONTINUE_SEARCH;
}
return EXCEPTION_CONTINUE_EXECUTION;
} else if (code == ExceptionLevelChangeSignal) {
ReturnToRunCodeByExceptionLevelChangeSignalHandler(code, reinterpret_cast<void*>(&info->ExceptionRecord->ExceptionAddress), info->ContextRecord);
return EXCEPTION_CONTINUE_EXECUTION;
} else {
// other exception? let it pass
return EXCEPTION_CONTINUE_SEARCH;
}
}
#endif
#ifdef __APPLE__
// https://github.com/apple-oss-distributions/libpthread/blob/42d026df5b07825070f60134b980a1ec2552dfee/src/pthread_tsd.c#L418-L435
extern "C" int pthread_key_init_np(int, void (*)(void *));
@ -542,13 +571,14 @@ void ArmNce::Initialize() {
if (m_thread_id == -1) {
m_thread_id = gettid();
}
#elif defined(__WIN32)
#elif defined(_WIN32)
if (m_thread_id == nullptr) {
DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(),
&m_thread_id, 0, false, DUPLICATE_SAME_ACCESS);
}
#endif
#ifndef _WIN32
// Configure signal stack.
if (!m_stack) {
m_stack = std::make_unique<u8[]>(StackSize);
@ -562,7 +592,6 @@ void ArmNce::Initialize() {
// Set up signals.
static std::once_flag flag;
std::call_once(flag, [] {
#ifndef __WIN32
using HandlerType = decltype(sigaction::sa_sigaction);
sigset_t signal_mask;
@ -600,10 +629,11 @@ void ArmNce::Initialize() {
reinterpret_cast<HandlerType>(&ArmNce::GuestMemoryFaultSignalHandler);
access_fault_action.sa_mask = signal_mask;
Common::SigAction(SIGSEGV, &access_fault_action, &g_orig_segv_action);
});
#else
AddVectoredExceptionHandler(1, VectoredExceptionHandler);
static std::once_flag flag;
std::call_once(flag, [] { AddVectoredExceptionHandler(1, VectoredExceptionHandler); });
#endif
});
}
void ArmNce::SetTpidrroEl0(u64 value) {
@ -663,7 +693,7 @@ void ArmNce::SignalInterrupt(Kernel::KThread* thread) {
"svc #0x80\n"
:: "r"(static_cast<u64>(m_thread_id)), "r"(static_cast<u64>(SIGURG))
: "x0", "x1", "x16", "memory", "cc");
#elif defined(__WIN32)
#elif defined(_WIN32)
// TODO: use SetThreadState to emulate BreakFromRunCodeSignalHandler
SuspendThread(m_thread_id);
UnlockThreadParameters(params);

22
src/core/arm/nce/arm_nce.h

@ -11,6 +11,10 @@
#include "core/arm/arm_interface.h"
#include "core/arm/nce/guest_context.h"
#ifdef _WIN32
#include <winternl.h>
#endif
#define SpinLockLocked 0
#define SpinLockUnlocked 1
@ -28,11 +32,14 @@ class System;
// so we can manually initialize and use it.
// https://github.com/apple-oss-distributions/libpthread/blob/42d026df5b07825070f60134b980a1ec2552dfee/private/pthread/tsd_private.h#L241-L245
constexpr pthread_key_t ContextKey = 210;
#elif __WIN32
#elif _WIN32
#define ExceptionLevelChangeSignal 0xE0000001
thread_local bool is_host_fault = false;
static const u32 ContextKey = os::TlsAlloc();
static const u32 NCEStorage = os::TlsAlloc();
static const u64 TlsSlots = offsetof(os::TEB, TlsSlots);
static const u32 ContextKey = TlsAlloc();
static const u32 NCEStorage = TlsAlloc();
static const u64 TlsSlots = offsetof(TEB, TlsSlots);
#endif
@ -77,7 +84,12 @@ private:
static void* GetGuestParameters();
static HaltReason ReturnToRunCodeByTrampoline(void* tpidr, u64 trampoline_addr);
#ifndef _WIN32
static HaltReason ReturnToRunCodeByExceptionLevelChange(int tid, void* tpidr);
#else
static HaltReason ReturnToRunCodeByExceptionLevelChange(void* tid, void* tpidr);
static LONG VectoredExceptionHandler(PEXCEPTION_POINTERS info);
#endif
static void ReturnToRunCodeByExceptionLevelChangeSignalHandler(int sig, void* info,
void* raw_context);
@ -96,7 +108,7 @@ public:
// Members set on initialization.
std::size_t m_core_index{};
#ifndef __WIN32
#ifndef _WIN32
pid_t m_thread_id{-1};
#else
void* m_thread_id{};

26
src/core/arm/nce/guest_context.h

@ -14,8 +14,9 @@
#ifdef __linux__
#include <signal.h>
#elif __WIN32
#include "core/arm/nce/win/nt_headers.h"
#elif _WIN32
#include <windows.h>
#undef interface
#endif
namespace Core {
@ -116,15 +117,15 @@ public:
u32* pstate() {
return &ptr->__ss.__cpsr;
}
#elif defined(__WIN32)
KernelContext(void* ptr) : ptr(static_cast<os::CONTEXT*>(ptr)) {}
#elif defined(_WIN32)
KernelContext(void* ptr) : ptr(static_cast<CONTEXT*>(ptr)) {}
u64* pc() {
return ptr->Pc;
return &ptr->Pc;
}
u64* sp() {
return ptr->Sp;
return &ptr->Sp;
}
u64* regs() {
@ -137,15 +138,18 @@ public:
}
u32* fpcr() {
return &ptr->Fpcr;
// unsigned long vs unsigned int
return reinterpret_cast<u32*>(&ptr->Fpcr);
}
u32* fpsr() {
return &ptr->Fpsr;
// unsigned long vs unsigned int
return reinterpret_cast<u32*>(&ptr->Fpsr);
}
u32* pstate() {
return &ptr->Cpsr;
// unsigned long vs unsigned int
return reinterpret_cast<u32*>(&ptr->Cpsr);
}
#endif
@ -163,8 +167,8 @@ private:
}
return reinterpret_cast<fpsimd_context*>(header);
}
#elif defined(__WIN32)
os::CONTEXT* ptr;
#elif defined(_WIN32)
CONTEXT* ptr;
#endif
};

31
src/core/arm/nce/patcher.cpp

@ -18,7 +18,7 @@
#include "core/memory.h"
#include "core/hle/kernel/k_thread.h"
#ifdef __WIN32
#ifdef _WIN32
#include "win/platform_visitor.h"
#endif
@ -169,16 +169,16 @@ bool Patcher::PatchText(std::span<const u8> program_image, const Kernel::CodeSet
if (auto exclusive = Exclusive{inst}; exclusive.Verify()) {
curr_patch->m_exclusives.push_back(i);
}
#ifdef __WIN32
// TODO: keep track of exclusives?
#ifdef _WIN32
// TODO: do we still keep track of exclusives?
if (auto scratch = CheckForPlatformRegister(inst); scratch) {
bool pre_buffer = false;
auto ret = AddRelocations(pre_buffer);
if (pre_buffer) {
WritePlatformRegHandler(ret, inst, scratch, c_pre);
WritePlatformRegHandler(ret, inst, *scratch, c_pre);
} else {
WritePlatformRegHandler(ret, inst, scratch, c);
WritePlatformRegHandler(ret, inst, *scratch, c);
}
}
#endif
@ -391,17 +391,16 @@ void Patcher::LoadTLS(oaknut::VectorCodeGenerator& cg, oaknut::XReg out) {
// https://github.com/apple-oss-distributions/xnu/blob/f6217f891ac0bb64f3d375211650a4c1ff8ca1ea/libsyscall/os/tsd.h#L156-L189
cg.MRS(out, oaknut::SystemReg::TPIDRRO_EL0);
cg.LDR(out, out, ContextKey * 8);
#elif __WIN32
#elif _WIN32
// x18 always points to TEB in Windows, we can just use that for TLS storage
ASSERT(out != X18);
cg.LDR(out, X18, TlsSlots + 8 * ContextKey);
#else
cg.MRS(out, oaknut::SystemReg::TPIDR_EL0);
#endif
}
#ifdef __WIN32
void Patcher::WritePlatformRegHandler(ModuleDestLabel module_dest, uint32 instruction, oaknut::XReg scratch, oaknut::VectorCodeGenerator& code) {
#ifdef _WIN32
void Patcher::WritePlatformRegHandler(ModuleDestLabel module_dest, u32 instruction, oaknut::XReg scratch, oaknut::VectorCodeGenerator& cg) {
// Save X18 register and scratch register
cg.STP(X18, scratch, SP, PRE_INDEXED, -16);
@ -410,7 +409,7 @@ void Patcher::WritePlatformRegHandler(ModuleDestLabel module_dest, uint32 instru
cg.LDR(X18, scratch, TlsSlots + 8 * NCEStorage);
// Perform operation
cg.append(instruction);
cg.dw(instruction);
// Store x18 register and restore scratch register
cg.STR(X18, scratch, TlsSlots + 8 * NCEStorage);
@ -540,7 +539,7 @@ void Patcher::WriteSvcTrampoline(ModuleDestLabel module_dest, u32 svc_id, oaknut
// Reload host TPIDR_EL0 and SP.
cg.LDP(X2, X3, X1, offsetof(HostContext, host_sp));
cg.MOV(SP, X2);
#if !defined(__APPLE__) && !defined(__WIN32)
#if !defined(__APPLE__) && !defined(_WIN32)
static_assert(offsetof(HostContext, host_sp) + 8 == offsetof(HostContext, host_tpidr_el0));
cg.MSR(oaknut::SystemReg::TPIDR_EL0, X3);
#endif
@ -608,8 +607,8 @@ void Patcher::WriteSvcTrampoline(ModuleDestLabel module_dest, u32 svc_id, oaknut
// Retrieve emulated TLS register from GuestContext.
void Patcher::WriteMrsHandler(ModuleDestLabel module_dest, oaknut::XReg dest_reg,
oaknut::SystemReg src_reg, oaknut::VectorCodeGenerator& cg) {
#ifdef __WIN32
if (dest_reg != X18) {
#ifdef _WIN32
if (dest_reg.index() == 18) {
#endif
LoadTLS(cg, dest_reg);
@ -618,7 +617,7 @@ void Patcher::WriteMrsHandler(ModuleDestLabel module_dest, oaknut::XReg dest_reg
} else {
cg.LDR(dest_reg, dest_reg, offsetof(NativeExecutionParameters, tpidr_el0));
}
#ifdef __WIN32
#ifdef _WIN32
} else {
const auto scratch = dest_reg.index() == 0 ? X1 : X0;
cg.STR(scratch, SP, PRE_INDEXED, -16);
@ -646,8 +645,8 @@ void Patcher::WriteMsrHandler(ModuleDestLabel module_dest, oaknut::XReg src_reg,
// Save guest value to NativeExecutionParameters::tpidr_el0.
LoadTLS(cg, scratch_reg);
#ifdef __WIN32
if (src_reg == X18) {
#ifdef _WIN32
if (src_reg.index() == 18) {
// Load real x18 value and use that
cg.LDR(scratch_reg2, X18, TlsSlots + 8 * NCEStorage);
src_reg = scratch_reg2;

4
src/core/arm/nce/patcher.h

@ -82,8 +82,8 @@ private:
void WriteMrsHandler(ModuleDestLabel module_dest, oaknut::XReg dest_reg, oaknut::SystemReg src_reg, oaknut::VectorCodeGenerator& code);
void WriteMsrHandler(ModuleDestLabel module_dest, oaknut::XReg src_reg, oaknut::VectorCodeGenerator& code);
void WriteCntpctHandler(ModuleDestLabel module_dest, oaknut::XReg dest_reg, oaknut::VectorCodeGenerator& code);
#ifdef __WIN32
void WritePlatformRegHandler(ModuleDestLabel module_dest, uint32 instruction, oaknut::XReg scratch, oaknut::VectorCodeGenerator& code);
#ifdef _WIN32
void WritePlatformRegHandler(ModuleDestLabel module_dest, u32 instruction, oaknut::XReg scratch, oaknut::VectorCodeGenerator& code);
#endif
// Convenience wrappers using default code generator

29
src/core/arm/nce/win/exceptions.cpp

@ -1,29 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include "core/arm/nce/win/exceptions.h"
#include "core/arm/nce/arm_nce.h"
namespace Core {
static s32 WINAPI VectoredExecptionHandler(os::EXCEPTION_POINTERS* info) {
u32 code = info->ExceptionRecord->ExceptionCode;
if (code == SIGSEGV || code == SIGBUS) {
GuestMemoryFaultSignalHandler(code, &info->ExceptionRecord->ExceptionAddress, info->ContextRecord);
if (is_host_fault) {
is_host_fault = false;
return EXCEPTION_CONTINUE_SEARCH;
}
return EXCEPTION_CONTINUE_EXECUTION;
} else if (code == SIGUSR2) {
ReturnToGuestByExceptionLevelChangeSignalHandler(code, &info->ExceptionRecord->ExceptionAddress, info->ContextRecord);
return EXCEPTION_CONTINUE_EXECUTION;
} else {
// other exception?? let it pass
return EXCEPTION_CONTINUE_SEARCH;
}
}
} // namespace Core

18
src/core/arm/nce/win/exceptions.h

@ -1,18 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include "core/arm/nce/arm_nce.h"
#define SIGBUS EXCEPTION_DATATYPE_MISALIGNMENT
#define SIGSEGV EXCEPTION_ACCESS_VIOLATION
#define SIGUSR2 0xE0000001
namespace Core {
thread_local bool is_host_fault = false;
static s32 WINAPI VectoredExecptionHandler(os::EXCEPTION_POINTERS* info);
} // namespace Core

14
src/core/arm/nce/win/nt_headers.h

@ -1,14 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
// Use a separate namespace to not add Windows headers to the global path in header files
// We can't directly add Windows.h because of winternl.h
namespace os {
extern "C" {
#include <winternl.h>
#include <processthreadsapi.h>
#include <errhandlingapi.h>
}
} // namespace os

2
src/core/arm/nce/win/platform_visitor.h

@ -14,7 +14,7 @@ struct XReg;
namespace Core {
std::optional<oaknut::Reg> CheckForPlatformRegister(u32 instruction);
std::optional<oaknut::XReg> CheckForPlatformRegister(u32 instruction);
class PlatformVisitor final : public VisitorBase {
public:

2
src/core/hle/kernel/k_thread.h

@ -668,7 +668,7 @@ public:
public:
// TODO: This shouldn't be defined in kernel namespace
struct NativeExecutionParameters {
#if (defined(__APPLE__) || defined(__WIN32)) && HAS_NCE
#if (defined(__APPLE__) || defined(_WIN32)) && HAS_NCE
// Are we in actual guest code?
bool is_actually_running{};
#endif

Loading…
Cancel
Save