diff --git a/Source/Windows/Defs/wow64.def b/Source/Windows/Defs/wow64.def index e5291402c..438ce7ebe 100644 --- a/Source/Windows/Defs/wow64.def +++ b/Source/Windows/Defs/wow64.def @@ -22,12 +22,13 @@ EXPORTS Wow64PassExceptionToGuest @16 Wow64PrepareForDebuggerAttach @17 PRIVATE Wow64PrepareForException @18 - Wow64RaiseException @19 - Wow64ShallowThunkAllocObjectAttributes32TO64_FNC @20 PRIVATE - Wow64ShallowThunkAllocSecurityQualityOfService32TO64_FNC @21 PRIVATE - Wow64ShallowThunkSIZE_T32TO64 @22 PRIVATE - Wow64ShallowThunkSIZE_T64TO32 @23 PRIVATE - Wow64SuspendLocalThread @24 - Wow64SystemServiceEx @25 - Wow64ValidateUserCallTarget @26 PRIVATE - Wow64ValidateUserCallTargetFilter @27 PRIVATE + Wow64ProcessPendingCrossProcessItems @19 + Wow64RaiseException @20 + Wow64ShallowThunkAllocObjectAttributes32TO64_FNC @21 PRIVATE + Wow64ShallowThunkAllocSecurityQualityOfService32TO64_FNC @22 PRIVATE + Wow64ShallowThunkSIZE_T32TO64 @23 PRIVATE + Wow64ShallowThunkSIZE_T64TO32 @24 PRIVATE + Wow64SuspendLocalThread @25 PRIVATE + Wow64SystemServiceEx @26 + Wow64ValidateUserCallTarget @27 PRIVATE + Wow64ValidateUserCallTargetFilter @28 PRIVATE diff --git a/Source/Windows/WOW64/Module.cpp b/Source/Windows/WOW64/Module.cpp index a199632f5..1d5177c7c 100644 --- a/Source/Windows/WOW64/Module.cpp +++ b/Source/Windows/WOW64/Module.cpp @@ -35,6 +35,7 @@ $end_info$ #include #include #include +#include #include #include #include @@ -94,6 +95,7 @@ namespace { SYSTEM_CPU_INFORMATION CpuInfo{}; std::mutex ThreadSuspendLock; + std::unordered_set InitializedWOWThreads; // Set of TIDs, `ThreadSuspendLock` must be locked when accessing std::pair GetThreadTLS(HANDLE Thread) { THREAD_BASIC_INFORMATION Info; @@ -460,6 +462,7 @@ public: const uint64_t EntryRAX = Frame->State.gregs[FEXCore::X86State::REG_RAX]; Context::UnlockJITContext(); + Wow64ProcessPendingCrossProcessItems(); ReturnRAX = static_cast(Wow64SystemServiceEx(static_cast(EntryRAX), reinterpret_cast(ReturnRSP + 4))); Context::LockJITContext(); @@ -554,6 +557,8 @@ void BTCpuProcessInit() { NTSTATUS BTCpuThreadInit() { GetTLS().ThreadState() = CTX->CreateThread(nullptr, 0); + std::scoped_lock Lock(ThreadSuspendLock); + InitializedWOWThreads.emplace(GetCurrentThreadId()); return STATUS_SUCCESS; } @@ -563,6 +568,17 @@ NTSTATUS BTCpuThreadTerm(HANDLE Thread) { return Err; } + { + THREAD_BASIC_INFORMATION Info; + if (NTSTATUS Err = NtQueryInformationThread(Thread, ThreadBasicInformation, &Info, sizeof(Info), nullptr); Err) { + return Err; + } + + const auto ThreadTID = reinterpret_cast(Info.ClientId.UniqueThread); + std::scoped_lock Lock(ThreadSuspendLock); + InitializedWOWThreads.erase(ThreadTID); + } + CTX->DestroyThread(TLS.ThreadState()); return STATUS_SUCCESS; } @@ -665,6 +681,11 @@ NTSTATUS BTCpuSuspendLocalThread(HANDLE Thread, ULONG *Count) { } std::scoped_lock Lock(ThreadSuspendLock); + + // If the thread hasn't yet been initialized, suspend it without special handling as it wont yet have entered the JIT + if (!InitializedWOWThreads.contains(ThreadTID)) + return NtSuspendThread(Thread, Count); + // If CONTROL_IN_JIT is unset at this point, then it can never be set (and thus the JIT cannot be reentered) as // CONTROL_PAUSED has been set, as such, while this may redundantly request interrupts in rare cases it will never // miss them diff --git a/Source/Windows/include/winternl.h b/Source/Windows/include/winternl.h index dddcc6963..72fbb257a 100644 --- a/Source/Windows/include/winternl.h +++ b/Source/Windows/include/winternl.h @@ -90,6 +90,7 @@ typedef enum _MEMORY_INFORMATION_CLASS { } MEMORY_INFORMATION_CLASS; NTSTATUS WINAPI Wow64SystemServiceEx(UINT,UINT*); +void WINAPI Wow64ProcessPendingCrossProcessItems(void); NTSTATUS WINAPI RtlWow64SetThreadContext(HANDLE,const WOW64_CONTEXT*); NTSTATUS WINAPI RtlWow64GetThreadContext(HANDLE,WOW64_CONTEXT*);