Merge pull request #3933 from bylaws/arm64-suspend

Support cooperative suspend on ARM64EC
This commit is contained in:
Ryan Houdek 2024-08-15 01:22:28 -07:00 committed by GitHub
commit df0ecad15b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 31 additions and 2 deletions

View File

@ -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

View File

@ -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) {

View File

@ -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;
};

View File

@ -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

View File

@ -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;
}