diff --git a/Source/Windows/ARM64EC/Module.S b/Source/Windows/ARM64EC/Module.S index 499facf5a..e182db3de 100644 --- a/Source/Windows/ARM64EC/Module.S +++ b/Source/Windows/ARM64EC/Module.S @@ -62,7 +62,14 @@ ExitFunctionEC: msr fpcr, x17 ldr x17, [x18, #0x1788] // TEB->ChpeV2CpuAreaInfo strb wzr, [x17, #0x0] // ChpeV2CpuAreaInfo->InSimulation - + ldr x17, [x17, #0x20] // ChpeV2CpuAreaInfo->SuspendDoorbell + ldr w17, [x17] + cbz w17, no_suspend +.global ExitFunctionSuspendPoint +ExitFunctionSuspendPoint: + brk #0xCAFE + // Will resume here +no_suspend: // 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. diff --git a/Source/Windows/ARM64EC/Module.cpp b/Source/Windows/ARM64EC/Module.cpp index 8022e41ce..b25fa43c6 100644 --- a/Source/Windows/ARM64EC/Module.cpp +++ b/Source/Windows/ARM64EC/Module.cpp @@ -66,6 +66,7 @@ extern IMAGE_DOS_HEADER __ImageBase; // Provided by the linker extern void* ExitFunctionEC; extern void* CheckCall; +extern void* ExitFunctionSuspendPoint; void* X64ReturnInstr; // See Module.S uintptr_t NtDllBase; @@ -712,6 +713,15 @@ bool ResetToConsistentStateImpl(EXCEPTION_RECORD* Exception, CONTEXT* GuestConte FEXCORE_PROFILE_ACCUMULATION(Thread, AccumulatedSignalTime); LogMan::Msg::DFmt("Exception: Code: {:X} Address: {:X}", Exception->ExceptionCode, reinterpret_cast(Exception->ExceptionAddress)); + if (NativeContext->Pc == reinterpret_cast(&ExitFunctionSuspendPoint)) { + // A suspend interrupt can occur in ExitFunctionEC before InSimulation is unset and set SuspendDoorbell. If this + // occurs then it is still our duty to cooperatively suspend with an appropriate context. To support this, after + // unsetting InSimulation a brk #0xCAFE instruction will be raised that we can handle here. + NativeContext->Pc += 4; // Skip over the brk instruction when we resume + *CPUArea.Area->SuspendDoorbell = 0; + return true; + } + if (Exception->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) { const auto FaultAddress = static_cast(Exception->ExceptionInformation[1]);