From d641d3f61e8d1e53b5661a0a3c7125b0ea47af5a Mon Sep 17 00:00:00 2001 From: Billy Laws Date: Tue, 1 Aug 2023 04:38:13 -0700 Subject: [PATCH 01/13] OpcodeDispatcher: Avoid redundantly passing args to WIN32 ABI syscalls --- FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp b/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp index a5b5c945d..acf89a2ad 100644 --- a/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp +++ b/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp @@ -71,11 +71,6 @@ void OpDispatchBuilder::SyscallOp(OpcodeArgs) { FEXCore::X86State::REG_RSP, }; - static constexpr SyscallArray GPRIndexes_Win32 = { - FEXCore::X86State::REG_RAX, - FEXCore::X86State::REG_RSP, - }; - SyscallFlags DefaultSyscallFlags = FEXCore::IR::SyscallFlags::DEFAULT; const auto OSABI = CTX->SyscallHandler->GetOSABI(); @@ -93,8 +88,9 @@ void OpDispatchBuilder::SyscallOp(OpcodeArgs) { DefaultSyscallFlags = FEXCore::IR::SyscallFlags::NORETURNEDRESULT; } else if (OSABI == FEXCore::HLE::SyscallOSABI::OS_WIN32) { - NumArguments = 2; - GPRIndexes = &GPRIndexes_Win32; + // Since the whole context is going to be saved at entry anyway, theres no need to do additional work to pass in args + NumArguments = 0; + GPRIndexes = nullptr; DefaultSyscallFlags = FEXCore::IR::SyscallFlags::NORETURNEDRESULT; } else if (OSABI == FEXCore::HLE::SyscallOSABI::OS_HANGOVER) { From 51f8c83c76d02ae9a7dc106dd6224fccc476aa2c Mon Sep 17 00:00:00 2001 From: Billy Laws Date: Sat, 5 Aug 2023 19:10:54 +0100 Subject: [PATCH 02/13] Context: Add an alternative thread-oriented execute function --- FEXCore/Source/Interface/Context/Context.h | 2 ++ FEXCore/Source/Interface/Core/Core.cpp | 4 ++++ FEXCore/include/FEXCore/Core/Context.h | 5 +++++ 3 files changed, 11 insertions(+) diff --git a/FEXCore/Source/Interface/Context/Context.h b/FEXCore/Source/Interface/Context/Context.h index 148cc3a52..d9309cdfa 100644 --- a/FEXCore/Source/Interface/Context/Context.h +++ b/FEXCore/Source/Interface/Context/Context.h @@ -87,6 +87,8 @@ namespace FEXCore::Context { ExitReason RunUntilExit() override; + void ExecuteThread(FEXCore::Core::InternalThreadState *Thread) override; + void CompileRIP(FEXCore::Core::InternalThreadState *Thread, uint64_t GuestRIP) override; int GetProgramStatus() const override; diff --git a/FEXCore/Source/Interface/Core/Core.cpp b/FEXCore/Source/Interface/Core/Core.cpp index 091455cb2..bdc2b94f0 100644 --- a/FEXCore/Source/Interface/Core/Core.cpp +++ b/FEXCore/Source/Interface/Core/Core.cpp @@ -574,6 +574,10 @@ namespace FEXCore::Context { } } + void ContextImpl::ExecuteThread(FEXCore::Core::InternalThreadState *Thread) { + Dispatcher->ExecuteDispatch(Thread->CurrentFrame); + } + int ContextImpl::GetProgramStatus() const { return ParentThread->StatusCode; } diff --git a/FEXCore/include/FEXCore/Core/Context.h b/FEXCore/include/FEXCore/Core/Context.h index 3b14bdfcd..661280ec3 100644 --- a/FEXCore/include/FEXCore/Core/Context.h +++ b/FEXCore/include/FEXCore/Core/Context.h @@ -176,6 +176,11 @@ namespace FEXCore::Context { */ FEX_DEFAULT_VISIBILITY virtual ExitReason RunUntilExit() = 0; + /** + * @brief Executes the supplied thread context on the current thread until a return is requested + */ + FEX_DEFAULT_VISIBILITY virtual void ExecuteThread(FEXCore::Core::InternalThreadState *Thread) = 0; + FEX_DEFAULT_VISIBILITY virtual void CompileRIP(FEXCore::Core::InternalThreadState *Thread, uint64_t GuestRIP) = 0; /** From f46fd4297735e0d7e63a15ba56e9b1e0f7ce57ae Mon Sep 17 00:00:00 2001 From: Billy Laws Date: Thu, 10 Aug 2023 04:35:10 -0700 Subject: [PATCH 03/13] Windows: Add a minimal set of wine-derived headers These are cut down versions of wine headers containing only what is necessary for WOW. This shouldn't carry any license implications for FEX, as per the LGPLv3 license: ``` The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following: a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the object code with a copy of the GNU GPL and this license document. ``` --- Source/Windows/include/wine/debug.h | 33 +++++++ Source/Windows/include/wine/unixlib.h | 35 ++++++++ Source/Windows/include/winternl.h | 123 ++++++++++++++++++++++++++ 3 files changed, 191 insertions(+) create mode 100644 Source/Windows/include/wine/debug.h create mode 100644 Source/Windows/include/wine/unixlib.h create mode 100644 Source/Windows/include/winternl.h diff --git a/Source/Windows/include/wine/debug.h b/Source/Windows/include/wine/debug.h new file mode 100644 index 000000000..c3bc48055 --- /dev/null +++ b/Source/Windows/include/wine/debug.h @@ -0,0 +1,33 @@ +/* + * Wine debugging interface + * + * Copyright 1999 Patrik Stridvall + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +int __cdecl __wine_dbg_output( const char *str ); + +#ifdef __cplusplus +} +#endif diff --git a/Source/Windows/include/wine/unixlib.h b/Source/Windows/include/wine/unixlib.h new file mode 100644 index 000000000..40d348081 --- /dev/null +++ b/Source/Windows/include/wine/unixlib.h @@ -0,0 +1,35 @@ +/* + * Definitions for Unix libraries + * + * Copyright (C) 2021 Alexandre Julliard + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +typedef UINT64 unixlib_handle_t; + +NTSTATUS WINAPI __wine_unix_call( unixlib_handle_t handle, unsigned int code, void *args ); + +#ifdef __cplusplus +} +#endif diff --git a/Source/Windows/include/winternl.h b/Source/Windows/include/winternl.h new file mode 100644 index 000000000..9cd5d2260 --- /dev/null +++ b/Source/Windows/include/winternl.h @@ -0,0 +1,123 @@ +/* + * Internal NT APIs and data structures + * + * Copyright (C) the Wine project + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#pragma once + +#include_next + +#ifdef __cplusplus +extern "C" { +#endif + +#define NtCurrentProcess() ((HANDLE)~(ULONG_PTR)0) + +#define WOW64_TLS_MAX_NUMBER 19 + +typedef struct _THREAD_BASIC_INFORMATION +{ + NTSTATUS ExitStatus; + PVOID TebBaseAddress; + CLIENT_ID ClientId; + ULONG_PTR AffinityMask; + LONG Priority; + LONG BasePriority; +} THREAD_BASIC_INFORMATION, *PTHREAD_BASIC_INFORMATION; + +/* System Information Class 0x01 */ + +typedef struct _SYSTEM_CPU_INFORMATION { + USHORT ProcessorArchitecture; + USHORT ProcessorLevel; + USHORT ProcessorRevision; + USHORT MaximumProcessors; + ULONG ProcessorFeatureBits; +} SYSTEM_CPU_INFORMATION, *PSYSTEM_CPU_INFORMATION; + +/* definitions of bits in the Feature set for the x86 processors */ +#define CPU_FEATURE_VME 0x00000005 /* Virtual 86 Mode Extensions */ +#define CPU_FEATURE_TSC 0x00000002 /* Time Stamp Counter available */ +#define CPU_FEATURE_CMOV 0x00000008 /* Conditional Move instruction*/ +#define CPU_FEATURE_PGE 0x00000014 /* Page table Entry Global bit */ +#define CPU_FEATURE_PSE 0x00000024 /* Page Size Extension */ +#define CPU_FEATURE_MTRR 0x00000040 /* Memory Type Range Registers */ +#define CPU_FEATURE_CX8 0x00000080 /* Compare and eXchange 8 byte instr. */ +#define CPU_FEATURE_MMX 0x00000100 /* Multi Media eXtensions */ +#define CPU_FEATURE_X86 0x00000200 /* seems to be always ON, on the '86 */ +#define CPU_FEATURE_PAT 0x00000400 /* Page Attribute Table */ +#define CPU_FEATURE_FXSR 0x00000800 /* FXSAVE and FXSTORE instructions */ +#define CPU_FEATURE_SEP 0x00001000 /* SYSENTER and SYSEXIT instructions */ +#define CPU_FEATURE_SSE 0x00002000 /* SSE extensions (ext. MMX) */ +#define CPU_FEATURE_3DNOW 0x00004000 /* 3DNOW instructions available */ +#define CPU_FEATURE_SSE2 0x00010000 /* SSE2 extensions (XMMI64) */ +#define CPU_FEATURE_DS 0x00020000 /* Debug Store */ +#define CPU_FEATURE_HTT 0x00040000 /* Hyper Threading Technology */ +#define CPU_FEATURE_SSE3 0x00080000 /* SSE3 extensions */ +#define CPU_FEATURE_CX128 0x00100000 /* cmpxchg16b instruction */ +#define CPU_FEATURE_XSAVE 0x00800000 /* XSAVE instructions */ +#define CPU_FEATURE_2NDLEV 0x04000000 /* Second-level address translation */ +#define CPU_FEATURE_VIRT 0x08000000 /* Virtualization support */ +#define CPU_FEATURE_RDFS 0x10000000 /* RDFSBASE etc. instructions */ +#define CPU_FEATURE_NX 0x20000000 /* Data execution prevention */ + +/* FIXME: following values are made up, actual flags are unknown */ +#define CPU_FEATURE_SSSE3 0x00008000 /* SSSE3 instructions */ +#define CPU_FEATURE_SSE41 0x01000000 /* SSE41 instructions */ +#define CPU_FEATURE_SSE42 0x02000000 /* SSE42 instructions */ +#define CPU_FEATURE_AVX 0x40000000 /* AVX instructions */ +#define CPU_FEATURE_AVX2 0x80000000 /* AVX2 instructions */ +#define CPU_FEATURE_PAE 0x00200000 +#define CPU_FEATURE_DAZ 0x00400000 + +typedef enum _MEMORY_INFORMATION_CLASS { + MemoryBasicInformation, + MemoryWorkingSetInformation, + MemoryMappedFilenameInformation, + MemoryRegionInformation, + MemoryWorkingSetExInformation, + MemorySharedCommitInformation, + MemoryImageInformation, + MemoryRegionInformationEx, + MemoryPrivilegedBasicInformation, + MemoryEnclaveImageInformation, + MemoryBasicInformationCapped, + MemoryPhysicalContiguityInformation, + MemoryBadInformation, + MemoryBadInformationAllProcesses, +#ifdef __WINESRC__ + MemoryWineUnixFuncs = 1000, + MemoryWineUnixWow64Funcs, +#endif +} MEMORY_INFORMATION_CLASS; + +NTSTATUS WINAPI Wow64SystemServiceEx(UINT,UINT*); + +NTSTATUS WINAPI RtlWow64SetThreadContext(HANDLE,const WOW64_CONTEXT*); +NTSTATUS WINAPI RtlWow64GetThreadContext(HANDLE,WOW64_CONTEXT*); +NTSTATUS WINAPI RtlWow64GetCurrentCpuArea(USHORT*,void**,void**); + +NTSTATUS WINAPI NtSuspendThread(HANDLE,PULONG); +NTSTATUS WINAPI NtGetContextThread(HANDLE,CONTEXT*); +NTSTATUS WINAPI NtContinue(PCONTEXT,BOOLEAN); +NTSTATUS WINAPI NtQueryVirtualMemory(HANDLE,LPCVOID,MEMORY_INFORMATION_CLASS,PVOID,SIZE_T,SIZE_T*); +NTSTATUS WINAPI NtProtectVirtualMemory(HANDLE,PVOID*,SIZE_T*,ULONG,ULONG*); + +#ifdef __cplusplus +} +#endif From 961213308858b8bc5d64ff2be71129049ff1a675 Mon Sep 17 00:00:00 2001 From: Billy Laws Date: Thu, 10 Aug 2023 04:50:20 -0700 Subject: [PATCH 04/13] Windows: Generate import libraries for private ntdll and wow64 APIs The MinGW supplied import libraries are incomplete and miss a lot of functions necessary to implement lower level windows code. To avoid needing to many resolve every function, pull in .def files from wine that detail the entire ntdll and wow64 APIs. --- Source/CMakeLists.txt | 4 + Source/Windows/CMakeLists.txt | 15 + Source/Windows/Defs/ntdll.def | 1378 +++++++++++++++++++++++++++++++++ Source/Windows/Defs/wow64.def | 33 + 4 files changed, 1430 insertions(+) create mode 100644 Source/Windows/CMakeLists.txt create mode 100644 Source/Windows/Defs/ntdll.def create mode 100644 Source/Windows/Defs/wow64.def diff --git a/Source/CMakeLists.txt b/Source/CMakeLists.txt index 23f435815..7514e23ec 100644 --- a/Source/CMakeLists.txt +++ b/Source/CMakeLists.txt @@ -1,2 +1,6 @@ add_subdirectory(Common/) add_subdirectory(Tools/) + +if (MINGW_BUILD) + add_subdirectory(Windows/) +endif() diff --git a/Source/Windows/CMakeLists.txt b/Source/Windows/CMakeLists.txt new file mode 100644 index 000000000..a5cfd7eff --- /dev/null +++ b/Source/Windows/CMakeLists.txt @@ -0,0 +1,15 @@ +function(build_implib name) + add_custom_target(${name}lib ALL DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/lib${name}.a) + add_custom_command( + OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/lib${name}.a + COMMAND ${CMAKE_DLLTOOL} -d ${CMAKE_CURRENT_SOURCE_DIR}/Defs/${name}.def -k -l lib${name}.a + COMMENT "Building lib${name}.a" + ) + + add_library(${name} SHARED IMPORTED) + set_property(TARGET ${name} PROPERTY IMPORTED_IMPLIB ${CMAKE_CURRENT_BINARY_DIR}/lib${name}.a) + add_dependencies(${name} ${name}lib) +endfunction() + +build_implib(ntdll) +build_implib(wow64) diff --git a/Source/Windows/Defs/ntdll.def b/Source/Windows/Defs/ntdll.def new file mode 100644 index 000000000..c6ba3b8e7 --- /dev/null +++ b/Source/Windows/Defs/ntdll.def @@ -0,0 +1,1378 @@ +; File generated automatically from wine/dlls/ntdll/ntdll.spec; do not edit! +; To generate: winebuild --def -E wine/dlls/ntdll/ntdll.spec > ntdll.def + +LIBRARY ntdll.dll + +EXPORTS + A_SHAFinal @1 + A_SHAInit @2 + A_SHAUpdate @3 + ApiSetQueryApiSetPresence @4 + ApiSetQueryApiSetPresenceEx @5 + CsrAllocateCaptureBuffer @6 PRIVATE + CsrAllocateCapturePointer @7 PRIVATE + CsrAllocateMessagePointer @8 PRIVATE + CsrCaptureMessageBuffer @9 PRIVATE + CsrCaptureMessageString @10 PRIVATE + CsrCaptureTimeout @11 PRIVATE + CsrClientCallServer @12 PRIVATE + CsrClientConnectToServer @13 PRIVATE + CsrClientMaxMessage @14 PRIVATE + CsrClientSendMessage @15 PRIVATE + CsrClientThreadConnect @16 PRIVATE + CsrFreeCaptureBuffer @17 PRIVATE + CsrIdentifyAlertableThread @18 PRIVATE + CsrNewThread @19 PRIVATE + CsrProbeForRead @20 PRIVATE + CsrProbeForWrite @21 PRIVATE + CsrSetPriorityClass @22 PRIVATE + CsrpProcessCallbackRequest @23 PRIVATE + DbgBreakPoint @24 + DbgPrint @25 + DbgPrintEx @26 + DbgPrompt @27 PRIVATE + DbgUiConnectToDbg @28 + DbgUiContinue @29 + DbgUiConvertStateChangeStructure @30 + DbgUiDebugActiveProcess @31 + DbgUiGetThreadDebugObject @32 + DbgUiIssueRemoteBreakin @33 + DbgUiRemoteBreakin @34 + DbgUiSetThreadDebugObject @35 + DbgUiStopDebugging @36 + DbgUiWaitStateChange @37 + DbgUserBreakPoint @38 + EtwEventActivityIdControl @39 + EtwEventEnabled @40 + EtwEventProviderEnabled @41 + EtwEventRegister @42 + EtwEventSetInformation @43 + EtwEventUnregister @44 + EtwEventWrite @45 + EtwEventWriteString @46 + EtwEventWriteTransfer @47 + EtwGetTraceEnableFlags @48 + EtwGetTraceEnableLevel @49 + EtwGetTraceLoggerHandle @50 + EtwLogTraceEvent @51 + EtwRegisterTraceGuidsA @52 + EtwRegisterTraceGuidsW @53 + EtwTraceMessage @54 + EtwTraceMessageVa @55 + EtwUnregisterTraceGuids @56 + KiRaiseUserExceptionDispatcher @57 + KiUserApcDispatcher @58 + KiUserCallbackDispatcher @59 + KiUserExceptionDispatcher @60 + LdrAccessResource @61 + LdrAddDllDirectory @62 + LdrAddRefDll @63 + LdrDisableThreadCalloutsForDll @64 + LdrEnumResources @65 PRIVATE + LdrEnumerateLoadedModules @66 + LdrFindEntryForAddress @67 + LdrFindResourceDirectory_U @68 + LdrFindResource_U @69 + LdrFlushAlternateResourceModules @70 PRIVATE + LdrGetDllDirectory @71 + LdrGetDllFullName @72 + LdrGetDllHandle @73 + LdrGetDllHandleEx @74 + LdrGetDllPath @75 + LdrGetProcedureAddress @76 + LdrInitShimEngineDynamic @77 PRIVATE + LdrInitializeThunk @78 + LdrLoadAlternateResourceModule @79 PRIVATE + LdrLoadDll @80 + LdrLockLoaderLock @81 + LdrProcessRelocationBlock @82 + LdrQueryImageFileExecutionOptions @83 + LdrQueryProcessModuleInformation @84 + LdrRegisterDllNotification @85 + LdrRemoveDllDirectory @86 + LdrResolveDelayLoadedAPI @87 + LdrSetAppCompatDllRedirectionCallback @88 PRIVATE + LdrSetDefaultDllDirectories @89 + LdrSetDllDirectory @90 + LdrSetDllManifestProber @91 PRIVATE + LdrShutdownProcess @92 + LdrShutdownThread @93 + LdrSystemDllInitBlock @94 DATA + LdrUnloadAlternateResourceModule @95 PRIVATE + LdrUnloadDll @96 + LdrUnlockLoaderLock @97 + LdrUnregisterDllNotification @98 + LdrVerifyImageMatchesChecksum @99 PRIVATE + MD4Final @100 + MD4Init @101 + MD4Update @102 + MD5Final @103 + MD5Init @104 + MD5Update @105 + NlsAnsiCodePage @106 DATA + NlsMbCodePageTag @107 DATA + NlsMbOemCodePageTag @108 DATA + NtAcceptConnectPort @109 + NtAccessCheck @110 + NtAccessCheckAndAuditAlarm @111 + NtAddAtom @112 + NtAdjustGroupsToken @113 + NtAdjustPrivilegesToken @114 + NtAlertResumeThread @115 + NtAlertThread @116 + NtAlertThreadByThreadId @117 + NtAllocateLocallyUniqueId @118 + NtAllocateUuids @119 + NtAllocateVirtualMemory @120 + NtAllocateVirtualMemoryEx @121 + NtAreMappedFilesTheSame @122 + NtAssignProcessToJobObject @123 + NtCallbackReturn @124 + NtCancelIoFile @125 + NtCancelIoFileEx @126 + NtCancelSynchronousIoFile @127 + NtCancelTimer @128 + NtClearEvent @129 + NtClose @130 + NtCommitTransaction @131 + NtCompareObjects @132 + NtCompleteConnectPort @133 + NtConnectPort @134 + NtContinue @135 + NtCreateDebugObject @136 + NtCreateDirectoryObject @137 + NtCreateEvent @138 + NtCreateFile @139 + NtCreateIoCompletion @140 + NtCreateJobObject @141 + NtCreateKey @142 + NtCreateKeyTransacted @143 + NtCreateKeyedEvent @144 + NtCreateLowBoxToken @145 + NtCreateMailslotFile @146 + NtCreateMutant @147 + NtCreateNamedPipeFile @148 + NtCreatePagingFile @149 + NtCreatePort @150 + NtCreateSection @151 + NtCreateSemaphore @152 + NtCreateSymbolicLinkObject @153 + NtCreateThread @154 + NtCreateThreadEx @155 + NtCreateTimer @156 + NtCreateTransaction @157 + NtCreateUserProcess @158 + NtDebugActiveProcess @159 + NtDebugContinue @160 + NtDelayExecution @161 + NtDeleteAtom @162 + NtDeleteFile @163 + NtDeleteKey @164 + NtDeleteValueKey @165 + NtDeviceIoControlFile @166 + NtDisplayString @167 + NtDuplicateObject @168 + NtDuplicateToken @169 + NtEnumerateKey @170 + NtEnumerateValueKey @171 + NtFilterToken @172 + NtFindAtom @173 + NtFlushBuffersFile @174 + NtFlushInstructionCache @175 + NtFlushKey @176 + NtFlushProcessWriteBuffers @177 + NtFlushVirtualMemory @178 + NtFreeVirtualMemory @179 + NtFsControlFile @180 + NtGetContextThread @181 + NtGetCurrentProcessorNumber @182 + NtGetNextThread @183 + NtGetNlsSectionPtr @184 + NtGetTickCount @185 + NtGetWriteWatch @186 + NtImpersonateAnonymousToken @187 + NtInitializeNlsFiles @188 + NtInitiatePowerAction @189 + NtIsProcessInJob @190 + NtListenPort @191 + NtLoadDriver @192 + NtLoadKey2 @193 + NtLoadKey @194 + NtLoadKeyEx @195 + NtLockFile @196 + NtLockVirtualMemory @197 + NtMakeTemporaryObject @198 + NtMapViewOfSection @199 + NtMapViewOfSectionEx @200 + NtNotifyChangeDirectoryFile @201 + NtNotifyChangeKey @202 + NtNotifyChangeMultipleKeys @203 + NtOpenDirectoryObject @204 + NtOpenEvent @205 + NtOpenFile @206 + NtOpenIoCompletion @207 + NtOpenJobObject @208 + NtOpenKey @209 + NtOpenKeyEx @210 + NtOpenKeyTransacted @211 + NtOpenKeyTransactedEx @212 + NtOpenKeyedEvent @213 + NtOpenMutant @214 + NtOpenProcess @215 + NtOpenProcessToken @216 + NtOpenProcessTokenEx @217 + NtOpenSection @218 + NtOpenSemaphore @219 + NtOpenSymbolicLinkObject @220 + NtOpenThread @221 + NtOpenThreadToken @222 + NtOpenThreadTokenEx @223 + NtOpenTimer @224 + NtPowerInformation @225 + NtPrivilegeCheck @226 + NtProtectVirtualMemory @227 + NtPulseEvent @228 + NtQueryAttributesFile @229 + NtQueryDefaultLocale @230 + NtQueryDefaultUILanguage @231 + NtQueryDirectoryFile @232 + NtQueryDirectoryObject @233 + NtQueryEaFile @234 + NtQueryEvent @235 + NtQueryFullAttributesFile @236 + NtQueryInformationAtom @237 + NtQueryInformationFile @238 + NtQueryInformationJobObject @239 + NtQueryInformationProcess @240 + NtQueryInformationThread @241 + NtQueryInformationToken @242 + NtQueryInstallUILanguage @243 + NtQueryIoCompletion @244 + NtQueryKey @245 + NtQueryLicenseValue @246 + NtQueryMultipleValueKey @247 + NtQueryMutant @248 + NtQueryObject @249 + NtQueryPerformanceCounter @250 + NtQuerySection @251 + NtQuerySecurityObject @252 + NtQuerySemaphore @253 + NtQuerySymbolicLinkObject @254 + NtQuerySystemEnvironmentValue @255 + NtQuerySystemEnvironmentValueEx @256 + NtQuerySystemInformation @257 + NtQuerySystemInformationEx @258 + NtQuerySystemTime @259 + NtQueryTimer @260 + NtQueryTimerResolution @261 + NtQueryValueKey @262 + NtQueryVirtualMemory @263 + NtQueryVolumeInformationFile @264 + NtQueueApcThread @265 + NtRaiseException @266 + NtRaiseHardError @267 + NtReadFile @268 + NtReadFileScatter @269 + NtReadVirtualMemory @270 + NtRegisterThreadTerminatePort @271 + NtReleaseKeyedEvent @272 + NtReleaseMutant @273 + NtReleaseSemaphore @274 + NtRemoveIoCompletion @275 + NtRemoveIoCompletionEx @276 + NtRemoveProcessDebug @277 + NtRenameKey @278 + NtReplaceKey @279 + NtReplyWaitReceivePort @280 + NtRequestWaitReplyPort @281 + NtResetEvent @282 + NtResetWriteWatch @283 + NtRestoreKey @284 + NtResumeProcess @285 + NtResumeThread @286 + NtRollbackTransaction @287 + NtSaveKey @288 + NtSecureConnectPort @289 + NtSetContextThread @290 + NtSetDebugFilterState @291 + NtSetDefaultLocale @292 + NtSetDefaultUILanguage @293 + NtSetEaFile @294 + NtSetEvent @295 + NtSetInformationDebugObject @296 + NtSetInformationFile @297 + NtSetInformationJobObject @298 + NtSetInformationKey @299 + NtSetInformationObject @300 + NtSetInformationProcess @301 + NtSetInformationThread @302 + NtSetInformationToken @303 + NtSetInformationVirtualMemory @304 + NtSetIntervalProfile @305 + NtSetIoCompletion @306 + NtSetLdtEntries @307 + NtSetSecurityObject @308 + NtSetSystemInformation @309 + NtSetSystemTime @310 + NtSetThreadExecutionState @311 + NtSetTimer @312 + NtSetTimerResolution @313 + NtSetValueKey @314 + NtSetVolumeInformationFile @315 + NtShutdownSystem @316 + NtSignalAndWaitForSingleObject @317 + NtSuspendProcess @318 + NtSuspendThread @319 + NtSystemDebugControl @320 + NtTerminateJobObject @321 + NtTerminateProcess @322 + NtTerminateThread @323 + NtTestAlert @324 + NtTraceControl @325 + NtUnloadDriver @326 + NtUnloadKey @327 + NtUnlockFile @328 + NtUnlockVirtualMemory @329 + NtUnmapViewOfSection @330 + NtUnmapViewOfSectionEx @331 + NtWaitForAlertByThreadId @332 + NtWaitForDebugEvent @333 + NtWaitForKeyedEvent @334 + NtWaitForMultipleObjects @335 + NtWaitForSingleObject @336 + NtWriteFile @337 + NtWriteFileGather @338 + NtWriteVirtualMemory @339 + NtYieldExecution @340 + PfxFindPrefix @341 PRIVATE + PfxInitialize @342 PRIVATE + PfxInsertPrefix @343 PRIVATE + PfxRemovePrefix @344 PRIVATE + RtlAbortRXact @345 PRIVATE + RtlAbsoluteToSelfRelativeSD @346 + RtlAcquirePebLock @347 + RtlAcquireResourceExclusive @348 + RtlAcquireResourceShared @349 + RtlAcquireSRWLockExclusive @350 + RtlAcquireSRWLockShared @351 + RtlActivateActivationContext @352 + RtlActivateActivationContextEx @353 + RtlActivateActivationContextUnsafeFast @354 PRIVATE + RtlAddAccessAllowedAce @355 + RtlAddAccessAllowedAceEx @356 + RtlAddAccessAllowedObjectAce @357 + RtlAddAccessDeniedAce @358 + RtlAddAccessDeniedAceEx @359 + RtlAddAccessDeniedObjectAce @360 + RtlAddAce @361 + RtlAddActionToRXact @362 PRIVATE + RtlAddAtomToAtomTable @363 + RtlAddAttributeActionToRXact @364 PRIVATE + RtlAddAuditAccessAce @365 + RtlAddAuditAccessAceEx @366 + RtlAddAuditAccessObjectAce @367 + RtlAddFunctionTable @368 + RtlAddGrowableFunctionTable @369 + RtlAddMandatoryAce @370 + RtlAddProcessTrustLabelAce @371 + RtlAddRefActivationContext @372 + RtlAddVectoredContinueHandler @373 + RtlAddVectoredExceptionHandler @374 + RtlAddressInSectionTable @375 + RtlAdjustPrivilege @376 + RtlAllocateAndInitializeSid @377 + RtlAllocateHandle @378 + RtlAllocateHeap @379 + RtlAnsiCharToUnicodeChar @380 + RtlAnsiStringToUnicodeSize @381 + RtlAnsiStringToUnicodeString @382 + RtlAppendAsciizToString @383 + RtlAppendStringToString @384 + RtlAppendUnicodeStringToString @385 + RtlAppendUnicodeToString @386 + RtlApplyRXact @387 PRIVATE + RtlApplyRXactNoFlush @388 PRIVATE + RtlAreAllAccessesGranted @389 + RtlAreAnyAccessesGranted @390 + RtlAreBitsClear @391 + RtlAreBitsSet @392 + RtlAssert @393 + RtlCaptureContext @394 + RtlCaptureStackBackTrace @395 + RtlCharToInteger @396 + RtlCheckRegistryKey @397 + RtlClearAllBits @398 + RtlClearBits @399 + RtlClosePropertySet @400 PRIVATE + RtlCompactHeap @401 + RtlCompareMemory @402 + RtlCompareMemoryUlong @403 + RtlCompareString @404 + RtlCompareUnicodeString @405 + RtlCompareUnicodeStrings @406 + RtlCompressBuffer @407 + RtlComputeCrc32 @408 + RtlConsoleMultiByteToUnicodeN @409 PRIVATE + RtlConvertExclusiveToShared @410 PRIVATE + RtlConvertSharedToExclusive @411 PRIVATE + RtlConvertSidToUnicodeString @412 + RtlConvertToAutoInheritSecurityObject @413 + RtlConvertUiListToApiList @414 PRIVATE + RtlCopyContext @415 + RtlCopyExtendedContext @416 + RtlCopyLuid @417 + RtlCopyLuidAndAttributesArray @418 + RtlCopyMemory @419 + RtlCopyMemoryNonTemporal=RtlCopyMemory @420 + RtlCopySecurityDescriptor @421 + RtlCopySid @422 + RtlCopySidAndAttributesArray @423 PRIVATE + RtlCopyString @424 + RtlCopyUnicodeString @425 + RtlCreateAcl @426 + RtlCreateActivationContext @427 + RtlCreateAndSetSD @428 PRIVATE + RtlCreateAtomTable @429 + RtlCreateEnvironment @430 + RtlCreateHeap @431 + RtlCreateProcessParameters @432 + RtlCreateProcessParametersEx @433 + RtlCreatePropertySet @434 PRIVATE + RtlCreateQueryDebugBuffer @435 + RtlCreateRegistryKey @436 + RtlCreateSecurityDescriptor @437 + RtlCreateTagHeap @438 PRIVATE + RtlCreateTimer @439 + RtlCreateTimerQueue @440 + RtlCreateUnicodeString @441 + RtlCreateUnicodeStringFromAsciiz @442 + RtlCreateUserProcess @443 + RtlCreateUserSecurityObject @444 PRIVATE + RtlCreateUserStack @445 + RtlCreateUserThread @446 + RtlCustomCPToUnicodeN @447 + RtlCutoverTimeToSystemTime @448 PRIVATE + RtlDeNormalizeProcessParams @449 + RtlDeactivateActivationContext @450 + RtlDeactivateActivationContextUnsafeFast @451 PRIVATE + RtlDebugPrintTimes @452 PRIVATE + RtlDecodePointer @453 + RtlDecodeSystemPointer=RtlDecodePointer @454 + RtlDecompressBuffer @455 + RtlDecompressFragment @456 + RtlDefaultNpAcl @457 + RtlDelete @458 PRIVATE + RtlDeleteAce @459 + RtlDeleteAtomFromAtomTable @460 + RtlDeleteCriticalSection @461 + RtlDeleteGrowableFunctionTable @462 + RtlDeleteElementGenericTable @463 PRIVATE + RtlDeleteElementGenericTableAvl @464 PRIVATE + RtlDeleteFunctionTable @465 + RtlDeleteNoSplay @466 PRIVATE + RtlDeleteOwnersRanges @467 PRIVATE + RtlDeleteRange @468 PRIVATE + RtlDeleteRegistryValue @469 + RtlDeleteResource @470 + RtlDeleteSecurityObject @471 + RtlDeleteTimer @472 + RtlDeleteTimerQueueEx @473 + RtlDeregisterWait @474 + RtlDeregisterWaitEx @475 + RtlDestroyAtomTable @476 + RtlDestroyEnvironment @477 + RtlDestroyHandleTable @478 + RtlDestroyHeap @479 + RtlDestroyProcessParameters @480 + RtlDestroyQueryDebugBuffer @481 + RtlDetermineDosPathNameType_U @482 + RtlDllShutdownInProgress @483 + RtlDoesFileExists_U @484 + RtlDosPathNameToNtPathName_U @485 + RtlDosPathNameToNtPathName_U_WithStatus @486 + RtlDosPathNameToRelativeNtPathName_U @487 + RtlDosPathNameToRelativeNtPathName_U_WithStatus @488 + RtlDosSearchPath_U @489 + RtlDowncaseUnicodeChar @490 + RtlDowncaseUnicodeString @491 + RtlDumpResource @492 + RtlDuplicateUnicodeString @493 + RtlEmptyAtomTable @494 + RtlEncodePointer @495 + RtlEncodeSystemPointer=RtlEncodePointer @496 + RtlEnterCriticalSection @497 + RtlEnumProcessHeaps @498 PRIVATE + RtlEnumerateGenericTable @499 PRIVATE + RtlEnumerateGenericTableWithoutSplaying @500 + RtlEnumerateProperties @501 PRIVATE + RtlEqualComputerName @502 + RtlEqualDomainName @503 + RtlEqualLuid @504 + RtlEqualPrefixSid @505 + RtlEqualSid @506 + RtlEqualString @507 + RtlEqualUnicodeString @508 + RtlEraseUnicodeString @509 + RtlExitUserProcess @510 + RtlExitUserThread @511 + RtlExpandEnvironmentStrings @512 + RtlExpandEnvironmentStrings_U @513 + RtlExtendHeap @514 PRIVATE + RtlFillMemory @515 + RtlFillMemoryUlong @516 + RtlFinalReleaseOutOfProcessMemoryStream @517 PRIVATE + RtlFindActivationContextSectionGuid @518 + RtlFindActivationContextSectionString @519 + RtlFindCharInUnicodeString @520 + RtlFindClearBits @521 + RtlFindClearBitsAndSet @522 + RtlFindClearRuns @523 + RtlFindExportedRoutineByName @524 + RtlFindLastBackwardRunClear @525 + RtlFindLastBackwardRunSet @526 + RtlFindLeastSignificantBit @527 + RtlFindLongestRunClear @528 + RtlFindLongestRunSet @529 + RtlFindMessage @530 + RtlFindMostSignificantBit @531 + RtlFindNextForwardRunClear @532 + RtlFindNextForwardRunSet @533 + RtlFindRange @534 PRIVATE + RtlFindSetBits @535 + RtlFindSetBitsAndClear @536 + RtlFindSetRuns @537 + RtlFirstEntrySList @538 + RtlFirstFreeAce @539 + RtlFlsAlloc @540 + RtlFlsFree @541 + RtlFlsGetValue @542 + RtlFlsSetValue @543 + RtlFlushPropertySet @544 PRIVATE + RtlFormatCurrentUserKeyPath @545 + RtlFormatMessage @546 + RtlFormatMessageEx @547 + RtlFreeActivationContextStack @548 + RtlFreeAnsiString @549 + RtlFreeHandle @550 + RtlFreeHeap @551 + RtlFreeOemString @552 + RtlFreeSid @553 + RtlFreeThreadActivationContextStack @554 + RtlFreeUnicodeString @555 + RtlFreeUserStack @556 + RtlGUIDFromString @557 + RtlGenerate8dot3Name @558 PRIVATE + RtlGetAce @559 + RtlGetActiveActivationContext @560 + RtlGetCallersAddress @561 PRIVATE + RtlGetCompressionWorkSpaceSize @562 + RtlGetControlSecurityDescriptor @563 + RtlGetCurrentDirectory_U @564 + RtlGetCurrentPeb @565 + RtlGetCurrentProcessorNumberEx @566 + RtlGetCurrentTransaction @567 + RtlGetDaclSecurityDescriptor @568 + RtlGetElementGenericTable @569 + RtlGetEnabledExtendedFeatures @570 + RtlGetExePath @571 + RtlGetExtendedContextLength @572 + RtlGetExtendedContextLength2 @573 + RtlGetExtendedFeaturesMask @574 + RtlGetFrame @575 + RtlGetFullPathName_U @576 + RtlGetGroupSecurityDescriptor @577 + RtlGetLastNtStatus @578 + RtlGetLastWin32Error @579 + RtlGetLocaleFileMappingAddress @580 + RtlGetLongestNtPathLength @581 + RtlGetNativeSystemInformation=NtQuerySystemInformation @582 + RtlGetNtGlobalFlags @583 + RtlGetNtProductType @584 + RtlGetNtVersionNumbers @585 + RtlGetOwnerSecurityDescriptor @586 + RtlGetProductInfo @587 + RtlGetProcessHeaps @588 + RtlGetProcessPreferredUILanguages @589 + RtlGetSaclSecurityDescriptor @590 + RtlGetSearchPath @591 + RtlGetSystemPreferredUILanguages @592 + RtlGetSystemTimePrecise @593 + RtlGetThreadErrorMode @594 + RtlGetThreadPreferredUILanguages @595 + RtlGetUnloadEventTrace @596 + RtlGetUnloadEventTraceEx @597 + RtlGetUserInfoHeap @598 + RtlGetUserPreferredUILanguages @599 + RtlGetVersion @600 + RtlGrowFunctionTable @601 + RtlGuidToPropertySetName @602 PRIVATE + RtlHashUnicodeString @603 + RtlIdentifierAuthoritySid @604 + RtlIdnToAscii @605 + RtlIdnToNameprepUnicode @606 + RtlIdnToUnicode @607 + RtlImageDirectoryEntryToData @608 + RtlImageNtHeader @609 + RtlImageRvaToSection @610 + RtlImageRvaToVa @611 + RtlImpersonateSelf @612 + RtlInitAnsiString @613 + RtlInitAnsiStringEx @614 + RtlInitCodePageTable @615 + RtlInitNlsTables @616 + RtlInitString @617 + RtlInitUnicodeString @618 + RtlInitUnicodeStringEx @619 + RtlInitializeBitMap @620 + RtlInitializeConditionVariable @621 + RtlInitializeContext @622 PRIVATE + RtlInitializeCriticalSection @623 + RtlInitializeCriticalSectionAndSpinCount @624 + RtlInitializeCriticalSectionEx @625 + RtlInitializeExtendedContext @626 + RtlInitializeExtendedContext2 @627 + RtlInitializeGenericTable @628 + RtlInitializeGenericTableAvl @629 + RtlInitializeHandleTable @630 + RtlInitializeRXact @631 PRIVATE + RtlInitializeResource @632 + RtlInitializeSListHead @633 + RtlInitializeSRWLock @634 + RtlInitializeSid @635 + RtlInsertElementGenericTable @636 PRIVATE + RtlInsertElementGenericTableAvl @637 + RtlInstallFunctionTableCallback @638 + RtlInt64ToUnicodeString @639 + RtlIntegerToChar @640 + RtlIntegerToUnicodeString @641 + RtlInterlockedFlushSList @642 + RtlInterlockedPopEntrySList @643 + RtlInterlockedPushEntrySList @644 + RtlInterlockedPushListSList @645 + RtlInterlockedPushListSListEx @646 + RtlIpv4AddressToStringA @647 + RtlIpv4AddressToStringExA @648 + RtlIpv4AddressToStringExW @649 + RtlIpv4AddressToStringW @650 + RtlIpv4StringToAddressA @651 + RtlIpv4StringToAddressExA @652 + RtlIpv4StringToAddressExW @653 + RtlIpv4StringToAddressW @654 + RtlIpv6AddressToStringA @655 + RtlIpv6AddressToStringExA @656 + RtlIpv6AddressToStringExW @657 + RtlIpv6AddressToStringW @658 + RtlIpv6StringToAddressA @659 + RtlIpv6StringToAddressExA @660 + RtlIpv6StringToAddressExW @661 + RtlIpv6StringToAddressW @662 + RtlIsActivationContextActive @663 + RtlIsCriticalSectionLocked @664 + RtlIsCriticalSectionLockedByThread @665 + RtlIsCurrentProcess @666 + RtlIsCurrentThread @667 + RtlIsDosDeviceName_U @668 + RtlIsEcCode @669 + RtlIsGenericTableEmpty @670 PRIVATE + RtlIsNameLegalDOS8Dot3 @671 + RtlIsNormalizedString @672 + RtlIsProcessorFeaturePresent @673 + RtlIsTextUnicode @674 + RtlIsValidHandle @675 + RtlIsValidIndexHandle @676 + RtlIsValidLocaleName @677 + RtlLargeIntegerToChar @678 + RtlLcidToLocaleName @679 + RtlLeaveCriticalSection @680 + RtlLengthRequiredSid @681 + RtlLengthSecurityDescriptor @682 + RtlLengthSid @683 + RtlLocalTimeToSystemTime @684 + RtlLocaleNameToLcid @685 + RtlLocateExtendedFeature @686 + RtlLocateExtendedFeature2 @687 + RtlLocateLegacyContext @688 + RtlLockHeap @689 + RtlLookupAtomInAtomTable @690 + RtlLookupElementGenericTable @691 + RtlLookupFunctionEntry @692 + RtlMakeSelfRelativeSD @693 + RtlMapGenericMask @694 + RtlMoveMemory @695 + RtlMultiByteToUnicodeN @696 + RtlMultiByteToUnicodeSize @697 + RtlNewInstanceSecurityObject @698 PRIVATE + RtlNewSecurityGrantedAccess @699 PRIVATE + RtlNewSecurityObject @700 + RtlNewSecurityObjectEx @701 + RtlNewSecurityObjectWithMultipleInheritance @702 + RtlNormalizeProcessParams @703 + RtlNormalizeString @704 + RtlNtStatusToDosError @705 + RtlNtStatusToDosErrorNoTeb @706 + RtlNumberGenericTableElements @707 + RtlNumberOfClearBits @708 + RtlNumberOfSetBits @709 + RtlOemStringToUnicodeSize @710 + RtlOemStringToUnicodeString @711 + RtlOemToUnicodeN @712 + RtlOpenCurrentUser @713 + RtlPcToFileHeader @714 + RtlPinAtomInAtomTable @715 + RtlPopFrame @716 + RtlPrefixString @717 + RtlPrefixUnicodeString @718 + RtlProcessFlsData @719 + RtlPropertySetNameToGuid @720 PRIVATE + RtlProtectHeap @721 PRIVATE + RtlPushFrame @722 + RtlQueryActivationContextApplicationSettings @723 + RtlQueryAtomInAtomTable @724 + RtlQueryDepthSList @725 + RtlQueryDynamicTimeZoneInformation @726 + RtlQueryEnvironmentVariable_U @727 + RtlQueryEnvironmentVariable @728 + RtlQueryHeapInformation @729 + RtlQueryInformationAcl @730 + RtlQueryInformationActivationContext @731 + RtlQueryInformationActiveActivationContext @732 PRIVATE + RtlQueryInterfaceMemoryStream @733 PRIVATE + RtlQueryPackageIdentity @734 + RtlQueryPerformanceCounter @735 + RtlQueryPerformanceFrequency @736 + RtlQueryProcessBackTraceInformation @737 PRIVATE + RtlQueryProcessDebugInformation @738 + RtlQueryProcessHeapInformation @739 PRIVATE + RtlQueryProcessLockInformation @740 PRIVATE + RtlQueryProcessPlaceholderCompatibilityMode @741 + RtlQueryProperties @742 PRIVATE + RtlQueryPropertyNames @743 PRIVATE + RtlQueryPropertySet @744 PRIVATE + RtlQueryRegistryValues @745 + RtlQueryRegistryValuesEx=RtlQueryRegistryValues @746 + RtlQuerySecurityObject @747 PRIVATE + RtlQueryTagHeap @748 PRIVATE + RtlQueryTimeZoneInformation @749 + RtlQueryUnbiasedInterruptTime @750 + RtlQueueApcWow64Thread @751 PRIVATE + RtlQueueWorkItem @752 + RtlRaiseException @753 + RtlRaiseStatus @754 + RtlRandom @755 + RtlRandomEx @756 + RtlReAllocateHeap @757 + RtlReadMemoryStream @758 PRIVATE + RtlReadOutOfProcessMemoryStream @759 PRIVATE + RtlRealPredecessor @760 PRIVATE + RtlRealSuccessor @761 PRIVATE + RtlRegisterSecureMemoryCacheCallback @762 PRIVATE + RtlRegisterWait @763 + RtlReleaseActivationContext @764 + RtlReleaseMemoryStream @765 PRIVATE + RtlReleasePath @766 + RtlReleasePebLock @767 + RtlReleaseRelativeName @768 + RtlReleaseResource @769 + RtlReleaseSRWLockExclusive @770 + RtlReleaseSRWLockShared @771 + RtlRemoteCall @772 PRIVATE + RtlRemoveVectoredContinueHandler @773 + RtlRemoveVectoredExceptionHandler @774 + RtlResetRtlTranslations @775 + RtlRestoreContext @776 + RtlRestoreLastWin32Error=RtlSetLastWin32Error @777 + RtlRevertMemoryStream @778 PRIVATE + RtlRunDecodeUnicodeString @779 PRIVATE + RtlRunEncodeUnicodeString @780 PRIVATE + RtlRunOnceBeginInitialize @781 + RtlRunOnceComplete @782 + RtlRunOnceExecuteOnce @783 + RtlRunOnceInitialize @784 + RtlSecondsSince1970ToTime @785 + RtlSecondsSince1980ToTime @786 + RtlSelfRelativeToAbsoluteSD @787 + RtlSetAllBits @788 + RtlSetBits @789 + RtlSetControlSecurityDescriptor @790 + RtlSetCriticalSectionSpinCount @791 + RtlSetCurrentDirectory_U @792 + RtlSetCurrentEnvironment @793 + RtlSetCurrentTransaction @794 + RtlSetDaclSecurityDescriptor @795 + RtlSetEnvironmentVariable @796 + RtlSetExtendedFeaturesMask @797 + RtlSetGroupSecurityDescriptor @798 + RtlSetHeapInformation @799 + RtlSetInformationAcl @800 PRIVATE + RtlSetIoCompletionCallback @801 + RtlSetLastWin32Error @802 + RtlSetLastWin32ErrorAndNtStatusFromNtStatus @803 + RtlSetOwnerSecurityDescriptor @804 + RtlSetProcessPreferredUILanguages @805 + RtlSetProperties @806 PRIVATE + RtlSetPropertyClassId @807 PRIVATE + RtlSetPropertyNames @808 PRIVATE + RtlSetPropertySetClassId @809 PRIVATE + RtlSetSaclSecurityDescriptor @810 + RtlSetSearchPathMode @811 + RtlSetSecurityObject @812 PRIVATE + RtlSetThreadErrorMode @813 + RtlSetThreadPreferredUILanguages @814 + RtlSetTimeZoneInformation @815 + RtlSetUnhandledExceptionFilter @816 + RtlSetUnicodeCallouts @817 PRIVATE + RtlSetUserFlagsHeap @818 + RtlSetUserValueHeap @819 + RtlSizeHeap @820 + RtlSleepConditionVariableCS @821 + RtlSleepConditionVariableSRW @822 + RtlSplay @823 PRIVATE + RtlStartRXact @824 PRIVATE + RtlStringFromGUID @825 + RtlSubAuthorityCountSid @826 + RtlSubAuthoritySid @827 + RtlSubtreePredecessor @828 PRIVATE + RtlSubtreeSuccessor @829 PRIVATE + RtlSystemTimeToLocalTime @830 + RtlTimeFieldsToTime @831 + RtlTimeToElapsedTimeFields @832 + RtlTimeToSecondsSince1970 @833 + RtlTimeToSecondsSince1980 @834 + RtlTimeToTimeFields @835 + RtlTryAcquireSRWLockExclusive @836 + RtlTryAcquireSRWLockShared @837 + RtlTryEnterCriticalSection @838 + RtlUTF8ToUnicodeN @839 + RtlUnicodeStringToAnsiSize @840 + RtlUnicodeStringToAnsiString @841 + RtlUnicodeStringToCountedOemString @842 PRIVATE + RtlUnicodeStringToInteger @843 + RtlUnicodeStringToOemSize @844 + RtlUnicodeStringToOemString @845 + RtlUnicodeToCustomCPN @846 + RtlUnicodeToMultiByteN @847 + RtlUnicodeToMultiByteSize @848 + RtlUnicodeToOemN @849 + RtlUnicodeToUTF8N @850 + RtlUniform @851 + RtlUnlockHeap @852 + RtlUnwind @853 + RtlUnwindEx @854 + RtlUpcaseUnicodeChar @855 + RtlUpcaseUnicodeString @856 + RtlUpcaseUnicodeStringToAnsiString @857 + RtlUpcaseUnicodeStringToCountedOemString @858 + RtlUpcaseUnicodeStringToOemString @859 + RtlUpcaseUnicodeToCustomCPN @860 + RtlUpcaseUnicodeToMultiByteN @861 + RtlUpcaseUnicodeToOemN @862 + RtlUpdateTimer @863 + RtlUpperChar @864 + RtlUpperString @865 + RtlUsageHeap @866 PRIVATE + RtlUserThreadStart @867 + RtlValidAcl @868 + RtlValidRelativeSecurityDescriptor @869 + RtlValidSecurityDescriptor @870 + RtlValidSid @871 + RtlValidateHeap @872 + RtlValidateProcessHeaps @873 PRIVATE + RtlVerifyVersionInfo @874 + RtlVirtualUnwind @875 + RtlWaitOnAddress @876 + RtlWakeAddressAll @877 + RtlWakeAddressSingle @878 + RtlWakeAllConditionVariable @879 + RtlWakeConditionVariable @880 + RtlWalkFrameChain @881 PRIVATE + RtlWalkHeap @882 + RtlWow64EnableFsRedirection @883 + RtlWow64EnableFsRedirectionEx @884 + RtlWow64GetCpuAreaInfo @885 + RtlWow64GetCurrentCpuArea @886 + RtlWow64GetCurrentMachine @887 + RtlWow64GetProcessMachines @888 + RtlWow64GetSharedInfoProcess @889 + RtlWow64GetThreadContext @890 + RtlWow64GetThreadSelectorEntry @891 + RtlWow64IsWowGuestMachineSupported @892 + RtlWow64SetThreadContext @893 + RtlWow64SuspendThread @894 + RtlWriteMemoryStream @895 PRIVATE + RtlWriteRegistryValue @896 + RtlZeroHeap @897 PRIVATE + RtlZeroMemory @898 + RtlZombifyActivationContext @899 + RtlpNtCreateKey @900 + RtlpNtEnumerateSubKey @901 + RtlpNtMakeTemporaryKey @902 + RtlpNtOpenKey @903 + RtlpNtQueryValueKey @904 + RtlpNtSetValueKey @905 + RtlpUnWaitCriticalSection @906 + RtlpWaitForCriticalSection @907 + RtlxAnsiStringToUnicodeSize=RtlAnsiStringToUnicodeSize @908 + RtlxOemStringToUnicodeSize=RtlOemStringToUnicodeSize @909 + RtlxUnicodeStringToAnsiSize=RtlUnicodeStringToAnsiSize @910 + RtlxUnicodeStringToOemSize=RtlUnicodeStringToOemSize @911 + TpAllocCleanupGroup @912 + TpAllocIoCompletion @913 + TpAllocPool @914 + TpAllocTimer @915 + TpAllocWait @916 + TpAllocWork @917 + TpCallbackLeaveCriticalSectionOnCompletion @918 + TpCallbackMayRunLong @919 + TpCallbackReleaseMutexOnCompletion @920 + TpCallbackReleaseSemaphoreOnCompletion @921 + TpCallbackSetEventOnCompletion @922 + TpCallbackUnloadDllOnCompletion @923 + TpCancelAsyncIoOperation @924 + TpDisassociateCallback @925 + TpIsTimerSet @926 + TpPostWork @927 + TpQueryPoolStackInformation @928 + TpReleaseCleanupGroup @929 + TpReleaseCleanupGroupMembers @930 + TpReleaseIoCompletion @931 + TpReleasePool @932 + TpReleaseTimer @933 + TpReleaseWait @934 + TpReleaseWork @935 + TpSetPoolMaxThreads @936 + TpSetPoolMinThreads @937 + TpSetPoolStackInformation @938 + TpSetTimer @939 + TpSetWait @940 + TpSimpleTryPost @941 + TpStartAsyncIoOperation @942 + TpWaitForIoCompletion @943 + TpWaitForTimer @944 + TpWaitForWait @945 + TpWaitForWork @946 + VerSetConditionMask @947 + WinSqmEndSession @948 + WinSqmIncrementDWORD @949 + WinSqmIsOptedIn @950 + WinSqmSetDWORD @951 + WinSqmStartSession @952 + ZwAcceptConnectPort=NtAcceptConnectPort @953 PRIVATE + ZwAccessCheck=NtAccessCheck @954 PRIVATE + ZwAccessCheckAndAuditAlarm=NtAccessCheckAndAuditAlarm @955 PRIVATE + ZwAddAtom=NtAddAtom @956 PRIVATE + ZwAdjustGroupsToken=NtAdjustGroupsToken @957 PRIVATE + ZwAdjustPrivilegesToken=NtAdjustPrivilegesToken @958 PRIVATE + ZwAlertResumeThread=NtAlertResumeThread @959 PRIVATE + ZwAlertThread=NtAlertThread @960 PRIVATE + ZwAlertThreadByThreadId=NtAlertThreadByThreadId @961 PRIVATE + ZwAllocateLocallyUniqueId=NtAllocateLocallyUniqueId @962 PRIVATE + ZwAllocateUuids=NtAllocateUuids @963 PRIVATE + ZwAllocateVirtualMemory=NtAllocateVirtualMemory @964 PRIVATE + ZwAllocateVirtualMemoryEx=NtAllocateVirtualMemoryEx @965 PRIVATE + ZwAreMappedFilesTheSame=NtAreMappedFilesTheSame @966 PRIVATE + ZwAssignProcessToJobObject=NtAssignProcessToJobObject @967 PRIVATE + ZwCancelIoFile=NtCancelIoFile @968 PRIVATE + ZwCancelIoFileEx=NtCancelIoFileEx @969 PRIVATE + ZwCancelSynchronousIoFile=NtCancelSynchronousIoFile @970 PRIVATE + ZwCancelTimer=NtCancelTimer @971 PRIVATE + ZwClearEvent=NtClearEvent @972 PRIVATE + ZwClose=NtClose @973 PRIVATE + ZwCompareObjects=NtCompareObjects @974 PRIVATE + ZwCompleteConnectPort=NtCompleteConnectPort @975 PRIVATE + ZwConnectPort=NtConnectPort @976 PRIVATE + ZwContinue=NtContinue @977 PRIVATE + ZwCreateDirectoryObject=NtCreateDirectoryObject @978 PRIVATE + ZwCreateEvent=NtCreateEvent @979 PRIVATE + ZwCreateFile=NtCreateFile @980 PRIVATE + ZwCreateIoCompletion=NtCreateIoCompletion @981 PRIVATE + ZwCreateJobObject=NtCreateJobObject @982 PRIVATE + ZwCreateKey=NtCreateKey @983 PRIVATE + ZwCreateKeyTransacted=NtCreateKeyTransacted @984 PRIVATE + ZwCreateKeyedEvent=NtCreateKeyedEvent @985 PRIVATE + ZwCreateLowBoxToken=NtCreateLowBoxToken @986 PRIVATE + ZwCreateMailslotFile=NtCreateMailslotFile @987 PRIVATE + ZwCreateMutant=NtCreateMutant @988 PRIVATE + ZwCreateNamedPipeFile=NtCreateNamedPipeFile @989 PRIVATE + ZwCreatePagingFile=NtCreatePagingFile @990 PRIVATE + ZwCreatePort=NtCreatePort @991 PRIVATE + ZwCreateSection=NtCreateSection @992 PRIVATE + ZwCreateSemaphore=NtCreateSemaphore @993 PRIVATE + ZwCreateSymbolicLinkObject=NtCreateSymbolicLinkObject @994 PRIVATE + ZwCreateThread=NtCreateThread @995 PRIVATE + ZwCreateThreadEx=NtCreateThreadEx @996 PRIVATE + ZwCreateTimer=NtCreateTimer @997 PRIVATE + ZwCreateUserProcess=NtCreateUserProcess @998 PRIVATE + ZwDebugActiveProcess=NtDebugActiveProcess @999 PRIVATE + ZwDebugContinue=NtDebugContinue @1000 PRIVATE + ZwDelayExecution=NtDelayExecution @1001 PRIVATE + ZwDeleteAtom=NtDeleteAtom @1002 PRIVATE + ZwDeleteFile=NtDeleteFile @1003 PRIVATE + ZwDeleteKey=NtDeleteKey @1004 PRIVATE + ZwDeleteValueKey=NtDeleteValueKey @1005 PRIVATE + ZwDeviceIoControlFile=NtDeviceIoControlFile @1006 PRIVATE + ZwDisplayString=NtDisplayString @1007 PRIVATE + ZwDuplicateObject=NtDuplicateObject @1008 PRIVATE + ZwDuplicateToken=NtDuplicateToken @1009 PRIVATE + ZwEnumerateKey=NtEnumerateKey @1010 PRIVATE + ZwEnumerateValueKey=NtEnumerateValueKey @1011 PRIVATE + ZwFilterToken=NtFilterToken @1012 PRIVATE + ZwFindAtom=NtFindAtom @1013 PRIVATE + ZwFlushBuffersFile=NtFlushBuffersFile @1014 PRIVATE + ZwFlushInstructionCache=NtFlushInstructionCache @1015 PRIVATE + ZwFlushKey=NtFlushKey @1016 PRIVATE + ZwFlushProcessWriteBuffers=NtFlushProcessWriteBuffers @1017 PRIVATE + ZwFlushVirtualMemory=NtFlushVirtualMemory @1018 PRIVATE + ZwFreeVirtualMemory=NtFreeVirtualMemory @1019 PRIVATE + ZwFsControlFile=NtFsControlFile @1020 PRIVATE + ZwGetContextThread=NtGetContextThread @1021 PRIVATE + ZwGetCurrentProcessorNumber=NtGetCurrentProcessorNumber @1022 PRIVATE + ZwGetNlsSectionPtr=NtGetNlsSectionPtr @1023 PRIVATE + ZwGetTickCount=NtGetTickCount @1024 PRIVATE + ZwGetWriteWatch=NtGetWriteWatch @1025 PRIVATE + ZwImpersonateAnonymousToken=NtImpersonateAnonymousToken @1026 PRIVATE + ZwInitializeNlsFiles=NtInitializeNlsFiles @1027 PRIVATE + ZwInitiatePowerAction=NtInitiatePowerAction @1028 PRIVATE + ZwIsProcessInJob=NtIsProcessInJob @1029 PRIVATE + ZwListenPort=NtListenPort @1030 PRIVATE + ZwLoadDriver=NtLoadDriver @1031 PRIVATE + ZwLoadKey2=NtLoadKey2 @1032 PRIVATE + ZwLoadKey=NtLoadKey @1033 PRIVATE + ZwLockFile=NtLockFile @1034 PRIVATE + ZwLockVirtualMemory=NtLockVirtualMemory @1035 PRIVATE + ZwMakeTemporaryObject=NtMakeTemporaryObject @1036 PRIVATE + ZwMapViewOfSection=NtMapViewOfSection @1037 PRIVATE + ZwMapViewOfSectionEx=NtMapViewOfSectionEx @1038 PRIVATE + ZwNotifyChangeDirectoryFile=NtNotifyChangeDirectoryFile @1039 PRIVATE + ZwNotifyChangeKey=NtNotifyChangeKey @1040 PRIVATE + ZwNotifyChangeMultipleKeys=NtNotifyChangeMultipleKeys @1041 PRIVATE + ZwOpenDirectoryObject=NtOpenDirectoryObject @1042 PRIVATE + ZwOpenEvent=NtOpenEvent @1043 PRIVATE + ZwOpenFile=NtOpenFile @1044 PRIVATE + ZwOpenIoCompletion=NtOpenIoCompletion @1045 PRIVATE + ZwOpenJobObject=NtOpenJobObject @1046 PRIVATE + ZwOpenKey=NtOpenKey @1047 PRIVATE + ZwOpenKeyEx=NtOpenKeyEx @1048 PRIVATE + ZwOpenKeyTransacted=NtOpenKeyTransacted @1049 PRIVATE + ZwOpenKeyTransactedEx=NtOpenKeyTransactedEx @1050 PRIVATE + ZwOpenKeyedEvent=NtOpenKeyedEvent @1051 PRIVATE + ZwOpenMutant=NtOpenMutant @1052 PRIVATE + ZwOpenProcess=NtOpenProcess @1053 PRIVATE + ZwOpenProcessToken=NtOpenProcessToken @1054 PRIVATE + ZwOpenProcessTokenEx=NtOpenProcessTokenEx @1055 PRIVATE + ZwOpenSection=NtOpenSection @1056 PRIVATE + ZwOpenSemaphore=NtOpenSemaphore @1057 PRIVATE + ZwOpenSymbolicLinkObject=NtOpenSymbolicLinkObject @1058 PRIVATE + ZwOpenThread=NtOpenThread @1059 PRIVATE + ZwOpenThreadToken=NtOpenThreadToken @1060 PRIVATE + ZwOpenThreadTokenEx=NtOpenThreadTokenEx @1061 PRIVATE + ZwOpenTimer=NtOpenTimer @1062 PRIVATE + ZwPowerInformation=NtPowerInformation @1063 PRIVATE + ZwPrivilegeCheck=NtPrivilegeCheck @1064 PRIVATE + ZwProtectVirtualMemory=NtProtectVirtualMemory @1065 PRIVATE + ZwPulseEvent=NtPulseEvent @1066 PRIVATE + ZwQueryAttributesFile=NtQueryAttributesFile @1067 PRIVATE + ZwQueryDefaultLocale=NtQueryDefaultLocale @1068 PRIVATE + ZwQueryDefaultUILanguage=NtQueryDefaultUILanguage @1069 PRIVATE + ZwQueryDirectoryFile=NtQueryDirectoryFile @1070 PRIVATE + ZwQueryDirectoryObject=NtQueryDirectoryObject @1071 PRIVATE + ZwQueryEaFile=NtQueryEaFile @1072 PRIVATE + ZwQueryEvent=NtQueryEvent @1073 PRIVATE + ZwQueryFullAttributesFile=NtQueryFullAttributesFile @1074 PRIVATE + ZwQueryInformationAtom=NtQueryInformationAtom @1075 PRIVATE + ZwQueryInformationFile=NtQueryInformationFile @1076 PRIVATE + ZwQueryInformationJobObject=NtQueryInformationJobObject @1077 PRIVATE + ZwQueryInformationProcess=NtQueryInformationProcess @1078 PRIVATE + ZwQueryInformationThread=NtQueryInformationThread @1079 PRIVATE + ZwQueryInformationToken=NtQueryInformationToken @1080 PRIVATE + ZwQueryInstallUILanguage=NtQueryInstallUILanguage @1081 PRIVATE + ZwQueryIoCompletion=NtQueryIoCompletion @1082 PRIVATE + ZwQueryKey=NtQueryKey @1083 PRIVATE + ZwQueryLicenseValue=NtQueryLicenseValue @1084 PRIVATE + ZwQueryMultipleValueKey=NtQueryMultipleValueKey @1085 PRIVATE + ZwQueryMutant=NtQueryMutant @1086 PRIVATE + ZwQueryObject=NtQueryObject @1087 PRIVATE + ZwQueryPerformanceCounter=NtQueryPerformanceCounter @1088 PRIVATE + ZwQuerySection=NtQuerySection @1089 PRIVATE + ZwQuerySecurityObject=NtQuerySecurityObject @1090 PRIVATE + ZwQuerySemaphore=NtQuerySemaphore @1091 PRIVATE + ZwQuerySymbolicLinkObject=NtQuerySymbolicLinkObject @1092 PRIVATE + ZwQuerySystemEnvironmentValue=NtQuerySystemEnvironmentValue @1093 PRIVATE + ZwQuerySystemEnvironmentValueEx=NtQuerySystemEnvironmentValueEx @1094 PRIVATE + ZwQuerySystemInformation=NtQuerySystemInformation @1095 PRIVATE + ZwQuerySystemInformationEx=NtQuerySystemInformationEx @1096 PRIVATE + ZwQuerySystemTime=NtQuerySystemTime @1097 PRIVATE + ZwQueryTimer=NtQueryTimer @1098 PRIVATE + ZwQueryTimerResolution=NtQueryTimerResolution @1099 PRIVATE + ZwQueryValueKey=NtQueryValueKey @1100 PRIVATE + ZwQueryVirtualMemory=NtQueryVirtualMemory @1101 PRIVATE + ZwQueryVolumeInformationFile=NtQueryVolumeInformationFile @1102 PRIVATE + ZwQueueApcThread=NtQueueApcThread @1103 PRIVATE + ZwRaiseException=NtRaiseException @1104 PRIVATE + ZwRaiseHardError=NtRaiseHardError @1105 PRIVATE + ZwReadFile=NtReadFile @1106 PRIVATE + ZwReadFileScatter=NtReadFileScatter @1107 PRIVATE + ZwReadVirtualMemory=NtReadVirtualMemory @1108 PRIVATE + ZwRegisterThreadTerminatePort=NtRegisterThreadTerminatePort @1109 PRIVATE + ZwReleaseKeyedEvent=NtReleaseKeyedEvent @1110 PRIVATE + ZwReleaseMutant=NtReleaseMutant @1111 PRIVATE + ZwReleaseSemaphore=NtReleaseSemaphore @1112 PRIVATE + ZwRemoveIoCompletion=NtRemoveIoCompletion @1113 PRIVATE + ZwRemoveIoCompletionEx=NtRemoveIoCompletionEx @1114 PRIVATE + ZwRemoveProcessDebug=NtRemoveProcessDebug @1115 PRIVATE + ZwRenameKey=NtRenameKey @1116 PRIVATE + ZwReplaceKey=NtReplaceKey @1117 PRIVATE + ZwReplyWaitReceivePort=NtReplyWaitReceivePort @1118 PRIVATE + ZwRequestWaitReplyPort=NtRequestWaitReplyPort @1119 PRIVATE + ZwResetEvent=NtResetEvent @1120 PRIVATE + ZwResetWriteWatch=NtResetWriteWatch @1121 PRIVATE + ZwRestoreKey=NtRestoreKey @1122 PRIVATE + ZwResumeProcess=NtResumeProcess @1123 PRIVATE + ZwResumeThread=NtResumeThread @1124 PRIVATE + ZwSaveKey=NtSaveKey @1125 PRIVATE + ZwSecureConnectPort=NtSecureConnectPort @1126 PRIVATE + ZwSetContextThread=NtSetContextThread @1127 PRIVATE + ZwSetDebugFilterState=NtSetDebugFilterState @1128 PRIVATE + ZwSetDefaultLocale=NtSetDefaultLocale @1129 PRIVATE + ZwSetDefaultUILanguage=NtSetDefaultUILanguage @1130 PRIVATE + ZwSetEaFile=NtSetEaFile @1131 PRIVATE + ZwSetEvent=NtSetEvent @1132 PRIVATE + ZwSetInformationDebugObject=NtSetInformationDebugObject @1133 PRIVATE + ZwSetInformationFile=NtSetInformationFile @1134 PRIVATE + ZwSetInformationJobObject=NtSetInformationJobObject @1135 PRIVATE + ZwSetInformationKey=NtSetInformationKey @1136 PRIVATE + ZwSetInformationObject=NtSetInformationObject @1137 PRIVATE + ZwSetInformationProcess=NtSetInformationProcess @1138 PRIVATE + ZwSetInformationThread=NtSetInformationThread @1139 PRIVATE + ZwSetInformationToken=NtSetInformationToken @1140 PRIVATE + ZwSetInformationVirtualMemory=NtSetInformationVirtualMemory @1141 PRIVATE + ZwSetIntervalProfile=NtSetIntervalProfile @1142 PRIVATE + ZwSetIoCompletion=NtSetIoCompletion @1143 PRIVATE + ZwSetLdtEntries=NtSetLdtEntries @1144 PRIVATE + ZwSetSecurityObject=NtSetSecurityObject @1145 PRIVATE + ZwSetSystemInformation=NtSetSystemInformation @1146 PRIVATE + ZwSetSystemTime=NtSetSystemTime @1147 PRIVATE + ZwSetThreadExecutionState=NtSetThreadExecutionState @1148 PRIVATE + ZwSetTimer=NtSetTimer @1149 PRIVATE + ZwSetTimerResolution=NtSetTimerResolution @1150 PRIVATE + ZwSetValueKey=NtSetValueKey @1151 PRIVATE + ZwSetVolumeInformationFile=NtSetVolumeInformationFile @1152 PRIVATE + ZwShutdownSystem=NtShutdownSystem @1153 PRIVATE + ZwSignalAndWaitForSingleObject=NtSignalAndWaitForSingleObject @1154 PRIVATE + ZwSuspendProcess=NtSuspendProcess @1155 PRIVATE + ZwSuspendThread=NtSuspendThread @1156 PRIVATE + ZwSystemDebugControl=NtSystemDebugControl @1157 PRIVATE + ZwTerminateJobObject=NtTerminateJobObject @1158 PRIVATE + ZwTerminateProcess=NtTerminateProcess @1159 PRIVATE + ZwTerminateThread=NtTerminateThread @1160 PRIVATE + ZwTestAlert=NtTestAlert @1161 PRIVATE + ZwTraceControl=NtTraceControl @1162 PRIVATE + ZwUnloadDriver=NtUnloadDriver @1163 PRIVATE + ZwUnloadKey=NtUnloadKey @1164 PRIVATE + ZwUnlockFile=NtUnlockFile @1165 PRIVATE + ZwUnlockVirtualMemory=NtUnlockVirtualMemory @1166 PRIVATE + ZwUnmapViewOfSection=NtUnmapViewOfSection @1167 PRIVATE + ZwUnmapViewOfSectionEx=NtUnmapViewOfSectionEx @1168 PRIVATE + ZwWaitForAlertByThreadId=NtWaitForAlertByThreadId @1169 PRIVATE + ZwWaitForDebugEvent=NtWaitForDebugEvent @1170 PRIVATE + ZwWaitForKeyedEvent=NtWaitForKeyedEvent @1171 PRIVATE + ZwWaitForMultipleObjects=NtWaitForMultipleObjects @1172 PRIVATE + ZwWaitForSingleObject=NtWaitForSingleObject @1173 PRIVATE + ZwWriteFile=NtWriteFile @1174 PRIVATE + ZwWriteFileGather=NtWriteFileGather @1175 PRIVATE + ZwWriteVirtualMemory=NtWriteVirtualMemory @1176 PRIVATE + ZwYieldExecution=NtYieldExecution @1177 PRIVATE + __C_specific_handler @1178 + __chkstk @1179 + __isascii @1180 + __iscsym @1181 + __iscsymf @1182 + __toascii @1183 + _atoi64 @1184 + _errno @1185 + _fltused @1186 PRIVATE + _i64toa @1187 + _i64toa_s @1188 + _i64tow @1189 + _i64tow_s @1190 + _itoa @1191 + _itoa_s @1192 + _itow @1193 + _itow_s @1194 + _lfind @1195 + _local_unwind @1196 + _ltoa @1197 + _ltoa_s @1198 + _ltow @1199 + _ltow_s @1200 + _makepath_s @1201 + _memccpy @1202 + _memicmp @1203 + _snprintf=NTDLL__snprintf @1204 + _snprintf_s @1205 + _snwprintf @1206 + _snwprintf_s @1207 + _splitpath @1208 + _splitpath_s @1209 + _strcmpi=_stricmp @1210 + _stricmp @1211 + _strlwr @1212 + _strlwr_s @1213 + _strnicmp @1214 + _strupr @1215 + _strupr_s @1216 + _swprintf=NTDLL_swprintf @1217 + _tolower @1218 + _toupper @1219 + _ui64toa @1220 + _ui64toa_s @1221 + _ui64tow @1222 + _ui64tow_s @1223 + _ultoa @1224 + _ultoa_s @1225 + _ultow @1226 + _ultow_s @1227 + _vscprintf @1228 + _vscwprintf @1229 + _vsnprintf @1230 + _vsnprintf_s @1231 + _vsnwprintf @1232 + _vsnwprintf_s @1233 + _vswprintf @1234 + _wcsicmp @1235 + _wcslwr @1236 + _wcslwr_s @1237 + _wcsnicmp @1238 + _wcstoi64 @1239 + _wcstoui64 @1240 + _wcsupr @1241 + _wcsupr_s @1242 + _wmakepath_s @1243 + _wsplitpath_s @1244 + _wtoi @1245 + _wtoi64 @1246 + _wtol @1247 + abs @1248 + atan @1249 + atan2 @1250 + atoi @1251 + atol @1252 + bsearch @1253 + bsearch_s @1254 + ceil @1255 + cos @1256 + fabs @1257 + floor @1258 + isalnum @1259 + isalpha @1260 + iscntrl @1261 + isdigit @1262 + isgraph @1263 + islower @1264 + isprint @1265 + ispunct @1266 + isspace @1267 + isupper @1268 + iswalnum @1269 + iswalpha @1270 + iswascii @1271 + iswctype @1272 + iswdigit @1273 + iswgraph @1274 + iswlower @1275 + iswprint @1276 + iswspace @1277 + iswxdigit @1278 + isxdigit @1279 + labs=abs @1280 + log @1281 + mbstowcs @1282 + memchr @1283 + memcmp @1284 + memcpy @1285 + memcpy_s @1286 + memmove @1287 + memmove_s @1288 + memset @1289 + pow @1290 + qsort @1291 + qsort_s @1292 + sin @1293 + sprintf=NTDLL_sprintf @1294 + sprintf_s @1295 + sqrt @1296 + sscanf @1297 + strcat @1298 + strcat_s @1299 + strchr @1300 + strcmp @1301 + strcpy @1302 + strcpy_s @1303 + strcspn @1304 + strlen @1305 + strncat @1306 + strncat_s @1307 + strncmp @1308 + strncpy @1309 + strncpy_s @1310 + strnlen @1311 + strpbrk @1312 + strrchr @1313 + strspn @1314 + strstr @1315 + strtok_s @1316 + strtol @1317 + strtoul @1318 + swprintf=NTDLL_swprintf @1319 + swprintf_s @1320 + tan @1321 + tolower @1322 + toupper @1323 + towlower @1324 + towupper @1325 + vDbgPrintEx @1326 + vDbgPrintExWithPrefix @1327 + vsprintf @1328 + vsprintf_s @1329 + vswprintf_s @1330 + wcscat @1331 + wcscat_s @1332 + wcschr @1333 + wcscmp @1334 + wcscpy @1335 + wcscpy_s @1336 + wcscspn @1337 + wcslen @1338 + wcsncat @1339 + wcsncat_s @1340 + wcsncmp @1341 + wcsncpy @1342 + wcsncpy_s @1343 + wcsnlen @1344 + wcspbrk @1345 + wcsrchr @1346 + wcsspn @1347 + wcsstr @1348 + wcstok @1349 + wcstok_s @1350 + wcstol @1351 + wcstombs @1352 + wcstoul @1353 + wine_server_call @1354 + wine_server_fd_to_handle @1355 + wine_server_handle_to_fd @1356 + __wine_unix_call @1357 + __wine_unix_spawnvp @1358 + __wine_ctrl_routine @1359 + __wine_syscall_dispatcher @1360 DATA PRIVATE + __wine_unix_call_dispatcher @1361 DATA PRIVATE + __wine_unixlib_handle @1362 DATA PRIVATE + __wine_dbg_write @1363 + __wine_dbg_get_channel_flags @1364 + __wine_dbg_header @1365 + __wine_dbg_output @1366 + __wine_dbg_strdup @1367 + wine_get_version @1368 + wine_get_build_id @1369 + wine_get_host_version @1370 + wine_nt_to_unix_file_name @1371 + wine_unix_to_nt_file_name @1372 diff --git a/Source/Windows/Defs/wow64.def b/Source/Windows/Defs/wow64.def new file mode 100644 index 000000000..e5291402c --- /dev/null +++ b/Source/Windows/Defs/wow64.def @@ -0,0 +1,33 @@ +; File generated automatically from wine/dlls/wow64/wow64.spec; do not edit! +; To generate: winebuild --def -E wine/dlls/wow64/wow64.spec > wow64.def + +LIBRARY wow64.dll + +EXPORTS + Wow64AllocThreadHeap @1 PRIVATE + Wow64AllocateHeap @2 PRIVATE + Wow64AllocateTemp @3 + Wow64ApcRoutine @4 + Wow64CheckIfNXEnabled @5 PRIVATE + Wow64EmulateAtlThunk @6 PRIVATE + Wow64FreeHeap @7 PRIVATE + Wow64FreeThreadHeap @8 PRIVATE + Wow64GetWow64ImageOption @9 PRIVATE + Wow64IsControlFlowGuardEnforced @10 PRIVATE + Wow64IsStackExtentsCheckEnforced @11 PRIVATE + Wow64KiUserCallbackDispatcher @12 + Wow64LdrpInitialize @13 + Wow64LogPrint @14 PRIVATE + Wow64NotifyUnsimulateComplete @15 PRIVATE + 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 From 2add8a7751cfc0c9aef6d329678c4fe927f9ba48 Mon Sep 17 00:00:00 2001 From: Billy Laws Date: Thu, 10 Aug 2023 11:29:02 -0700 Subject: [PATCH 05/13] Windows: Introduce a barebones FEXCore-based WOW64 BT module This allows for running x86 applications under wine without having to run all of wine under FEX. The JIT is invoked when running application code and then left when handling NT syscalls or unix calls to e.g. the Vulkan driver. --- Source/Windows/CMakeLists.txt | 4 + Source/Windows/WOW64/BTInterface.h | 25 ++ Source/Windows/WOW64/CMakeLists.txt | 25 ++ Source/Windows/WOW64/Module.cpp | 389 +++++++++++++++++++++++++++ Source/Windows/WOW64/libwow64fex.def | 20 ++ 5 files changed, 463 insertions(+) create mode 100644 Source/Windows/WOW64/BTInterface.h create mode 100644 Source/Windows/WOW64/CMakeLists.txt create mode 100644 Source/Windows/WOW64/Module.cpp create mode 100644 Source/Windows/WOW64/libwow64fex.def diff --git a/Source/Windows/CMakeLists.txt b/Source/Windows/CMakeLists.txt index a5cfd7eff..3e2a3f205 100644 --- a/Source/Windows/CMakeLists.txt +++ b/Source/Windows/CMakeLists.txt @@ -13,3 +13,7 @@ endfunction() build_implib(ntdll) build_implib(wow64) + +if (_M_ARM_64) + add_subdirectory(WOW64) +endif() diff --git a/Source/Windows/WOW64/BTInterface.h b/Source/Windows/WOW64/BTInterface.h new file mode 100644 index 000000000..afa242b89 --- /dev/null +++ b/Source/Windows/WOW64/BTInterface.h @@ -0,0 +1,25 @@ +#pragma once + +#include +#include +#include + +extern "C" { +void STDMETHODCALLTYPE BTCpuProcessInit(); +NTSTATUS STDMETHODCALLTYPE BTCpuThreadInit(); +NTSTATUS STDMETHODCALLTYPE BTCpuThreadTerm(HANDLE Thread); +void STDMETHODCALLTYPE *BTCpuGetBopCode(); +void STDMETHODCALLTYPE *__wine_get_unix_opcode(); +NTSTATUS STDMETHODCALLTYPE BTCpuGetContext(HANDLE Thread, HANDLE Process, void *Unknown, WOW64_CONTEXT *Context); +NTSTATUS STDMETHODCALLTYPE BTCpuSetContext(HANDLE Thread, HANDLE Process, void *Unknown, WOW64_CONTEXT *Context); +void STDMETHODCALLTYPE BTCpuSimulate(); +NTSTATUS STDMETHODCALLTYPE BTCpuSuspendLocalThread(HANDLE Thread, ULONG *Count); +NTSTATUS STDMETHODCALLTYPE BTCpuResetToConsistentState(EXCEPTION_POINTERS *Ptrs); +void STDMETHODCALLTYPE BTCpuFlushInstructionCache2(const void *Address, SIZE_T Size); +void STDMETHODCALLTYPE BTCpuNotifyMemoryAlloc(void *Address, SIZE_T Size, ULONG Type, ULONG Prot); +void STDMETHODCALLTYPE BTCpuNotifyMemoryProtect(void *Address, SIZE_T Size, ULONG NewProt); +void STDMETHODCALLTYPE BTCpuNotifyMemoryFree(void *Address, SIZE_T Size, ULONG FreeType); +void STDMETHODCALLTYPE BTCpuNotifyUnmapViewOfSection(void *Address, ULONG Flags); +BOOLEAN STDMETHODCALLTYPE BTCpuIsProcessorFeaturePresent(UINT Feature); +BOOLEAN STDMETHODCALLTYPE BTCpuUpdateProcessorInformation(SYSTEM_CPU_INFORMATION *Info); +} diff --git a/Source/Windows/WOW64/CMakeLists.txt b/Source/Windows/WOW64/CMakeLists.txt new file mode 100644 index 000000000..c1e0b22ab --- /dev/null +++ b/Source/Windows/WOW64/CMakeLists.txt @@ -0,0 +1,25 @@ +add_library(wow64fex SHARED + Module.cpp + libwow64fex.def +) + +target_include_directories(wow64fex PRIVATE + "${CMAKE_SOURCE_DIR}/Source/Windows/include/" + "${CMAKE_SOURCE_DIR}/Source/" +) + +target_link_libraries(wow64fex + PRIVATE + FEXCore + Common + CommonTools + wow64 + ntdll +) + +target_link_options(wow64fex PRIVATE "LINKER:--image-base,0x6f100000") + +install(TARGETS wow64fex + RUNTIME + DESTINATION bin + COMPONENT runtime) diff --git a/Source/Windows/WOW64/Module.cpp b/Source/Windows/WOW64/Module.cpp new file mode 100644 index 000000000..000a7a8e1 --- /dev/null +++ b/Source/Windows/WOW64/Module.cpp @@ -0,0 +1,389 @@ +/* +$info$ +tags: Bin|WOW64 +desc: Implements the WOW64 BT module API using FEXCore +$end_info$ +*/ + +// Thanks to André Zwing, whose ideas from https://github.com/AndreRH/hangover this code is based upon + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "Common/Config.h" +#include "DummyHandlers.h" +#include "BTInterface.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct TLS { + enum class Slot : size_t { + ENTRY_CONTEXT = WOW64_TLS_MAX_NUMBER, + THREAD_STATE = WOW64_TLS_MAX_NUMBER - 2, + }; + + _TEB *TEB; + + explicit TLS(_TEB *TEB) : TEB(TEB) {} + + CONTEXT *&EntryContext() const { + return reinterpret_cast(TEB->TlsSlots[FEXCore::ToUnderlying(Slot::ENTRY_CONTEXT)]); + } + + FEXCore::Core::InternalThreadState *&ThreadState() const { + return reinterpret_cast(TEB->TlsSlots[FEXCore::ToUnderlying(Slot::THREAD_STATE)]); + } +}; + +class WowSyscallHandler; + +namespace { + namespace BridgeInstrs { + uint16_t Syscall{0x2ecd}; + uint16_t UnixCall{0x2ecd}; + } + + fextl::unique_ptr CTX; + fextl::unique_ptr SignalDelegator; + fextl::unique_ptr SyscallHandler; + + std::pair GetThreadTLS(HANDLE Thread) { + THREAD_BASIC_INFORMATION Info; + const NTSTATUS Err = NtQueryInformationThread(Thread, ThreadBasicInformation, &Info, sizeof(Info), nullptr); + return {Err, TLS{reinterpret_cast<_TEB *>(Info.TebBaseAddress)}}; + } + + TLS GetTLS() { + return TLS{NtCurrentTeb()}; + } + + uint64_t GetWowTEB(void *TEB) { + static constexpr size_t WowTEBOffsetMemberOffset{0x180c}; + return static_cast(*reinterpret_cast(reinterpret_cast(TEB) + WowTEBOffsetMemberOffset) + + reinterpret_cast(TEB)); + } + + bool IsAddressInJit(uint64_t Address) { + return GetTLS().ThreadState()->CPUBackend->IsAddressInCodeBuffer(Address); + } +} + +namespace Context { + void LoadStateFromWowContext(FEXCore::Core::InternalThreadState *Thread, uint64_t WowTEB, WOW64_CONTEXT *Context) { + auto &State = Thread->CurrentFrame->State; + + // General register state + + State.gregs[FEXCore::X86State::REG_RAX] = Context->Eax; + State.gregs[FEXCore::X86State::REG_RBX] = Context->Ebx; + State.gregs[FEXCore::X86State::REG_RCX] = Context->Ecx; + State.gregs[FEXCore::X86State::REG_RDX] = Context->Edx; + State.gregs[FEXCore::X86State::REG_RSI] = Context->Esi; + State.gregs[FEXCore::X86State::REG_RDI] = Context->Edi; + State.gregs[FEXCore::X86State::REG_RBP] = Context->Ebp; + State.gregs[FEXCore::X86State::REG_RSP] = Context->Esp; + + State.rip = Context->Eip; + CTX->SetFlagsFromCompactedEFLAGS(Thread, Context->EFlags); + + State.es_idx = Context->SegEs & 0xffff; + State.cs_idx = Context->SegCs & 0xffff; + State.ss_idx = Context->SegSs & 0xffff; + State.ds_idx = Context->SegDs & 0xffff; + State.fs_idx = Context->SegFs & 0xffff; + State.gs_idx = Context->SegGs & 0xffff; + + // The TEB is the only populated GDT entry by default + State.gdt[(Context->SegFs & 0xffff) >> 3].base = WowTEB; + State.fs_cached = WowTEB; + State.es_cached = 0; + State.cs_cached = 0; + State.ss_cached = 0; + State.ds_cached = 0; + + // Floating-point register state + const auto *XSave = reinterpret_cast(Context->ExtendedRegisters); + + memcpy(State.xmm.sse.data, XSave->XmmRegisters, sizeof(State.xmm.sse.data)); + memcpy(State.mm, XSave->FloatRegisters, sizeof(State.mm)); + + State.FCW = XSave->ControlWord; + State.flags[FEXCore::X86State::X87FLAG_C0_LOC] = (XSave->StatusWord >> 8) & 1; + State.flags[FEXCore::X86State::X87FLAG_C1_LOC] = (XSave->StatusWord >> 9) & 1; + State.flags[FEXCore::X86State::X87FLAG_C2_LOC] = (XSave->StatusWord >> 10) & 1; + State.flags[FEXCore::X86State::X87FLAG_C3_LOC] = (XSave->StatusWord >> 14) & 1; + State.flags[FEXCore::X86State::X87FLAG_TOP_LOC] = (XSave->StatusWord >> 11) & 0b111; + State.AbridgedFTW = XSave->TagWord; + } + + void StoreWowContextFromState(FEXCore::Core::InternalThreadState *Thread, WOW64_CONTEXT *Context) { + auto &State = Thread->CurrentFrame->State; + + // General register state + + Context->Eax = State.gregs[FEXCore::X86State::REG_RAX]; + Context->Ebx = State.gregs[FEXCore::X86State::REG_RBX]; + Context->Ecx = State.gregs[FEXCore::X86State::REG_RCX]; + Context->Edx = State.gregs[FEXCore::X86State::REG_RDX]; + Context->Esi = State.gregs[FEXCore::X86State::REG_RSI]; + Context->Edi = State.gregs[FEXCore::X86State::REG_RDI]; + Context->Ebp = State.gregs[FEXCore::X86State::REG_RBP]; + Context->Esp = State.gregs[FEXCore::X86State::REG_RSP]; + + Context->Eip = State.rip; + Context->EFlags = CTX->ReconstructCompactedEFLAGS(Thread); + + Context->SegEs = State.es_idx; + Context->SegCs = State.cs_idx; + Context->SegSs = State.ss_idx; + Context->SegDs = State.ds_idx; + Context->SegFs = State.fs_idx; + Context->SegGs = State.gs_idx; + + // Floating-point register state + + auto *XSave = reinterpret_cast(Context->ExtendedRegisters); + + memcpy(XSave->XmmRegisters, State.xmm.sse.data, sizeof(State.xmm.sse.data)); + memcpy(XSave->FloatRegisters, State.mm, sizeof(State.mm)); + + XSave->ControlWord = State.FCW; + XSave->StatusWord = + (State.flags[FEXCore::X86State::X87FLAG_TOP_LOC] << 11) | + (State.flags[FEXCore::X86State::X87FLAG_C0_LOC] << 8) | + (State.flags[FEXCore::X86State::X87FLAG_C1_LOC] << 9) | + (State.flags[FEXCore::X86State::X87FLAG_C2_LOC] << 10) | + (State.flags[FEXCore::X86State::X87FLAG_C3_LOC] << 14); + XSave->TagWord = State.AbridgedFTW; + + Context->FloatSave.ControlWord = State.FCW; + Context->FloatSave.StatusWord = XSave->StatusWord; + Context->FloatSave.TagWord = FEXCore::FPState::ConvertFromAbridgedFTW(XSave->StatusWord, State.mm, XSave->TagWord); + Context->FloatSave.ErrorOffset = XSave->ErrorOffset; + Context->FloatSave.ErrorSelector = XSave->ErrorSelector | (XSave->ErrorOpcode << 16); + Context->FloatSave.DataOffset = XSave->DataOffset; + Context->FloatSave.DataSelector = XSave->DataSelector; + Context->FloatSave.Cr0NpxState = XSave->StatusWord | 0xffff0000; + } + + NTSTATUS FlushThreadStateContext(HANDLE Thread) { + const auto [Err, TLS] = GetThreadTLS(Thread); + if (Err) { + return Err; + } + + WOW64_CONTEXT TmpWowContext{ + .ContextFlags = WOW64_CONTEXT_FULL | WOW64_CONTEXT_EXTENDED_REGISTERS + }; + + Context::StoreWowContextFromState(TLS.ThreadState(), &TmpWowContext); + return RtlWow64SetThreadContext(Thread, &TmpWowContext); + } +} + +namespace Logging { + void MsgHandler(LogMan::DebugLevels Level, char const *Message) { + const auto Output = fextl::fmt::format("[{}][{:X}] {}\n", LogMan::DebugLevelStr(Level), GetCurrentThreadId(), Message); + __wine_dbg_output(Output.c_str()); + } + + void AssertHandler(char const *Message) { + const auto Output = fextl::fmt::format("[ASSERT] {}\n", Message); + __wine_dbg_output(Output.c_str()); + } + + void Init() { + LogMan::Throw::InstallHandler(AssertHandler); + LogMan::Msg::InstallHandler(MsgHandler); + } +} + +class WowSyscallHandler : public FEXCore::HLE::SyscallHandler, public FEXCore::Allocator::FEXAllocOperators { +public: + WowSyscallHandler() { + OSABI = FEXCore::HLE::SyscallOSABI::OS_WIN32; + } + + uint64_t HandleSyscall(FEXCore::Core::CpuStateFrame *Frame, FEXCore::HLE::SyscallArguments *Args) override { + const uint64_t ReturnRIP = *(uint32_t *)(Frame->State.gregs[FEXCore::X86State::REG_RSP]); // Return address from the stack + uint64_t ReturnRSP = Frame->State.gregs[FEXCore::X86State::REG_RSP] + 4; // Stack pointer after popping return address + uint64_t ReturnRAX = 0; + + // APCs/User Callbacks end up calling into the JIT from Wow64SystemService, and since the FEX return stack pointer + // is stored in TLS, the reentrant call ends up overwriting the callers stored return stack location. Stash it here + // to avoid that breaking returns used in thread suspend + const auto StashedStackLocation = Frame->ReturningStackLocation; + if (Frame->State.rip == (uint64_t)&BridgeInstrs::UnixCall) { + struct StackLayout { + unixlib_handle_t Handle; + UINT32 ID; + ULONG32 Args; + } *StackArgs = reinterpret_cast(ReturnRSP); + + ReturnRSP += sizeof(StackLayout); + + // Skip unlocking the JIT context here since the atomic accesses hurt unix call perfomance quite badly + // NOTE: this will break suspension if there are any infinitely-blocking unix calls + ReturnRAX = static_cast(__wine_unix_call(StackArgs->Handle, StackArgs->ID, ULongToPtr(StackArgs->Args))); + } else if (Frame->State.rip == (uint64_t)&BridgeInstrs::Syscall) { + const uint64_t EntryRAX = Frame->State.gregs[FEXCore::X86State::REG_RAX]; + + ReturnRAX = static_cast(Wow64SystemServiceEx(static_cast(EntryRAX), + reinterpret_cast(ReturnRSP + 4))); + + } + // If a new context has been set, use it directly and don't return to the syscall caller + if (Frame->State.rip == (uint64_t)&BridgeInstrs::Syscall || + Frame->State.rip == (uint64_t)&BridgeInstrs::UnixCall) { + Frame->State.gregs[FEXCore::X86State::REG_RAX] = ReturnRAX; + Frame->State.gregs[FEXCore::X86State::REG_RSP] = ReturnRSP; + Frame->State.rip = ReturnRIP; + } + Frame->ReturningStackLocation = StashedStackLocation; + + // NORETURNEDRESULT causes this result to be ignored since we restore all registers back from memory after a syscall anyway + return 0; + } + + FEXCore::HLE::SyscallABI GetSyscallABI(uint64_t Syscall) override { + return { .NumArgs = 0, .HasReturn = false, .HostSyscallNumber = -1 }; + } + + FEXCore::HLE::AOTIRCacheEntryLookupResult LookupAOTIRCacheEntry(FEXCore::Core::InternalThreadState *Thread, uint64_t GuestAddr) override { + return {0, 0}; + } +}; + +void BTCpuProcessInit() { + Logging::Init(); + FEX::Config::InitializeConfigs(); + FEXCore::Config::Initialize(); + FEXCore::Config::AddLayer(FEX::Config::CreateGlobalMainLayer()); + FEXCore::Config::AddLayer(FEX::Config::CreateMainLayer()); + FEXCore::Config::Load(); + FEXCore::Config::ReloadMetaLayer(); + + FEXCore::Config::EraseSet(FEXCore::Config::CONFIG_IS_INTERPRETER, "0"); + FEXCore::Config::EraseSet(FEXCore::Config::CONFIG_INTERPRETER_INSTALLED, "0"); + FEXCore::Config::EraseSet(FEXCore::Config::CONFIG_IS64BIT_MODE, "0"); + + // Not applicable to Windows + FEXCore::Config::EraseSet(FEXCore::Config::ConfigOption::CONFIG_TSOAUTOMIGRATION, "0"); + + FEXCore::Context::InitializeStaticTables(FEXCore::Context::MODE_32BIT); + + SignalDelegator = fextl::make_unique(); + SyscallHandler = fextl::make_unique(); + + CTX = FEXCore::Context::Context::CreateNewContext(); + CTX->InitializeContext(); + CTX->SetSignalDelegator(SignalDelegator.get()); + CTX->SetSyscallHandler(SyscallHandler.get()); + CTX->InitCore(0, 0); +} + +NTSTATUS BTCpuThreadInit() { + GetTLS().ThreadState() = CTX->CreateThread(nullptr, 0); + + return STATUS_SUCCESS; +} + +NTSTATUS BTCpuThreadTerm(HANDLE Thread) { + const auto [Err, TLS] = GetThreadTLS(Thread); + if (Err) { + return Err; + } + + CTX->DestroyThread(TLS.ThreadState()); + return STATUS_SUCCESS; +} + +void *BTCpuGetBopCode() { + return &BridgeInstrs::Syscall; +} + +void *__wine_get_unix_opcode() { + return &BridgeInstrs::UnixCall; +} + +NTSTATUS BTCpuGetContext(HANDLE Thread, HANDLE Process, void *Unknown, WOW64_CONTEXT *Context) { + auto [Err, TLS] = GetThreadTLS(Thread); + if (Err) { + return Err; + } + + if (Err = Context::FlushThreadStateContext(Thread); Err) { + return Err; + } + + return RtlWow64GetThreadContext(Thread, Context); +} + +NTSTATUS BTCpuSetContext(HANDLE Thread, HANDLE Process, void *Unknown, WOW64_CONTEXT *Context) { + auto [Err, TLS] = GetThreadTLS(Thread); + if (Err) { + return Err; + } + + + // Back-up the input context incase we've been passed the CPU area (the flush below would wipe it out otherwise) + WOW64_CONTEXT TmpContext = *Context; + + if (Err = Context::FlushThreadStateContext(Thread); Err) { + return Err; + } + + // Merge the input context into the CPU area then pass the full context into the JIT + if (Err = RtlWow64SetThreadContext(Thread, &TmpContext); Err) { + return Err; + } + + TmpContext.ContextFlags = WOW64_CONTEXT_FULL | WOW64_CONTEXT_EXTENDED_REGISTERS; + + if (Err = RtlWow64GetThreadContext(Thread, &TmpContext); Err) { + return Err; + } + + Context::LoadStateFromWowContext(TLS.ThreadState(), GetWowTEB(TLS.TEB), &TmpContext); + return STATUS_SUCCESS; +} + +void BTCpuSimulate() { + CONTEXT entry_context; + RtlCaptureContext(&entry_context); + + // APC handling calls BTCpuSimulate from syscalls and then use NtContinue to return to the previous context, + // to avoid the saved context being clobbered in this case only save the entry context highest in the stack + if (!GetTLS().EntryContext() || GetTLS().EntryContext()->Sp <= entry_context.Sp) { + GetTLS().EntryContext() = &entry_context; + } + + while (1) { + Context::LockJITContext(); + CTX->ExecuteThread(GetTLS().ThreadState()); + Context::UnlockJITContext(); + } +} diff --git a/Source/Windows/WOW64/libwow64fex.def b/Source/Windows/WOW64/libwow64fex.def new file mode 100644 index 000000000..f78953474 --- /dev/null +++ b/Source/Windows/WOW64/libwow64fex.def @@ -0,0 +1,20 @@ +LIBRARY libwow64fex.dll + +EXPORTS + BTCpuFlushInstructionCache2 + BTCpuGetBopCode + BTCpuGetContext + BTCpuIsProcessorFeaturePresent + BTCpuNotifyMemoryAlloc + BTCpuNotifyMemoryProtect + BTCpuNotifyMemoryFree + BTCpuNotifyUnmapViewOfSection + BTCpuProcessInit + BTCpuResetToConsistentState + BTCpuSetContext + BTCpuSimulate + BTCpuSuspendLocalThread + BTCpuThreadInit + BTCpuThreadTerm + BTCpuUpdateProcessorInformation + __wine_get_unix_opcode From be4fcaf65ceec1adf6cb5ae2fc29a2e03f16ecb3 Mon Sep 17 00:00:00 2001 From: Billy Laws Date: Thu, 10 Aug 2023 11:36:27 -0700 Subject: [PATCH 06/13] WOW64: Report CPU features based off of the emulated cpuid --- Source/Windows/WOW64/Module.cpp | 99 ++++++++++++++++++++++++++++++++- 1 file changed, 98 insertions(+), 1 deletion(-) diff --git a/Source/Windows/WOW64/Module.cpp b/Source/Windows/WOW64/Module.cpp index 000a7a8e1..890712c1f 100644 --- a/Source/Windows/WOW64/Module.cpp +++ b/Source/Windows/WOW64/Module.cpp @@ -70,6 +70,8 @@ namespace { fextl::unique_ptr SignalDelegator; fextl::unique_ptr SyscallHandler; + SYSTEM_CPU_INFORMATION CpuInfo{}; + std::pair GetThreadTLS(HANDLE Thread) { THREAD_BASIC_INFORMATION Info; const NTSTATUS Err = NtQueryInformationThread(Thread, ThreadBasicInformation, &Info, sizeof(Info), nullptr); @@ -179,7 +181,7 @@ namespace Context { (State.flags[FEXCore::X86State::X87FLAG_C3_LOC] << 14); XSave->TagWord = State.AbridgedFTW; - Context->FloatSave.ControlWord = State.FCW; + Context->FloatSave.ControlWord = XSave->ControlWord; Context->FloatSave.StatusWord = XSave->StatusWord; Context->FloatSave.TagWord = FEXCore::FPState::ConvertFromAbridgedFTW(XSave->StatusWord, State.mm, XSave->TagWord); Context->FloatSave.ErrorOffset = XSave->ErrorOffset; @@ -303,6 +305,39 @@ void BTCpuProcessInit() { CTX->SetSignalDelegator(SignalDelegator.get()); CTX->SetSyscallHandler(SyscallHandler.get()); CTX->InitCore(0, 0); + + CpuInfo.ProcessorArchitecture = PROCESSOR_ARCHITECTURE_INTEL; + + // Baseline FEX feature-set + CpuInfo.ProcessorFeatureBits = CPU_FEATURE_VME | CPU_FEATURE_TSC | CPU_FEATURE_CMOV | CPU_FEATURE_PGE | + CPU_FEATURE_PSE | CPU_FEATURE_MTRR | CPU_FEATURE_CX8 | CPU_FEATURE_MMX | + CPU_FEATURE_X86 | CPU_FEATURE_PAT | CPU_FEATURE_FXSR | CPU_FEATURE_SEP | + CPU_FEATURE_SSE | CPU_FEATURE_3DNOW | CPU_FEATURE_SSE2 | CPU_FEATURE_SSE3 | + CPU_FEATURE_CX128 | CPU_FEATURE_NX | CPU_FEATURE_SSSE3 | CPU_FEATURE_SSE41 | + CPU_FEATURE_PAE | CPU_FEATURE_DAZ; + + // Features that require specific host CPU support + const auto CPUIDResult01 = CTX->RunCPUIDFunction(0x01, 0); + if (CPUIDResult01.ecx & (1 << 20)) { + CpuInfo.ProcessorFeatureBits |= CPU_FEATURE_SSE42; + } + if (CPUIDResult01.ecx & (1 << 27)) { + CpuInfo.ProcessorFeatureBits |= CPU_FEATURE_XSAVE; + } + if (CPUIDResult01.ecx & (1 << 28)) { + CpuInfo.ProcessorFeatureBits |= CPU_FEATURE_AVX; + } + + const auto CPUIDResult07 = CTX->RunCPUIDFunction(0x07, 0); + if (CPUIDResult07.ebx & (1 << 5)) { + CpuInfo.ProcessorFeatureBits |= CPU_FEATURE_AVX2; + } + + const auto FamilyIdentifier = CPUIDResult01.eax; + CpuInfo.ProcessorLevel = ((FamilyIdentifier >> 8) & 0xf) + ((FamilyIdentifier >> 20) & 0xff); // Family + CpuInfo.ProcessorRevision = (FamilyIdentifier & 0xf0000) >> 4; // Extended Model + CpuInfo.ProcessorRevision |= (FamilyIdentifier & 0xf0) << 4; // Model + CpuInfo.ProcessorRevision |= FamilyIdentifier & 0xf; // Stepping } NTSTATUS BTCpuThreadInit() { @@ -387,3 +422,65 @@ void BTCpuSimulate() { Context::UnlockJITContext(); } } + +BOOLEAN WINAPI BTCpuIsProcessorFeaturePresent(UINT Feature) { + switch (Feature) { + case PF_FLOATING_POINT_PRECISION_ERRATA: + return FALSE; + case PF_FLOATING_POINT_EMULATED: + return FALSE; + case PF_COMPARE_EXCHANGE_DOUBLE: + return !!(CpuInfo.ProcessorFeatureBits & CPU_FEATURE_CX8); + case PF_MMX_INSTRUCTIONS_AVAILABLE: + return !!(CpuInfo.ProcessorFeatureBits & CPU_FEATURE_MMX); + case PF_XMMI_INSTRUCTIONS_AVAILABLE: + return !!(CpuInfo.ProcessorFeatureBits & CPU_FEATURE_SSE); + case PF_3DNOW_INSTRUCTIONS_AVAILABLE: + return !!(CpuInfo.ProcessorFeatureBits & CPU_FEATURE_3DNOW); + case PF_RDTSC_INSTRUCTION_AVAILABLE: + return !!(CpuInfo.ProcessorFeatureBits & CPU_FEATURE_TSC); + case PF_PAE_ENABLED: + return !!(CpuInfo.ProcessorFeatureBits & CPU_FEATURE_PAE); + case PF_XMMI64_INSTRUCTIONS_AVAILABLE: + return !!(CpuInfo.ProcessorFeatureBits & CPU_FEATURE_SSE2); + case PF_SSE3_INSTRUCTIONS_AVAILABLE: + return !!(CpuInfo.ProcessorFeatureBits & CPU_FEATURE_SSE3); + case PF_SSSE3_INSTRUCTIONS_AVAILABLE: + return !!(CpuInfo.ProcessorFeatureBits & CPU_FEATURE_SSSE3); + case PF_XSAVE_ENABLED: + return !!(CpuInfo.ProcessorFeatureBits & CPU_FEATURE_XSAVE); + case PF_COMPARE_EXCHANGE128: + return !!(CpuInfo.ProcessorFeatureBits & CPU_FEATURE_CX128); + case PF_SSE_DAZ_MODE_AVAILABLE: + return !!(CpuInfo.ProcessorFeatureBits & CPU_FEATURE_DAZ); + case PF_NX_ENABLED: + return !!(CpuInfo.ProcessorFeatureBits & CPU_FEATURE_NX); + case PF_SECOND_LEVEL_ADDRESS_TRANSLATION: + return !!(CpuInfo.ProcessorFeatureBits & CPU_FEATURE_2NDLEV); + case PF_VIRT_FIRMWARE_ENABLED: + return !!(CpuInfo.ProcessorFeatureBits & CPU_FEATURE_VIRT); + case PF_RDWRFSGSBASE_AVAILABLE: + return !!(CpuInfo.ProcessorFeatureBits & CPU_FEATURE_RDFS); + case PF_FASTFAIL_AVAILABLE: + return TRUE; + case PF_SSE4_1_INSTRUCTIONS_AVAILABLE: + return !!(CpuInfo.ProcessorFeatureBits & CPU_FEATURE_SSE41); + case PF_SSE4_2_INSTRUCTIONS_AVAILABLE: + return !!(CpuInfo.ProcessorFeatureBits & CPU_FEATURE_SSE42); + case PF_AVX_INSTRUCTIONS_AVAILABLE: + return !!(CpuInfo.ProcessorFeatureBits & CPU_FEATURE_AVX); + case PF_AVX2_INSTRUCTIONS_AVAILABLE: + return !!(CpuInfo.ProcessorFeatureBits & CPU_FEATURE_AVX2); + default: + LogMan::Msg::DFmt("Unknown CPU feature: {:X}", Feature); + return FALSE; + } +} + +BOOLEAN BTCpuUpdateProcessorInformation(SYSTEM_CPU_INFORMATION *Info) { + Info->ProcessorArchitecture = CpuInfo.ProcessorArchitecture; + Info->ProcessorLevel = CpuInfo.ProcessorLevel; + Info->ProcessorRevision = CpuInfo.ProcessorRevision; + Info->ProcessorFeatureBits = CpuInfo.ProcessorFeatureBits; + return TRUE; +} From 22b1fea96d6ef9d9ae7710da93630b8882d5c0e9 Mon Sep 17 00:00:00 2001 From: Billy Laws Date: Thu, 10 Aug 2023 11:42:20 -0700 Subject: [PATCH 07/13] WOW64: Handle unaligned atomic accesses This is done in EnsureConsistentState rather than as a VEH to avoid needing to go through all of wine's exception handling logic for such a hot path. --- Source/Windows/WOW64/Module.cpp | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/Source/Windows/WOW64/Module.cpp b/Source/Windows/WOW64/Module.cpp index 890712c1f..42b803aa3 100644 --- a/Source/Windows/WOW64/Module.cpp +++ b/Source/Windows/WOW64/Module.cpp @@ -204,6 +204,21 @@ namespace Context { Context::StoreWowContextFromState(TLS.ThreadState(), &TmpWowContext); return RtlWow64SetThreadContext(Thread, &TmpWowContext); } + + bool HandleUnalignedAccess(CONTEXT *Context) { + if (!GetTLS().ThreadState()->CPUBackend->IsAddressInCodeBuffer(Context->Pc)) { + return false; + } + + FEX_CONFIG_OPT(ParanoidTSO, PARANOIDTSO); + const auto Result = FEXCore::ArchHelpers::Arm64::HandleUnalignedAccess(ParanoidTSO(), Context->Pc, &Context->X0); + if (!Result.first) { + return false; + } + + Context->Pc += Result.second; + return true; + } } namespace Logging { @@ -423,6 +438,18 @@ void BTCpuSimulate() { } } +NTSTATUS BTCpuResetToConsistentState(EXCEPTION_POINTERS *Ptrs) { + auto *Context = Ptrs->ContextRecord; + const auto *Exception = Ptrs->ExceptionRecord; + + if (Exception->ExceptionCode == EXCEPTION_DATATYPE_MISALIGNMENT && Context::HandleUnalignedAccess(Context)) { + LogMan::Msg::DFmt("Handled unaligned atomic: new pc: {:X}", Context->Pc); + NtContinue(Context, FALSE); + } + + return STATUS_SUCCESS; +} + BOOLEAN WINAPI BTCpuIsProcessorFeaturePresent(UINT Feature) { switch (Feature) { case PF_FLOATING_POINT_PRECISION_ERRATA: From 19713bd20a51394410938bff4b8117b66e9032ba Mon Sep 17 00:00:00 2001 From: Billy Laws Date: Thu, 10 Aug 2023 11:48:02 -0700 Subject: [PATCH 08/13] WOW64: Implement exception handling with context restoration When an exception occurs, pretend that we were just at the point of JIT entry so the stack can be unwound to the wow64 SEH handler, which then handles dispatching the exception to the x86 guest with the restored context. --- Source/Windows/WOW64/Module.cpp | 44 +++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/Source/Windows/WOW64/Module.cpp b/Source/Windows/WOW64/Module.cpp index 42b803aa3..c27d4bb7a 100644 --- a/Source/Windows/WOW64/Module.cpp +++ b/Source/Windows/WOW64/Module.cpp @@ -205,6 +205,36 @@ namespace Context { return RtlWow64SetThreadContext(Thread, &TmpWowContext); } + WOW64_CONTEXT ReconstructWowContext(CONTEXT *Context) { + WOW64_CONTEXT WowContext{ + .ContextFlags = WOW64_CONTEXT_ALL, + }; + + auto *XSave = reinterpret_cast(WowContext.ExtendedRegisters); + XSave->ControlWord = 0x27f; + XSave->MxCsr = 0x1f80; + + const auto &Config = SignalDelegator->GetConfig(); + auto *Thread = GetTLS().ThreadState(); + auto &State = Thread->CurrentFrame->State; + + State.rip = CTX->RestoreRIPFromHostPC(Thread, Context->Pc); + + // Spill all SRA GPRs + for (size_t i = 0; i < Config.SRAGPRCount; i++) { + State.gregs[i] = Context->X[Config.SRAGPRMapping[i]]; + } + + // Spill all SRA FPRs + for (size_t i = 0; i < Config.SRAFPRCount; i++) { + memcpy(State.xmm.sse.data[i], &Context->V[Config.SRAFPRMapping[i]], sizeof(__uint128_t)); + } + + Context::StoreWowContextFromState(Thread, &WowContext); + + return WowContext; + } + bool HandleUnalignedAccess(CONTEXT *Context) { if (!GetTLS().ThreadState()->CPUBackend->IsAddressInCodeBuffer(Context->Pc)) { return false; @@ -447,6 +477,20 @@ NTSTATUS BTCpuResetToConsistentState(EXCEPTION_POINTERS *Ptrs) { NtContinue(Context, FALSE); } + if (!IsAddressInJit(Context->Pc)) { + return STATUS_SUCCESS; + } + + LogMan::Msg::DFmt("Reconstructing context"); + + WOW64_CONTEXT WowContext = Context::ReconstructWowContext(Context); + LogMan::Msg::DFmt("pc: {:X} eip: {:X}", Context->Pc, WowContext.Eip); + + BTCpuSetContext(GetCurrentThread(), GetCurrentProcess(), nullptr, &WowContext); + + // Replace the host context with one captured before JIT entry so host code can unwind + memcpy(Context, GetTLS().EntryContext(), sizeof(*Context)); + return STATUS_SUCCESS; } From c978fdd12fd23ce0d6d38243ea45cacc60ec19a3 Mon Sep 17 00:00:00 2001 From: Billy Laws Date: Thu, 10 Aug 2023 11:58:09 -0700 Subject: [PATCH 09/13] WOW64: Implement basic code invalidation handling --- Source/Windows/WOW64/Module.cpp | 53 +++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/Source/Windows/WOW64/Module.cpp b/Source/Windows/WOW64/Module.cpp index c27d4bb7a..beec33731 100644 --- a/Source/Windows/WOW64/Module.cpp +++ b/Source/Windows/WOW64/Module.cpp @@ -251,6 +251,34 @@ namespace Context { } } +namespace Invalidation { + void HandleMemoryProtectionNotification(uint64_t Address, uint64_t Size, ULONG Prot) { + const auto AlignedBase = Address & FHU::FEX_PAGE_MASK; + const auto AlignedSize = (Address - AlignedBase + Size + FHU::FEX_PAGE_SIZE - 1) & FHU::FEX_PAGE_MASK; + + if (Prot & (PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE)) { + CTX->InvalidateGuestCodeRange(GetTLS().ThreadState(), AlignedBase, AlignedSize); + } + } + + void InvalidateContainingSection(uint64_t Address, bool Free) { + MEMORY_BASIC_INFORMATION Info; + if (NtQueryVirtualMemory(NtCurrentProcess(), reinterpret_cast(Address), MemoryBasicInformation, &Info, sizeof(Info), nullptr)) + return; + + const auto SectionBase = reinterpret_cast(Info.AllocationBase); + const auto SectionSize = reinterpret_cast(Info.BaseAddress) + Info.RegionSize + - reinterpret_cast(Info.AllocationBase); + CTX->InvalidateGuestCodeRange(GetTLS().ThreadState(), SectionBase, SectionSize); + } + + void InvalidateAlignedInterval(uint64_t Address, uint64_t Size, bool Free) { + const auto AlignedBase = Address & FHU::FEX_PAGE_MASK; + const auto AlignedSize = (Address - AlignedBase + Size + FHU::FEX_PAGE_SIZE - 1) & FHU::FEX_PAGE_MASK; + CTX->InvalidateGuestCodeRange(GetTLS().ThreadState(), AlignedBase, AlignedSize); + } +} + namespace Logging { void MsgHandler(LogMan::DebugLevels Level, char const *Message) { const auto Output = fextl::fmt::format("[{}][{:X}] {}\n", LogMan::DebugLevelStr(Level), GetCurrentThreadId(), Message); @@ -494,6 +522,31 @@ NTSTATUS BTCpuResetToConsistentState(EXCEPTION_POINTERS *Ptrs) { return STATUS_SUCCESS; } +void BTCpuFlushInstructionCache2(const void *Address, SIZE_T Size) { + Invalidation::InvalidateAlignedInterval(reinterpret_cast(Address), static_cast(Size), false); +} + +void BTCpuNotifyMemoryAlloc(void *Address, SIZE_T Size, ULONG Type, ULONG Prot) { + Invalidation::HandleMemoryProtectionNotification(reinterpret_cast(Address), Size, Prot); +} + +void BTCpuNotifyMemoryProtect(void *Address, SIZE_T Size, ULONG NewProt, ULONG *OldProt) { + const auto AddressInt = reinterpret_cast(Address); + Invalidation::HandleMemoryProtectionNotification(AddressInt, static_cast(Size), NewProt); +} + +void BTCpuNotifyMemoryFree(void *Address, SIZE_T Size, ULONG FreeType) { + if (!Size) { + Invalidation::InvalidateContainingSection(reinterpret_cast(Address), true); + } else if (FreeType & MEM_DECOMMIT) { + Invalidation::InvalidateAlignedInterval(reinterpret_cast(Address), static_cast(Size), true); + } +} + +void BTCpuNotifyUnmapViewOfSection(void *Address, ULONG Flags) { + Invalidation::InvalidateContainingSection(reinterpret_cast(Address), true); +} + BOOLEAN WINAPI BTCpuIsProcessorFeaturePresent(UINT Feature) { switch (Feature) { case PF_FLOATING_POINT_PRECISION_ERRATA: From f57aee0a622a14fe880a7d8e35e148fc6d3adac3 Mon Sep 17 00:00:00 2001 From: Billy Laws Date: Thu, 10 Aug 2023 13:25:33 -0700 Subject: [PATCH 10/13] WOW64: Add a templated interval list implementation Stores binary intervals in a sorted vector container, to be used for SMC handling. --- Source/Windows/WOW64/IntervalList.h | 144 ++++++++++++++++++++++++++++ 1 file changed, 144 insertions(+) create mode 100644 Source/Windows/WOW64/IntervalList.h diff --git a/Source/Windows/WOW64/IntervalList.h b/Source/Windows/WOW64/IntervalList.h new file mode 100644 index 000000000..6bdca9f3e --- /dev/null +++ b/Source/Windows/WOW64/IntervalList.h @@ -0,0 +1,144 @@ +#pragma once + +#include +#include + +#include + +template +class IntervalList { +public: + using DifferenceType = decltype(std::declval() - std::declval()); + + struct Interval { + SizeType Offset; + SizeType End; + + Interval() = default; + + Interval(SizeType Offset, SizeType End) : Offset{Offset}, End{End} {} + }; + +private: + fextl::vector Intervals; ///< list of intervals sorted by their end offset + +public: + struct QueryResult { + bool Enclosed; ///< If the given offset was enclosed by an interval + DifferenceType Size; ///< Size of the interval starting from the query offset, or distance to the next interval if + /// `Enclosed` is false (if there is no next interval, size is 0) + }; + + void Clear() { + Intervals.clear(); + } + + void Insert(Interval Entry) { + if (Entry.Offset == Entry.End) { + return; + } + + auto [FirstIt, EndIt] = std::equal_range(Intervals.begin(), Intervals.end(), Entry, [](const auto &LHS, const auto &RHS) { + return LHS.End <= RHS.Offset; + }); + + if (FirstIt == EndIt) { + // No overlaps + Intervals.insert(FirstIt, Entry); + return; + } + + auto LastIt = std::prev(EndIt); + // FirstIt/LastIt are the lowest/highest offset intervals respectively that overlap with the new interval + + const SizeType Offset = std::min(Entry.Offset, FirstIt->Offset); + const SizeType End = std::max(LastIt->End, Entry.End); + + // Erase all overlapping entries but the first + const auto EraseStartIt = std::next(FirstIt); + const auto EraseEndIt = std::next(LastIt); + LastIt = Intervals.erase(EraseStartIt, EraseEndIt); + FirstIt = std::prev(LastIt); + + FirstIt->Offset = Offset; + FirstIt->End = End; + } + + void Remove(Interval Entry) { + if (Entry.Offset == Entry.End) { + return; + } + + auto [FirstIt, EndIt] = std::equal_range(Intervals.begin(), Intervals.end(), Entry, [](const auto &LHS, const auto &RHS) { + return LHS.End <= RHS.Offset; + }); + + if (FirstIt == EndIt) { + // No intersecting intervals present, nothing more to do + return; + } + + if (FirstIt->Offset < Entry.Offset && FirstIt->End > Entry.End) { + // The interval to be removed is fully enclosed by an existing interval + + // Break the single interval into two smaller intervals on either side on the interval being removed + const auto FirstPredecessorIt = Intervals.insert(FirstIt, *FirstIt); + FirstIt = std::next(FirstPredecessorIt); + FirstPredecessorIt->End = Entry.Offset; + FirstIt->Offset = Entry.End; + return; + } + + auto LastIt = std::prev(EndIt); + // FirstIt/LastIt are the lowest/highest offset intervals respectively that overlap with the new interval + + if (FirstIt->Offset < Entry.Offset) { + // The first overlap straddles the start of the interval to be removed + FirstIt->End = Entry.Offset; + if (FirstIt == LastIt) { + // No more overlaps left, nothing more to do + return; + } else { + FirstIt++; + } + } + + if (LastIt->End > Entry.End) { + // The last overlap straddles the end of the interval to be removed + LastIt->Offset = Entry.End; + if (LastIt == FirstIt) { + // No more overlaps left, nothing more to do + return; + } else { + LastIt--; + } + } + + // Now none of the overlaps straddle the edges of the interval to be removed they can all be erased + const auto EraseStartIt = FirstIt; + const auto EraseEndIt = std::next(LastIt); + Intervals.erase(EraseStartIt, EraseEndIt); + } + + QueryResult Query(SizeType Offset) { + const auto It = std::upper_bound(Intervals.begin(), Intervals.end(), Offset, [](const auto &LHS, const auto &RHS) { + return LHS < RHS.End; + }); // Lowest offset interval that (maybe) overlaps with the query offset + + if (It == Intervals.end()) { // No overlaps past offset + return {false, {}}; + } else if (It->Offset > Offset) { // No overlap, return the distance to the next possible overlap + return {false, It->Offset - Offset}; + } else { // Overlap, return the distance to the end of the overlap + return {true, It->End - Offset}; + } + } + + bool Intersect(Interval Entry) { + const auto It = std::upper_bound(Intervals.begin(), Intervals.end(), Entry, [](const auto &LHS, const auto &RHS) { + return LHS.Offset < RHS.End; + }); // Lowest offset interval that (maybe) overlaps with the query offset + + return It != Intervals.end() && It->Offset < Entry.End; + } +}; From 3d6955592b6a06643de460068387b6d8ee861094 Mon Sep 17 00:00:00 2001 From: Billy Laws Date: Thu, 10 Aug 2023 13:39:58 -0700 Subject: [PATCH 11/13] WOW64: Implement partial self-modifying code handling This should support most simple cases of SMC, however programs which make use of separate shared memory mappings for writing and execution are not handled. The overall approach is the same as is done for linux, where RWX mappings are protected to RX and then when a write occurs the signal handler invalidates the faulting page and reprotects it to RWX until code in that page is jitted again. --- Source/Windows/WOW64/Module.cpp | 103 ++++++++++++++++++++++++++------ 1 file changed, 86 insertions(+), 17 deletions(-) diff --git a/Source/Windows/WOW64/Module.cpp b/Source/Windows/WOW64/Module.cpp index beec33731..5ae7dc9ee 100644 --- a/Source/Windows/WOW64/Module.cpp +++ b/Source/Windows/WOW64/Module.cpp @@ -27,6 +27,7 @@ $end_info$ #include "Common/Config.h" #include "DummyHandlers.h" #include "BTInterface.h" +#include "IntervalList.h" #include #include @@ -42,7 +43,7 @@ $end_info$ struct TLS { enum class Slot : size_t { ENTRY_CONTEXT = WOW64_TLS_MAX_NUMBER, - THREAD_STATE = WOW64_TLS_MAX_NUMBER - 2, + THREAD_STATE = WOW64_TLS_MAX_NUMBER - 1, }; _TEB *TEB; @@ -252,6 +253,9 @@ namespace Context { } namespace Invalidation { + static IntervalList RWXIntervals; + static std::mutex RWXIntervalsLock; + void HandleMemoryProtectionNotification(uint64_t Address, uint64_t Size, ULONG Prot) { const auto AlignedBase = Address & FHU::FEX_PAGE_MASK; const auto AlignedSize = (Address - AlignedBase + Size + FHU::FEX_PAGE_SIZE - 1) & FHU::FEX_PAGE_MASK; @@ -259,6 +263,15 @@ namespace Invalidation { if (Prot & (PAGE_EXECUTE | PAGE_EXECUTE_READ | PAGE_EXECUTE_READWRITE)) { CTX->InvalidateGuestCodeRange(GetTLS().ThreadState(), AlignedBase, AlignedSize); } + + if (Prot & PAGE_EXECUTE_READWRITE) { + LogMan::Msg::DFmt("Add SMC interval: {:X} - {:X}", AlignedBase, AlignedBase + AlignedSize); + std::scoped_lock Lock(RWXIntervalsLock); + RWXIntervals.Insert({AlignedBase, AlignedBase + AlignedSize}); + } else { + std::scoped_lock Lock(RWXIntervalsLock); + RWXIntervals.Remove({AlignedBase, AlignedBase + AlignedSize}); + } } void InvalidateContainingSection(uint64_t Address, bool Free) { @@ -270,12 +283,65 @@ namespace Invalidation { const auto SectionSize = reinterpret_cast(Info.BaseAddress) + Info.RegionSize - reinterpret_cast(Info.AllocationBase); CTX->InvalidateGuestCodeRange(GetTLS().ThreadState(), SectionBase, SectionSize); + + if (Free) { + std::scoped_lock Lock(RWXIntervalsLock); + RWXIntervals.Remove({SectionBase, SectionBase + SectionSize}); + } } void InvalidateAlignedInterval(uint64_t Address, uint64_t Size, bool Free) { const auto AlignedBase = Address & FHU::FEX_PAGE_MASK; const auto AlignedSize = (Address - AlignedBase + Size + FHU::FEX_PAGE_SIZE - 1) & FHU::FEX_PAGE_MASK; CTX->InvalidateGuestCodeRange(GetTLS().ThreadState(), AlignedBase, AlignedSize); + + if (Free) { + std::scoped_lock Lock(RWXIntervalsLock); + RWXIntervals.Remove({AlignedBase, AlignedBase + AlignedSize}); + } + } + + void ReprotectRWXIntervals(uint64_t Address, uint64_t Size) { + const auto End = Address + Size; + std::scoped_lock Lock(RWXIntervalsLock); + + do { + const auto Query = RWXIntervals.Query(Address); + if (Query.Enclosed) { + void *TmpAddress = reinterpret_cast(Address); + SIZE_T TmpSize = static_cast(std::min(End, Address + Query.Size) - Address); + ULONG TmpProt; + NtProtectVirtualMemory(NtCurrentProcess(), &TmpAddress, &TmpSize, PAGE_EXECUTE_READ, &TmpProt); + } else if (!Query.Size) { + // No more regions past `Address` in the interval list + break; + } + + Address += Query.Size; + } while (Address < End); + } + + bool HandleRWXAccessViolation(uint64_t FaultAddress) { + const bool NeedsInvalidate = [](uint64_t Address) { + std::unique_lock Lock(RWXIntervalsLock); + const bool Enclosed = RWXIntervals.Query(Address).Enclosed; + // Invalidate just the single faulting page + if (!Enclosed) + return false; + + ULONG TmpProt; + void *TmpAddress = reinterpret_cast(Address); + SIZE_T TmpSize = 1; + NtProtectVirtualMemory(NtCurrentProcess(), &TmpAddress, &TmpSize, PAGE_EXECUTE_READWRITE, &TmpProt); + return true; + }(FaultAddress); + + if (NeedsInvalidate) { + // RWXIntervalsLock cannot be held during invalidation + CTX->InvalidateGuestCodeRange(GetTLS().ThreadState(), FaultAddress & FHU::FEX_PAGE_MASK, FHU::FEX_PAGE_SIZE); + return true; + } + return false; } } @@ -307,10 +373,6 @@ public: uint64_t ReturnRSP = Frame->State.gregs[FEXCore::X86State::REG_RSP] + 4; // Stack pointer after popping return address uint64_t ReturnRAX = 0; - // APCs/User Callbacks end up calling into the JIT from Wow64SystemService, and since the FEX return stack pointer - // is stored in TLS, the reentrant call ends up overwriting the callers stored return stack location. Stash it here - // to avoid that breaking returns used in thread suspend - const auto StashedStackLocation = Frame->ReturningStackLocation; if (Frame->State.rip == (uint64_t)&BridgeInstrs::UnixCall) { struct StackLayout { unixlib_handle_t Handle; @@ -320,8 +382,6 @@ public: ReturnRSP += sizeof(StackLayout); - // Skip unlocking the JIT context here since the atomic accesses hurt unix call perfomance quite badly - // NOTE: this will break suspension if there are any infinitely-blocking unix calls ReturnRAX = static_cast(__wine_unix_call(StackArgs->Handle, StackArgs->ID, ULongToPtr(StackArgs->Args))); } else if (Frame->State.rip == (uint64_t)&BridgeInstrs::Syscall) { const uint64_t EntryRAX = Frame->State.gregs[FEXCore::X86State::REG_RAX]; @@ -337,7 +397,6 @@ public: Frame->State.gregs[FEXCore::X86State::REG_RSP] = ReturnRSP; Frame->State.rip = ReturnRIP; } - Frame->ReturningStackLocation = StashedStackLocation; // NORETURNEDRESULT causes this result to be ignored since we restore all registers back from memory after a syscall anyway return 0; @@ -350,6 +409,10 @@ public: FEXCore::HLE::AOTIRCacheEntryLookupResult LookupAOTIRCacheEntry(FEXCore::Core::InternalThreadState *Thread, uint64_t GuestAddr) override { return {0, 0}; } + + void MarkGuestExecutableRange(FEXCore::Core::InternalThreadState *Thread, uint64_t Start, uint64_t Length) override { + Invalidation::ReprotectRWXIntervals(Start, Length); + } }; void BTCpuProcessInit() { @@ -489,17 +552,22 @@ void BTCpuSimulate() { GetTLS().EntryContext() = &entry_context; } - while (1) { - Context::LockJITContext(); - CTX->ExecuteThread(GetTLS().ThreadState()); - Context::UnlockJITContext(); - } + CTX->ExecuteThread(GetTLS().ThreadState()); } NTSTATUS BTCpuResetToConsistentState(EXCEPTION_POINTERS *Ptrs) { auto *Context = Ptrs->ContextRecord; const auto *Exception = Ptrs->ExceptionRecord; + if (Exception->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) { + const auto FaultAddress = static_cast(Exception->ExceptionInformation[1]); + + if (Invalidation::HandleRWXAccessViolation(FaultAddress)) { + LogMan::Msg::DFmt("Handled self-modifying code: pc: {:X} fault: {:X}", Context->Pc, FaultAddress); + NtContinue(Context, FALSE); + } + } + if (Exception->ExceptionCode == EXCEPTION_DATATYPE_MISALIGNMENT && Context::HandleUnalignedAccess(Context)) { LogMan::Msg::DFmt("Handled unaligned atomic: new pc: {:X}", Context->Pc); NtContinue(Context, FALSE); @@ -527,12 +595,13 @@ void BTCpuFlushInstructionCache2(const void *Address, SIZE_T Size) { } void BTCpuNotifyMemoryAlloc(void *Address, SIZE_T Size, ULONG Type, ULONG Prot) { - Invalidation::HandleMemoryProtectionNotification(reinterpret_cast(Address), Size, Prot); + Invalidation::HandleMemoryProtectionNotification(reinterpret_cast(Address), static_cast(Size), + Prot); } -void BTCpuNotifyMemoryProtect(void *Address, SIZE_T Size, ULONG NewProt, ULONG *OldProt) { - const auto AddressInt = reinterpret_cast(Address); - Invalidation::HandleMemoryProtectionNotification(AddressInt, static_cast(Size), NewProt); +void BTCpuNotifyMemoryProtect(void *Address, SIZE_T Size, ULONG NewProt) { + Invalidation::HandleMemoryProtectionNotification(reinterpret_cast(Address), static_cast(Size), + NewProt); } void BTCpuNotifyMemoryFree(void *Address, SIZE_T Size, ULONG FreeType) { From 057a7c6ee880a8ffb148c3698297986ded8abb3c Mon Sep 17 00:00:00 2001 From: Billy Laws Date: Thu, 10 Aug 2023 14:15:37 -0700 Subject: [PATCH 12/13] WOW64: Implement thread suspension handling This provides more robust handling than a signal based approach, as the suspender is able to wait for the suspendee to reach a suitable position and flush its context to memory before returning. --- Source/Windows/WOW64/Module.cpp | 198 +++++++++++++++++++++++++++++--- 1 file changed, 179 insertions(+), 19 deletions(-) diff --git a/Source/Windows/WOW64/Module.cpp b/Source/Windows/WOW64/Module.cpp index 5ae7dc9ee..d88175a8e 100644 --- a/Source/Windows/WOW64/Module.cpp +++ b/Source/Windows/WOW64/Module.cpp @@ -40,16 +40,34 @@ $end_info$ #include #include +namespace ControlBits { + // When this is unset, a thread can be safely interrupted and have its context recovered + // IMPORTANT: This can only safely be written by the owning thread + static constexpr uint32_t IN_JIT{1U << 0}; + + // JIT entry polls this bit until it is unset, at which point CONTROL_IN_JIT will be set + static constexpr uint32_t PAUSED{1U << 1}; + + // When this is set, the CPU context stored in the CPU area has not yet been flushed to the FEX TLS + static constexpr uint32_t WOW_CPU_AREA_DIRTY{1U << 2}; +}; + struct TLS { enum class Slot : size_t { ENTRY_CONTEXT = WOW64_TLS_MAX_NUMBER, - THREAD_STATE = WOW64_TLS_MAX_NUMBER - 1, + CONTROL_WORD = WOW64_TLS_MAX_NUMBER - 1, + THREAD_STATE = WOW64_TLS_MAX_NUMBER - 2, }; _TEB *TEB; explicit TLS(_TEB *TEB) : TEB(TEB) {} + std::atomic &ControlWord() const { + // TODO: Change this when libc++ gains std::atomic_ref support + return reinterpret_cast &>(TEB->TlsSlots[FEXCore::ToUnderlying(Slot::CONTROL_WORD)]); + } + CONTEXT *&EntryContext() const { return reinterpret_cast(TEB->TlsSlots[FEXCore::ToUnderlying(Slot::ENTRY_CONTEXT)]); } @@ -63,6 +81,7 @@ class WowSyscallHandler; namespace { namespace BridgeInstrs { + // These directly jumped to by the guest to make system calls uint16_t Syscall{0x2ecd}; uint16_t UnixCall{0x2ecd}; } @@ -73,6 +92,8 @@ namespace { SYSTEM_CPU_INFORMATION CpuInfo{}; + std::mutex ThreadSuspendLock; + std::pair GetThreadTLS(HANDLE Thread) { THREAD_BASIC_INFORMATION Info; const NTSTATUS Err = NtQueryInformationThread(Thread, ThreadBasicInformation, &Info, sizeof(Info), nullptr); @@ -206,15 +227,7 @@ namespace Context { return RtlWow64SetThreadContext(Thread, &TmpWowContext); } - WOW64_CONTEXT ReconstructWowContext(CONTEXT *Context) { - WOW64_CONTEXT WowContext{ - .ContextFlags = WOW64_CONTEXT_ALL, - }; - - auto *XSave = reinterpret_cast(WowContext.ExtendedRegisters); - XSave->ControlWord = 0x27f; - XSave->MxCsr = 0x1f80; - + void ReconstructThreadState(CONTEXT *Context) { const auto &Config = SignalDelegator->GetConfig(); auto *Thread = GetTLS().ThreadState(); auto &State = Thread->CurrentFrame->State; @@ -230,9 +243,20 @@ namespace Context { for (size_t i = 0; i < Config.SRAFPRCount; i++) { memcpy(State.xmm.sse.data[i], &Context->V[Config.SRAFPRMapping[i]], sizeof(__uint128_t)); } + } - Context::StoreWowContextFromState(Thread, &WowContext); + WOW64_CONTEXT ReconstructWowContext(CONTEXT *Context) { + ReconstructThreadState(Context); + WOW64_CONTEXT WowContext{ + .ContextFlags = WOW64_CONTEXT_ALL, + }; + + auto *XSave = reinterpret_cast(WowContext.ExtendedRegisters); + XSave->ControlWord = 0x27f; + XSave->MxCsr = 0x1f80; + + Context::StoreWowContextFromState(GetTLS().ThreadState(), &WowContext); return WowContext; } @@ -250,6 +274,52 @@ namespace Context { Context->Pc += Result.second; return true; } + + void LockJITContext() { + uint32_t Expected = GetTLS().ControlWord().load(), New; + + // Spin until PAUSED is unset, setting IN_JIT when that occurs + do { + Expected = Expected & ~ControlBits::PAUSED; + New = (Expected | ControlBits::IN_JIT) & ~ControlBits::WOW_CPU_AREA_DIRTY; + } while (!GetTLS().ControlWord().compare_exchange_weak(Expected, New, std::memory_order::relaxed)); + std::atomic_signal_fence(std::memory_order::seq_cst); + + // If the CPU area is dirty, flush it to the JIT context before reentry + if (Expected & ControlBits::WOW_CPU_AREA_DIRTY) { + WOW64_CONTEXT *WowContext; + RtlWow64GetCurrentCpuArea(nullptr, reinterpret_cast(&WowContext), nullptr); + Context::LoadStateFromWowContext(GetTLS().ThreadState(), GetWowTEB(NtCurrentTeb()), WowContext); + } + } + + void UnlockJITContext() { + std::atomic_signal_fence(std::memory_order::seq_cst); + GetTLS().ControlWord().fetch_and(~ControlBits::IN_JIT, std::memory_order::relaxed); + } + + bool HandleSuspendInterrupt(CONTEXT *Context, uint64_t FaultAddress) { + if (FaultAddress != reinterpret_cast(&GetTLS().ThreadState()->InterruptFaultPage)) { + return false; + } + + void *TmpAddress = reinterpret_cast(FaultAddress); + SIZE_T TmpSize = FHU::FEX_PAGE_SIZE; + ULONG TmpProt; + NtProtectVirtualMemory(NtCurrentProcess(), &TmpAddress, &TmpSize, PAGE_READWRITE, &TmpProt); + + // Since interrupts only happen at the start of blocks, the reconstructed state should be entirely accurate + ReconstructThreadState(Context); + + // Yield to the suspender + UnlockJITContext(); + LockJITContext(); + + // Adjust context to return to the dispatcher, reloading SRA from thread state + const auto &Config = SignalDelegator->GetConfig(); + Context->Pc = Config.AbsoluteLoopTopAddressFillSRA; + return true; + } } namespace Invalidation { @@ -382,12 +452,16 @@ public: ReturnRSP += sizeof(StackLayout); + Context::UnlockJITContext(); ReturnRAX = static_cast(__wine_unix_call(StackArgs->Handle, StackArgs->ID, ULongToPtr(StackArgs->Args))); + Context::LockJITContext(); } else if (Frame->State.rip == (uint64_t)&BridgeInstrs::Syscall) { const uint64_t EntryRAX = Frame->State.gregs[FEXCore::X86State::REG_RAX]; + Context::UnlockJITContext(); ReturnRAX = static_cast(Wow64SystemServiceEx(static_cast(EntryRAX), reinterpret_cast(ReturnRSP + 4))); + Context::LockJITContext(); } // If a new context has been set, use it directly and don't return to the syscall caller @@ -506,8 +580,10 @@ NTSTATUS BTCpuGetContext(HANDLE Thread, HANDLE Process, void *Unknown, WOW64_CON return Err; } - if (Err = Context::FlushThreadStateContext(Thread); Err) { - return Err; + if (!(TLS.ControlWord().load(std::memory_order::relaxed) & ControlBits::WOW_CPU_AREA_DIRTY)) { + if (Err = Context::FlushThreadStateContext(Thread); Err) { + return Err; + } } return RtlWow64GetThreadContext(Thread, Context); @@ -523,8 +599,10 @@ NTSTATUS BTCpuSetContext(HANDLE Thread, HANDLE Process, void *Unknown, WOW64_CON // Back-up the input context incase we've been passed the CPU area (the flush below would wipe it out otherwise) WOW64_CONTEXT TmpContext = *Context; - if (Err = Context::FlushThreadStateContext(Thread); Err) { - return Err; + if (!(TLS.ControlWord().load(std::memory_order::relaxed) & ControlBits::WOW_CPU_AREA_DIRTY)) { + if (Err = Context::FlushThreadStateContext(Thread); Err) { + return Err; + } } // Merge the input context into the CPU area then pass the full context into the JIT @@ -552,12 +630,93 @@ void BTCpuSimulate() { GetTLS().EntryContext() = &entry_context; } + Context::LockJITContext(); CTX->ExecuteThread(GetTLS().ThreadState()); + Context::UnlockJITContext(); +} + +NTSTATUS BTCpuSuspendLocalThread(HANDLE Thread, ULONG *Count) { + 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); + if (ThreadTID == GetCurrentThreadId()) { + LogMan::Msg::DFmt("Suspending self"); + // Mark the CPU area as dirty, to force the JIT context to be restored from it on entry as it may be changed using + // SetThreadContext (which doesn't use the BTCpu API) + if (!(GetTLS().ControlWord().fetch_or(ControlBits::WOW_CPU_AREA_DIRTY, std::memory_order::relaxed) & + ControlBits::WOW_CPU_AREA_DIRTY)) { + if (NTSTATUS Err = Context::FlushThreadStateContext(Thread); Err) { + return Err; + } + } + + return NtSuspendThread(Thread, Count); + } + + LogMan::Msg::DFmt("Suspending thread: {:X}", ThreadTID); + + auto [Err, TLS] = GetThreadTLS(Thread); + if (Err) { + return Err; + } + + std::scoped_lock Lock(ThreadSuspendLock); + // 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 + if (TLS.ControlWord().fetch_or(ControlBits::PAUSED, std::memory_order::relaxed) & ControlBits::IN_JIT) { + LogMan::Msg::DFmt("Thread {:X} is in JIT, polling for interrupt", ThreadTID); + + ULONG TmpProt; + void *TmpAddress = &TLS.ThreadState()->InterruptFaultPage; + SIZE_T TmpSize = FHU::FEX_PAGE_SIZE; + NtProtectVirtualMemory(NtCurrentProcess(), &TmpAddress, &TmpSize, PAGE_READONLY, &TmpProt); + } + + // Spin until the JIT is interrupted + while (TLS.ControlWord().load() & ControlBits::IN_JIT); + + // The JIT has now been interrupted and the context stored in the thread's CPU area is up-to-date + if (Err = NtSuspendThread(Thread, Count); Err) { + TLS.ControlWord().fetch_and(~ControlBits::PAUSED, std::memory_order::relaxed); + return Err; + } + + CONTEXT TmpContext{ + .ContextFlags = CONTEXT_INTEGER, + }; + + // NtSuspendThread may return before the thread is actually suspended, so a sync operation like NtGetContextThread + // needs to be called to ensure it is before we unset CONTROL_PAUSED + std::ignore = NtGetContextThread(Thread, &TmpContext); + + // Mark the CPU area as dirty, to force the JIT context to be restored from it on entry as it may be changed using + // SetThreadContext (which doesn't use the BTCpu API) + if (!(TLS.ControlWord().fetch_or(ControlBits::WOW_CPU_AREA_DIRTY, std::memory_order::relaxed) & ControlBits::WOW_CPU_AREA_DIRTY)) { + if (Err = Context::FlushThreadStateContext(Thread); Err) { + return Err; + } + } + + LogMan::Msg::DFmt("Thread suspended: {:X}", ThreadTID); + + // Now the thread is suspended on the host, unset CONTROL_PAUSED so that NtResumeThread will + // continue execution in the JIT + TLS.ControlWord().fetch_and(~ControlBits::PAUSED, std::memory_order::relaxed); + + return Err; } NTSTATUS BTCpuResetToConsistentState(EXCEPTION_POINTERS *Ptrs) { auto *Context = Ptrs->ContextRecord; const auto *Exception = Ptrs->ExceptionRecord; + if (Exception->ExceptionCode == EXCEPTION_DATATYPE_MISALIGNMENT && Context::HandleUnalignedAccess(Context)) { + LogMan::Msg::DFmt("Handled unaligned atomic: new pc: {:X}", Context->Pc); + NtContinue(Context, FALSE); + } if (Exception->ExceptionCode == EXCEPTION_ACCESS_VIOLATION) { const auto FaultAddress = static_cast(Exception->ExceptionInformation[1]); @@ -566,11 +725,11 @@ NTSTATUS BTCpuResetToConsistentState(EXCEPTION_POINTERS *Ptrs) { LogMan::Msg::DFmt("Handled self-modifying code: pc: {:X} fault: {:X}", Context->Pc, FaultAddress); NtContinue(Context, FALSE); } - } - if (Exception->ExceptionCode == EXCEPTION_DATATYPE_MISALIGNMENT && Context::HandleUnalignedAccess(Context)) { - LogMan::Msg::DFmt("Handled unaligned atomic: new pc: {:X}", Context->Pc); - NtContinue(Context, FALSE); + if (Context::HandleSuspendInterrupt(Context, FaultAddress)) { + LogMan::Msg::DFmt("Resumed from suspend"); + NtContinue(Context, FALSE); + } } if (!IsAddressInJit(Context->Pc)) { @@ -583,6 +742,7 @@ NTSTATUS BTCpuResetToConsistentState(EXCEPTION_POINTERS *Ptrs) { LogMan::Msg::DFmt("pc: {:X} eip: {:X}", Context->Pc, WowContext.Eip); BTCpuSetContext(GetCurrentThread(), GetCurrentProcess(), nullptr, &WowContext); + Context::UnlockJITContext(); // Replace the host context with one captured before JIT entry so host code can unwind memcpy(Context, GetTLS().EntryContext(), sizeof(*Context)); From 04cf418452e4be378957134d5ef5e9e499ef6d50 Mon Sep 17 00:00:00 2001 From: Billy Laws Date: Thu, 21 Sep 2023 16:59:41 -0700 Subject: [PATCH 13/13] Windows: Add SPDX license identifiers --- Source/Windows/WOW64/BTInterface.h | 1 + Source/Windows/WOW64/IntervalList.h | 1 + Source/Windows/WOW64/Module.cpp | 1 + Source/Windows/include/wine/debug.h | 21 ++------------------- Source/Windows/include/wine/unixlib.h | 21 ++------------------- Source/Windows/include/winternl.h | 21 ++------------------- 6 files changed, 9 insertions(+), 57 deletions(-) diff --git a/Source/Windows/WOW64/BTInterface.h b/Source/Windows/WOW64/BTInterface.h index afa242b89..7ff7f019f 100644 --- a/Source/Windows/WOW64/BTInterface.h +++ b/Source/Windows/WOW64/BTInterface.h @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: MIT #pragma once #include diff --git a/Source/Windows/WOW64/IntervalList.h b/Source/Windows/WOW64/IntervalList.h index 6bdca9f3e..6c2b772a4 100644 --- a/Source/Windows/WOW64/IntervalList.h +++ b/Source/Windows/WOW64/IntervalList.h @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: MIT #pragma once #include diff --git a/Source/Windows/WOW64/Module.cpp b/Source/Windows/WOW64/Module.cpp index d88175a8e..ee5dff680 100644 --- a/Source/Windows/WOW64/Module.cpp +++ b/Source/Windows/WOW64/Module.cpp @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: MIT /* $info$ tags: Bin|WOW64 diff --git a/Source/Windows/include/wine/debug.h b/Source/Windows/include/wine/debug.h index c3bc48055..70a4868e0 100644 --- a/Source/Windows/include/wine/debug.h +++ b/Source/Windows/include/wine/debug.h @@ -1,22 +1,5 @@ -/* - * Wine debugging interface - * - * Copyright 1999 Patrik Stridvall - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ +// SPDX-License-Identifier: LGPL-2.1-or-later +// SPDX-FileCopyrightText: Copyright 1999 Patrik Stridvall #pragma once diff --git a/Source/Windows/include/wine/unixlib.h b/Source/Windows/include/wine/unixlib.h index 40d348081..bca7ae3a8 100644 --- a/Source/Windows/include/wine/unixlib.h +++ b/Source/Windows/include/wine/unixlib.h @@ -1,22 +1,5 @@ -/* - * Definitions for Unix libraries - * - * Copyright (C) 2021 Alexandre Julliard - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ +// SPDX-License-Identifier: LGPL-2.1-or-later +// SPDX-FileCopyrightText: Copyright (C) 2021 Alexandre Julliard #pragma once diff --git a/Source/Windows/include/winternl.h b/Source/Windows/include/winternl.h index 9cd5d2260..dddcc6963 100644 --- a/Source/Windows/include/winternl.h +++ b/Source/Windows/include/winternl.h @@ -1,22 +1,5 @@ -/* - * Internal NT APIs and data structures - * - * Copyright (C) the Wine project - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ +// SPDX-License-Identifier: LGPL-2.1-or-later +// SPDX-FileCopyrightText: Copyright (C) the Wine project #pragma once