Merge pull request #3915 from bylaws/winbase

ARM64EC: Support the JIT API as is used by Windows
This commit is contained in:
Ryan Houdek authored and GitHub committed 2024-08-02 10:56:46 -07:00
commit 7ffd3e55d5
5 files changed
+208 -89

No files matched your search

+12 -8
View File
@@ -6,16 +6,20 @@
#include <winternl.h>
extern "C" {
void STDMETHODCALLTYPE ProcessInit();
void STDMETHODCALLTYPE ProcessTerm();
NTSTATUS STDMETHODCALLTYPE ProcessInit();
void STDMETHODCALLTYPE ProcessTerm(HANDLE Handle, BOOL After, NTSTATUS Status);
NTSTATUS STDMETHODCALLTYPE ThreadInit();
NTSTATUS STDMETHODCALLTYPE ThreadTerm(HANDLE Thread);
NTSTATUS STDMETHODCALLTYPE ResetToConsistentState(EXCEPTION_POINTERS* Ptrs, ARM64_NT_CONTEXT* Context, BOOLEAN* Continue);
NTSTATUS STDMETHODCALLTYPE ThreadTerm(HANDLE Thread, LONG ExitCode);
NTSTATUS STDMETHODCALLTYPE ResetToConsistentState(EXCEPTION_RECORD* Exception, CONTEXT* GuestContext, ARM64_NT_CONTEXT* NativeContext);
void STDMETHODCALLTYPE NotifyMemoryAlloc(void* Address, SIZE_T Size, ULONG Type, ULONG Prot, BOOL After, NTSTATUS Status);
void STDMETHODCALLTYPE NotifyMemoryFree(void* Address, SIZE_T Size, ULONG FreeType, BOOL After, NTSTATUS Status);
void STDMETHODCALLTYPE NotifyMemoryProtect(void* Address, SIZE_T Size, ULONG NewProt, BOOL After, NTSTATUS Status);
NTSTATUS STDMETHODCALLTYPE NotifyMapViewOfSection(void* Unk1, void* Address, void* Unk2, SIZE_T Size, ULONG AllocType, ULONG Prot);
void STDMETHODCALLTYPE NotifyUnmapViewOfSection(void* Address, BOOL After, NTSTATUS Status);
void STDMETHODCALLTYPE FlushInstructionCacheHeavy(const void* Address, SIZE_T Size);
void STDMETHODCALLTYPE BTCpu64FlushInstructionCache(const void* Address, SIZE_T Size);
void STDMETHODCALLTYPE NotifyMemoryAlloc(void* Address, SIZE_T Size, ULONG Type, ULONG Prot);
void STDMETHODCALLTYPE NotifyMemoryFree(void* Address, SIZE_T Size, ULONG FreeType);
void STDMETHODCALLTYPE NotifyMemoryProtect(void* Address, SIZE_T Size, ULONG NewProt);
void STDMETHODCALLTYPE NotifyUnmapViewOfSection(void* Address);
void STDMETHODCALLTYPE BTCpu64NotifyMemoryDirty(void* Address, SIZE_T Size);
void STDMETHODCALLTYPE BTCpu64NotifyReadFile(HANDLE Handle, void* Address, SIZE_T Size, BOOL After, NTSTATUS Status);
BOOLEAN STDMETHODCALLTYPE BTCpu64IsProcessorFeaturePresent(UINT Feature);
void STDMETHODCALLTYPE UpdateProcessorInformation(SYSTEM_CPU_INFORMATION* Info);
}
+20
View File
@@ -41,6 +41,9 @@ enter_jit:
// Expects a CONTEXT pointer in x0
.global BeginSimulation
BeginSimulation:
ldr x17, [x18, #0x1788] // TEB->ChpeV2CpuAreaInfo
ldr x16, [x17, #0x8] // ChpeV2CpuAreaInfo->EmulatorStackBase
mov sp, x16
bl "#SyncThreadContext"
ldr x17, [x18, #0x1788] // TEB->ChpeV2CpuAreaInfo
ldr x16, [x17, #0x48] // ChpeV2CpuAreaInfo->EmulatorData[3] - DispatcherLoopTopEnterECFillSRA
@@ -78,3 +81,20 @@ ret_sp_misaligned:
adrp lr, X64ReturnInstr
ldr lr, [lr, #:lo12:X64ReturnInstr]
br x17
// Calls NtContinue directly to allow continuing from a full native context, as the NTDLL NtContinue export takes in
// an x64 context with EC and the conversion to that loses the ARM64EC ABI-disallowed registers that FEX uses.
.global "#NtContinueNative"
"#NtContinueNative":
adrp x16, WineSyscallDispatcher
ldr x16, [x16, #:lo12:WineSyscallDispatcher]
cbz x16, direct_syscall
wine_syscall:
mov x9, x30
adrp x8, WineNtContinueSyscallId
ldr x8, [x8, #:lo12:WineNtContinueSyscallId]
blr x16
ret
direct_syscall:
svc #0x43
ret
+171 -78
View File
@@ -46,9 +46,17 @@ $end_info$
#include <wine/debug.h>
class ECSyscallHandler;
extern "C" {
void* X64ReturnInstr; // See Module.S
extern void* ExitFunctionEC;
// Wine doesn't support issuing direct system calls with SVC, and unlike Windows it doesn't have a 'stable' syscall number for NtContinue
void* WineSyscallDispatcher;
// TODO: this really shouldn't be hardcoded, once wine gains proper syscall thunks this can be dropped.
uint64_t WineNtContinueSyscallId = 0x1a;
}
struct ThreadCPUArea {
static constexpr size_t TEBCPUAreaOffset = 0x1788;
CHPE_V2_CPU_AREA_INFO* Area;
@@ -56,11 +64,11 @@ struct ThreadCPUArea {
explicit ThreadCPUArea(_TEB* TEB)
: Area(*reinterpret_cast<CHPE_V2_CPU_AREA_INFO**>(reinterpret_cast<uintptr_t>(TEB) + TEBCPUAreaOffset)) {}
uint64_t EmulatorStackLimit() const {
uint64_t& EmulatorStackLimit() const {
return Area->EmulatorStackLimit;
}
uint64_t EmulatorStackBase() const {
uint64_t& EmulatorStackBase() const {
return Area->EmulatorStackBase;
}
@@ -85,6 +93,9 @@ struct ThreadCPUArea {
}
};
extern "C" NTSTATUS NtContinueNative(ARM64_NT_CONTEXT* NativeContext, BOOLEAN Alert);
namespace {
fextl::unique_ptr<FEXCore::Context::Context> CTX;
fextl::unique_ptr<FEX::DummyHandlers::DummySignalDelegator> SignalDelegator;
@@ -232,55 +243,64 @@ static bool HandleUnalignedAccess(ARM64_NT_CONTEXT& Context) {
static void LoadStateFromECContext(FEXCore::Core::InternalThreadState* Thread, CONTEXT& Context) {
auto& State = Thread->CurrentFrame->State;
// General register state
State.gregs[FEXCore::X86State::REG_RAX] = Context.Rax;
State.gregs[FEXCore::X86State::REG_RCX] = Context.Rcx;
State.gregs[FEXCore::X86State::REG_RDX] = Context.Rdx;
State.gregs[FEXCore::X86State::REG_RBX] = Context.Rbx;
State.gregs[FEXCore::X86State::REG_RSP] = Context.Rsp;
State.gregs[FEXCore::X86State::REG_RBP] = Context.Rbp;
State.gregs[FEXCore::X86State::REG_RSI] = Context.Rsi;
State.gregs[FEXCore::X86State::REG_RDI] = Context.Rdi;
State.gregs[FEXCore::X86State::REG_R8] = Context.R8;
State.gregs[FEXCore::X86State::REG_R9] = Context.R9;
State.gregs[FEXCore::X86State::REG_R10] = Context.R10;
State.gregs[FEXCore::X86State::REG_R11] = Context.R11;
State.gregs[FEXCore::X86State::REG_R12] = Context.R12;
State.gregs[FEXCore::X86State::REG_R13] = Context.R13;
State.gregs[FEXCore::X86State::REG_R14] = Context.R14;
State.gregs[FEXCore::X86State::REG_R15] = Context.R15;
if (Context.ContextFlags & CONTEXT_INTEGER) {
// General register state
State.gregs[FEXCore::X86State::REG_RAX] = Context.Rax;
State.gregs[FEXCore::X86State::REG_RCX] = Context.Rcx;
State.gregs[FEXCore::X86State::REG_RDX] = Context.Rdx;
State.gregs[FEXCore::X86State::REG_RBX] = Context.Rbx;
State.rip = Context.Rip;
CTX->SetFlagsFromCompactedEFLAGS(Thread, Context.EFlags);
State.gregs[FEXCore::X86State::REG_RSI] = Context.Rsi;
State.gregs[FEXCore::X86State::REG_RDI] = Context.Rdi;
State.gregs[FEXCore::X86State::REG_R8] = Context.R8;
State.gregs[FEXCore::X86State::REG_R9] = Context.R9;
State.gregs[FEXCore::X86State::REG_R10] = Context.R10;
State.gregs[FEXCore::X86State::REG_R11] = Context.R11;
State.gregs[FEXCore::X86State::REG_R12] = Context.R12;
State.gregs[FEXCore::X86State::REG_R13] = Context.R13;
State.gregs[FEXCore::X86State::REG_R14] = Context.R14;
State.gregs[FEXCore::X86State::REG_R15] = Context.R15;
}
State.es_idx = Context.SegEs & 0xffff;
State.cs_idx = Context.SegCs & 0xffff;
State.ss_idx = Context.SegSs & 0xffff;
State.ds_idx = Context.SegDs & 0xffff;
State.fs_idx = Context.SegFs & 0xffff;
State.gs_idx = Context.SegGs & 0xffff;
if (Context.ContextFlags & CONTEXT_CONTROL) {
State.rip = Context.Rip;
State.gregs[FEXCore::X86State::REG_RSP] = Context.Rsp;
State.gregs[FEXCore::X86State::REG_RBP] = Context.Rbp;
CTX->SetFlagsFromCompactedEFLAGS(Thread, Context.EFlags);
}
// The TEB is the only populated GDT entry by default
const auto TEB = reinterpret_cast<uint64_t>(NtCurrentTeb());
State.gdt[(Context.SegGs & 0xffff) >> 3].base = TEB;
State.gs_cached = TEB;
State.fs_cached = 0;
State.es_cached = 0;
State.cs_cached = 0;
State.ss_cached = 0;
State.ds_cached = 0;
if (Context.ContextFlags & CONTEXT_SEGMENTS) {
State.es_idx = Context.SegEs & 0xffff;
State.cs_idx = Context.SegCs & 0xffff;
State.ss_idx = Context.SegSs & 0xffff;
State.ds_idx = Context.SegDs & 0xffff;
State.fs_idx = Context.SegFs & 0xffff;
State.gs_idx = Context.SegGs & 0xffff;
// Floating-point register state
CTX->SetXMMRegistersFromState(Thread, reinterpret_cast<const __uint128_t*>(Context.FltSave.XmmRegisters), nullptr);
memcpy(State.mm, Context.FltSave.FloatRegisters, sizeof(State.mm));
// The TEB is the only populated GDT entry by default
const auto TEB = reinterpret_cast<uint64_t>(NtCurrentTeb());
State.gdt[(Context.SegGs & 0xffff) >> 3].base = TEB;
State.gs_cached = TEB;
State.fs_cached = 0;
State.es_cached = 0;
State.cs_cached = 0;
State.ss_cached = 0;
State.ds_cached = 0;
}
State.FCW = Context.FltSave.ControlWord;
State.flags[FEXCore::X86State::X87FLAG_C0_LOC] = (Context.FltSave.StatusWord >> 8) & 1;
State.flags[FEXCore::X86State::X87FLAG_C1_LOC] = (Context.FltSave.StatusWord >> 9) & 1;
State.flags[FEXCore::X86State::X87FLAG_C2_LOC] = (Context.FltSave.StatusWord >> 10) & 1;
State.flags[FEXCore::X86State::X87FLAG_C3_LOC] = (Context.FltSave.StatusWord >> 14) & 1;
State.flags[FEXCore::X86State::X87FLAG_TOP_LOC] = (Context.FltSave.StatusWord >> 11) & 0b111;
State.AbridgedFTW = Context.FltSave.TagWord;
if (Context.ContextFlags & CONTEXT_FLOATING_POINT) {
// Floating-point register state
CTX->SetXMMRegistersFromState(Thread, reinterpret_cast<const __uint128_t*>(Context.FltSave.XmmRegisters), nullptr);
memcpy(State.mm, Context.FltSave.FloatRegisters, sizeof(State.mm));
State.FCW = Context.FltSave.ControlWord;
State.flags[FEXCore::X86State::X87FLAG_C0_LOC] = (Context.FltSave.StatusWord >> 8) & 1;
State.flags[FEXCore::X86State::X87FLAG_C1_LOC] = (Context.FltSave.StatusWord >> 9) & 1;
State.flags[FEXCore::X86State::X87FLAG_C2_LOC] = (Context.FltSave.StatusWord >> 10) & 1;
State.flags[FEXCore::X86State::X87FLAG_C3_LOC] = (Context.FltSave.StatusWord >> 14) & 1;
State.flags[FEXCore::X86State::X87FLAG_TOP_LOC] = (Context.FltSave.StatusWord >> 11) & 0b111;
State.AbridgedFTW = Context.FltSave.TagWord;
}
}
static void ReconstructThreadState(ARM64_NT_CONTEXT& Context) {
@@ -306,7 +326,7 @@ static ARM64_NT_CONTEXT ReconstructPackedECContext(ARM64_NT_CONTEXT& Context) {
ReconstructThreadState(Context);
ARM64_NT_CONTEXT ECContext {};
ECContext.ContextFlags = CONTEXT_ARM64_CONTROL | CONTEXT_ARM64_INTEGER | CONTEXT_ARM64_FLOATING_POINT;
ECContext.ContextFlags = CONTEXT_ARM64_FULL;
auto* Thread = GetCPUArea().ThreadState();
auto& State = Thread->CurrentFrame->State;
@@ -365,6 +385,7 @@ static void RethrowGuestException(const EXCEPTION_RECORD& Rec, ARM64_NT_CONTEXT&
uint64_t GuestSp = Context.X[Config.SRAGPRMapping[static_cast<size_t>(FEXCore::X86State::REG_RSP)]];
struct DispatchArgs {
ARM64_NT_CONTEXT Context;
uint64_t Pad[4]; // Only present on newer Windows versions, likely for SVE.
EXCEPTION_RECORD Rec;
uint64_t Align;
uint64_t Redzone[2];
@@ -407,7 +428,7 @@ extern "C" void SyncThreadContext(CONTEXT* Context) {
Exception::LoadStateFromECContext(Thread, *Context);
}
void ProcessInit() {
NTSTATUS ProcessInit() {
FEX::Config::InitializeConfigs();
FEXCore::Config::Initialize();
FEXCore::Config::AddLayer(FEX::Config::CreateGlobalMainLayer());
@@ -437,10 +458,17 @@ void ProcessInit() {
X64ReturnInstr = ::VirtualAlloc(nullptr, FEXCore::Utils::FEX_PAGE_SIZE, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
*reinterpret_cast<uint8_t*>(X64ReturnInstr) = 0xc3;
Exception::KiUserExceptionDispatcher = GetRedirectedProcAddress(GetModuleHandle("ntdll.dll"), "KiUserExceptionDispatcher");
const auto NtDll = GetModuleHandle("ntdll.dll");
Exception::KiUserExceptionDispatcher = GetRedirectedProcAddress(NtDll, "KiUserExceptionDispatcher");
const auto WineSyscallDispatcherPtr = reinterpret_cast<void**>(GetProcAddress(NtDll, "__wine_syscall_dispatcher"));
if (WineSyscallDispatcherPtr) {
WineSyscallDispatcher = *WineSyscallDispatcherPtr;
}
return STATUS_SUCCESS;
}
void ProcessTerm() {}
void ProcessTerm(HANDLE Handle, BOOL After, NTSTATUS Status) {}
class ScopedCallbackDisable {
private:
@@ -457,87 +485,135 @@ public:
}
};
NTSTATUS ResetToConsistentState(EXCEPTION_POINTERS* Ptrs, ARM64_NT_CONTEXT* Context, BOOLEAN* Continue) {
ScopedCallbackDisable Guard;
const auto* Exception = Ptrs->ExceptionRecord;
if (Exception->ExceptionCode == EXCEPTION_DATATYPE_MISALIGNMENT && Exception::HandleUnalignedAccess(*Context)) {
LogMan::Msg::DFmt("Handled unaligned atomic: new pc: {:X}", Context->Pc);
*Continue = true;
return STATUS_SUCCESS;
}
bool ResetToConsistentStateImpl(EXCEPTION_RECORD* Exception, CONTEXT* GuestContext, ARM64_NT_CONTEXT* NativeContext) {
LogMan::Msg::DFmt("Exception: Code: {:X} Address: {:X}", Exception->ExceptionCode, reinterpret_cast<uintptr_t>(Exception->ExceptionAddress));
const auto CPUArea = GetCPUArea();
if (Exception->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) {
const auto FaultAddress = static_cast<uint64_t>(Exception->ExceptionInformation[1]);
bool HandledRWX = false;
if (InvalidationTracker && GetCPUArea().ThreadState()) {
if (InvalidationTracker && CPUArea.ThreadState()) {
std::scoped_lock Lock(ThreadCreationMutex);
HandledRWX = InvalidationTracker->HandleRWXAccessViolation(FaultAddress);
}
if (HandledRWX) {
LogMan::Msg::DFmt("Handled self-modifying code: pc: {:X} fault: {:X}", Context->Pc, FaultAddress);
*Continue = true;
return STATUS_SUCCESS;
LogMan::Msg::DFmt("Handled self-modifying code: pc: {:X} fault: {:X}", NativeContext->Pc, FaultAddress);
return true;
}
}
if (!CTX->IsAddressInCodeBuffer(GetCPUArea().ThreadState(), Context->Pc) && !IsDispatcherAddress(Context->Pc)) {
return STATUS_SUCCESS;
if (!CTX->IsAddressInCodeBuffer(CPUArea.ThreadState(), NativeContext->Pc) && !IsDispatcherAddress(NativeContext->Pc)) {
LogMan::Msg::DFmt("Passing through exception");
return false;
}
if (Exception->ExceptionCode == EXCEPTION_DATATYPE_MISALIGNMENT && Exception::HandleUnalignedAccess(*NativeContext)) {
LogMan::Msg::DFmt("Handled unaligned atomic: new pc: {:X}", NativeContext->Pc);
return true;
}
if (IsEmulatorStackAddress(reinterpret_cast<uint64_t>(__builtin_frame_address(0)))) {
Exception::RethrowGuestException(*Exception, *Context);
LogMan::Msg::DFmt("Rethrowing onto guest stack: {:X}", Context->Sp);
*Continue = true;
return STATUS_SUCCESS;
Exception::RethrowGuestException(*Exception, *NativeContext);
LogMan::Msg::DFmt("Rethrowing onto guest stack: {:X}", NativeContext->Sp);
return true;
} else {
LogMan::Msg::EFmt("Unexpected exception in JIT code on guest stack");
return STATUS_SUCCESS;
return false;
}
}
void NotifyMemoryAlloc(void* Address, SIZE_T Size, ULONG Type, ULONG Prot) {
NTSTATUS ResetToConsistentState(EXCEPTION_RECORD* Exception, CONTEXT* GuestContext, ARM64_NT_CONTEXT* NativeContext) {
if (!GetCPUArea().ThreadState()) {
return STATUS_SUCCESS;
}
bool Cont {};
{
ScopedCallbackDisable guard;
Cont = ResetToConsistentStateImpl(Exception, GuestContext, NativeContext);
}
if (Cont) {
NtContinueNative(NativeContext, false);
}
return STATUS_SUCCESS;
}
void NotifyMemoryAlloc(void* Address, SIZE_T Size, ULONG Type, ULONG Prot, BOOL After, NTSTATUS Status) {
if (!InvalidationTracker || !GetCPUArea().ThreadState()) {
return;
}
if (!After || Status) {
return;
}
std::scoped_lock Lock(ThreadCreationMutex);
InvalidationTracker->HandleMemoryProtectionNotification(reinterpret_cast<uint64_t>(Address), static_cast<uint64_t>(Size), Prot);
}
void NotifyMemoryFree(void* Address, SIZE_T Size, ULONG FreeType) {
void NotifyMemoryFree(void* Address, SIZE_T Size, ULONG FreeType, BOOL After, NTSTATUS Status) {
if (!InvalidationTracker || !GetCPUArea().ThreadState()) {
return;
}
if (After) {
return;
}
std::scoped_lock Lock(ThreadCreationMutex);
if (!Size) {
InvalidationTracker->InvalidateContainingSection(reinterpret_cast<uint64_t>(Address), true);
} else if (FreeType & MEM_DECOMMIT) {
if (FreeType & MEM_DECOMMIT) {
InvalidationTracker->InvalidateAlignedInterval(reinterpret_cast<uint64_t>(Address), static_cast<uint64_t>(Size), true);
} else if (FreeType & MEM_RELEASE) {
InvalidationTracker->InvalidateContainingSection(reinterpret_cast<uint64_t>(Address), true);
}
}
void NotifyMemoryProtect(void* Address, SIZE_T Size, ULONG NewProt) {
void NotifyMemoryProtect(void* Address, SIZE_T Size, ULONG NewProt, BOOL After, NTSTATUS Status) {
if (!InvalidationTracker || !GetCPUArea().ThreadState()) {
return;
}
if (!After || Status) {
return;
}
std::scoped_lock Lock(ThreadCreationMutex);
InvalidationTracker->HandleMemoryProtectionNotification(reinterpret_cast<uint64_t>(Address), static_cast<uint64_t>(Size), NewProt);
}
void NotifyUnmapViewOfSection(void* Address) {
NTSTATUS NotifyMapViewOfSection(void* Unk1, void* Address, void* Unk2, SIZE_T Size, ULONG AllocType, ULONG Prot) {
return STATUS_SUCCESS;
}
void NotifyUnmapViewOfSection(void* Address, BOOL After, NTSTATUS Status) {
if (!InvalidationTracker || !GetCPUArea().ThreadState()) {
return;
}
if (After) {
return;
}
std::scoped_lock Lock(ThreadCreationMutex);
InvalidationTracker->InvalidateContainingSection(reinterpret_cast<uint64_t>(Address), true);
}
void FlushInstructionCacheHeavy(const void* Address, SIZE_T Size) {
if (!InvalidationTracker || !GetCPUArea().ThreadState()) {
return;
}
std::scoped_lock Lock(ThreadCreationMutex);
InvalidationTracker->InvalidateAlignedInterval(reinterpret_cast<uint64_t>(Address), static_cast<uint64_t>(Size), false);
}
void BTCpu64FlushInstructionCache(const void* Address, SIZE_T Size) {
if (!InvalidationTracker || !GetCPUArea().ThreadState()) {
return;
@@ -547,7 +623,23 @@ void BTCpu64FlushInstructionCache(const void* Address, SIZE_T Size) {
InvalidationTracker->InvalidateAlignedInterval(reinterpret_cast<uint64_t>(Address), static_cast<uint64_t>(Size), false);
}
void BTCpu64NotifyMemoryDirty(void* Address, SIZE_T Size) {
if (!InvalidationTracker || !GetCPUArea().ThreadState()) {
return;
}
std::scoped_lock Lock(ThreadCreationMutex);
InvalidationTracker->InvalidateAlignedInterval(reinterpret_cast<uint64_t>(Address), static_cast<uint64_t>(Size), false);
}
void BTCpu64NotifyReadFile(HANDLE Handle, void* Address, SIZE_T Size, BOOL After, NTSTATUS Status) {}
NTSTATUS ThreadInit() {
static constexpr size_t EmulatorStackSize = 0x40000;
const uint64_t EmulatorStack = reinterpret_cast<uint64_t>(::VirtualAlloc(nullptr, EmulatorStackSize, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE));
GetCPUArea().EmulatorStackLimit() = EmulatorStack;
GetCPUArea().EmulatorStackBase() = EmulatorStack + EmulatorStackSize;
const auto CPUArea = GetCPUArea();
auto* Thread = CTX->CreateThread(0, 0);
@@ -560,7 +652,7 @@ NTSTATUS ThreadInit() {
uint64_t EnterECFillSRA = Thread->CurrentFrame->Pointers.Common.DispatcherLoopTopEnterECFillSRA;
CPUArea.DispatcherLoopTopEnterECFillSRA() = EnterECFillSRA;
CPUArea.ContextAmd64() = {.ContextFlags = CONTEXT_CONTROL | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT,
CPUArea.ContextAmd64() = {.ContextFlags = CONTEXT_CONTROL | CONTEXT_SEGMENTS | CONTEXT_INTEGER | CONTEXT_FLOATING_POINT,
.AMD64_SegCs = 0x33,
.AMD64_SegDs = 0x2b,
.AMD64_SegEs = 0x2b,
@@ -582,7 +674,7 @@ NTSTATUS ThreadInit() {
return STATUS_SUCCESS;
}
NTSTATUS ThreadTerm(HANDLE Thread) {
NTSTATUS ThreadTerm(HANDLE Thread, LONG ExitCode) {
const auto [Err, CPUArea] = GetThreadCPUArea(Thread);
if (Err) {
return Err;
@@ -602,6 +694,7 @@ NTSTATUS ThreadTerm(HANDLE Thread) {
}
CTX->DestroyThread(OldThreadState);
::VirtualFree(reinterpret_cast<void*>(GetCPUArea().EmulatorStackLimit()), 0, MEM_RELEASE);
return STATUS_SUCCESS;
}
+4 -2
View File
@@ -3,12 +3,14 @@ LIBRARY libarm64ecfex.dll
EXPORTS
BTCpu64FlushInstructionCache
BTCpu64IsProcessorFeaturePresent
BTCpu64NotifyMemoryDirty
BTCpu64NotifyReadFile
DispatchJump DATA
RetToEntryThunk DATA
ExitToX64 DATA
BeginSimulation DATA
; FlushInstructionCacheHeavy
; NotifyMapViewOfSection
FlushInstructionCacheHeavy
NotifyMapViewOfSection
NotifyMemoryAlloc
NotifyMemoryFree
NotifyMemoryProtect
+1 -1
View File
@@ -68,7 +68,7 @@ bool CPUFeatures::IsFeaturePresent(uint32_t Feature) {
case PF_SSE4_2_INSTRUCTIONS_AVAILABLE: return !!(CpuInfo.ProcessorFeatureBits & CPU_FEATURE_SSE42);
case PF_AVX_INSTRUCTIONS_AVAILABLE: return !!(CpuInfo.ProcessorFeatureBits & CPU_FEATURE_AVX);
case PF_AVX2_INSTRUCTIONS_AVAILABLE: return !!(CpuInfo.ProcessorFeatureBits & CPU_FEATURE_AVX2);
default: LogMan::Msg::DFmt("Unknown CPU feature: {:X}", Feature); return false;
default: return false;
}
}