Files
FEX-Emu--FEX/Source/Windows/ARM64EC/Module.S
T
Billy Laws 4877bb3f19 ARM64EC: Support directly issuing the NtContinue syscall
This is required for handling SMC with the ResetToConsistentState
arguments as used in Windows, as using the NTDLL exported NtContinue
would wipe out any reserved registers in the ARM64EC ABI.

For Windows the syscall numbers are somewhat stable, and the SVC
instruction can be called directly. Since wine doesn't handle that on
ARM64, hardcode the system call number and manually call into wine
dispatcher. Once wine gains proper syscall thunks, those can be
parsed to get the number and the hardcoding dropped.
2024-08-01 12:06:05 +00:00

101 lines
3.4 KiB
ArmAsm

.text
.balign 16
// __os_arm64x_x64_jump in ARM64EC docs
// Expects target code address in x9
.globl DispatchJump
DispatchJump:
str lr, [sp, #-8]! // Push return address to stack, this will be popped by the x86 RET instr.
b check_target_ec
// __os_arm64x_dispatch_ret in ARM64EC docs
// Expects target code address in lr
.globl RetToEntryThunk
RetToEntryThunk:
mov x9, lr
check_target_ec:
// Check if target is in fact x86 code
ldr x16, [x18, #0x60] // TEB->PEB
ldr x16, [x16, #0x368] // PEB->EcCodeBitMap
lsr x17, x9, #15
and x17, x17, #0x1fffffffffff8
ldr x16, [x16, x17]
lsr x17, x9, #12
lsr x16, x16, x17
tbnz x16, #0, ExitFunctionEC
b enter_jit
// __os_arm64x_dispatch_call_no_redirect in ARM64EC docs
// Expects target code address in x9, and to be called using a 'blr x16' instruction.
.globl ExitToX64
ExitToX64:
str lr, [sp, #-8]! // Push return address to stack, this will be popped by the x86 RET instr.
enter_jit:
ldr x17, [x18, #0x1788] // TEB->ChpeV2CpuAreaInfo
ldr x16, [x17, #0x40] // ChpeV2CpuAreaInfo->EmulatorData[2] - DispatcherLoopTopEnterEC
br x16 // DispatcherLoopTopEnterEC(RIP:x9, CPUArea:x17)
// Invoked by KiUserEmulationDispatcher after e.g. an NtContinue to x86 code
// 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
br x16 // DispatcherLoopTopEnterECFillSRA(CPUArea:x17)
// Called into by FEXCore
// Expects the target code address in x9
.global ExitFunctionEC
ExitFunctionEC:
// Either return to an exit thunk (return to ARM64EC function) or call an entry thunk (call to ARM64EC function).
// It is assumed that a 'blr x16' instruction is only ever used to call into x86 code from an exit thunk, and that all
// exported ARM64EC functions have a 4-byte offset to their entry thunk immediately before their first instruction.
mov x17, x9
mov w16, #0x200
movk w16, #0xd63f, lsl 16 // blr x16
ldursw x23, [x17, #-0x4] // Load either the entry thunk offset or the calling instruction.
cmp w23, w16
beq ret_sp_aligned
and x23, x23, #-0x4
add x17, x17, x23 // Resolve entry thunk address.
mov x4, sp
tbz x4, #3, ret_sp_misaligned
ldr lr, [x4], #0x8 // Pop the return address into lr.
mov sp, x4
ret_sp_aligned:
br x17
ret_sp_misaligned:
// In the case of the x64 caller leaving sp only 8-byte aligned, leave the return address on the stack to keep 16-byte
// alignment and have the callee return to an x86 ret instruction. FEX can then return to the actual caller keeping
// the misaligned RSP.
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