diff --git a/Source/Windows/ARM64EC/Module.S b/Source/Windows/ARM64EC/Module.S index 9d8e169ee..6510dd447 100644 --- a/Source/Windows/ARM64EC/Module.S +++ b/Source/Windows/ARM64EC/Module.S @@ -81,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 diff --git a/Source/Windows/ARM64EC/Module.cpp b/Source/Windows/ARM64EC/Module.cpp index 8b6a0195e..8584afcf9 100644 --- a/Source/Windows/ARM64EC/Module.cpp +++ b/Source/Windows/ARM64EC/Module.cpp @@ -46,9 +46,17 @@ $end_info$ #include 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; @@ -85,6 +93,9 @@ struct ThreadCPUArea { } }; + +extern "C" NTSTATUS NtContinueNative(ARM64_NT_CONTEXT* NativeContext, BOOLEAN Alert); + namespace { fextl::unique_ptr CTX; fextl::unique_ptr SignalDelegator; @@ -437,7 +448,12 @@ void ProcessInit() { X64ReturnInstr = ::VirtualAlloc(nullptr, FEXCore::Utils::FEX_PAGE_SIZE, MEM_COMMIT, PAGE_EXECUTE_READWRITE); *reinterpret_cast(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(GetProcAddress(NtDll, "__wine_syscall_dispatcher")); + if (WineSyscallDispatcherPtr) { + WineSyscallDispatcher = *WineSyscallDispatcherPtr; + } } void ProcessTerm() {}