mirror of
https://github.com/FEX-Emu/FEX.git
synced 2025-02-10 00:55:55 +00:00
Merge pull request #3933 from bylaws/arm64-suspend
Support cooperative suspend on ARM64EC
This commit is contained in:
commit
df0ecad15b
@ -347,8 +347,8 @@ bool ContextImpl::InitCore() {
|
||||
|
||||
#ifndef _WIN32
|
||||
ThunkHandler = FEXCore::ThunkHandler::Create();
|
||||
#else
|
||||
// WIN32 always needs the interrupt fault check to be enabled.
|
||||
#elif !defined(_M_ARM64EC)
|
||||
// WOW64 always needs the interrupt fault check to be enabled.
|
||||
Config.NeedsPendingInterruptFaultCheck = true;
|
||||
#endif
|
||||
|
||||
|
@ -718,6 +718,16 @@ CPUBackend::CompiledCode Arm64JITCore::CompileCode(uint64_t Entry, const FEXCore
|
||||
offsetof(FEXCore::Core::InternalThreadState, InterruptFaultPage) - offsetof(FEXCore::Core::InternalThreadState, BaseFrameState));
|
||||
}
|
||||
|
||||
#ifdef _M_ARM_64EC
|
||||
static constexpr uint16_t SuspendMagic {0xCAFE};
|
||||
|
||||
ldr(TMP2.W(), STATE_PTR(CpuStateFrame, SuspendDoorbell));
|
||||
ARMEmitter::SingleUseForwardLabel l_NoSuspend;
|
||||
cbz(ARMEmitter::Size::i32Bit, TMP2, &l_NoSuspend);
|
||||
brk(SuspendMagic);
|
||||
Bind(&l_NoSuspend);
|
||||
#endif
|
||||
|
||||
SpillSlots = RAData->SpillSlots();
|
||||
|
||||
if (SpillSlots) {
|
||||
|
@ -345,6 +345,11 @@ struct CpuStateFrame {
|
||||
|
||||
InternalThreadState* Thread;
|
||||
|
||||
#ifdef _M_ARM_64EC
|
||||
// Set by the kernel on ARM64EC whenever the JIT should cooperatively suspend running guest code.
|
||||
uint32_t SuspendDoorbell {};
|
||||
#endif
|
||||
|
||||
// Pointers that the JIT needs to load to remove relocations
|
||||
JITPointers Pointers;
|
||||
};
|
||||
|
@ -34,6 +34,8 @@ ExitToX64:
|
||||
|
||||
enter_jit:
|
||||
ldr x17, [x18, #0x1788] // TEB->ChpeV2CpuAreaInfo
|
||||
mov w16, #1
|
||||
strb w16, [x17, #0x0] // ChpeV2CpuAreaInfo->InSimulation
|
||||
ldr x16, [x17, #0x40] // ChpeV2CpuAreaInfo->EmulatorData[2] - DispatcherLoopTopEnterEC
|
||||
br x16 // DispatcherLoopTopEnterEC(RIP:x9, CPUArea:x17)
|
||||
|
||||
@ -57,6 +59,8 @@ ExitFunctionEC:
|
||||
mrs x17, fpcr
|
||||
and x17, x17, #~6 // NEP + AH
|
||||
msr fpcr, x17
|
||||
ldr x17, [x18, #0x1788] // TEB->ChpeV2CpuAreaInfo
|
||||
strb wzr, [x17, #0x0] // ChpeV2CpuAreaInfo->InSimulation
|
||||
|
||||
// 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
|
||||
|
@ -605,6 +605,15 @@ bool ResetToConsistentStateImpl(EXCEPTION_RECORD* Exception, CONTEXT* GuestConte
|
||||
return true;
|
||||
}
|
||||
|
||||
// The JIT (in CompileBlock) emits code to check the suspend doorbell at the start of every block, and run the following instruction if it is set:
|
||||
static constexpr uint32_t SuspendTrapMagic {0xD4395FC0}; // brk #0xCAFE
|
||||
if (Exception->ExceptionCode == EXCEPTION_ILLEGAL_INSTRUCTION && *reinterpret_cast<uint32_t*>(NativeContext->Pc) == SuspendTrapMagic) {
|
||||
*NativeContext = Exception::ReconstructPackedECContext(*NativeContext);
|
||||
LogMan::Msg::DFmt("Suspending: RIP: {:X} SP: {:X}", NativeContext->Pc, NativeContext->Sp);
|
||||
CPUArea.Area->InSimulation = 0;
|
||||
*CPUArea.Area->SuspendDoorbell = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (IsEmulatorStackAddress(reinterpret_cast<uint64_t>(__builtin_frame_address(0)))) {
|
||||
Exception::RethrowGuestException(*Exception, *NativeContext);
|
||||
@ -764,6 +773,7 @@ NTSTATUS ThreadInit() {
|
||||
}
|
||||
|
||||
CPUArea.ThreadState() = Thread;
|
||||
CPUArea.Area->SuspendDoorbell = reinterpret_cast<ULONG*>(&Thread->CurrentFrame->SuspendDoorbell);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user