Module: wine Branch: master Commit: 716599703671fe0e003c022a21f39621fe064d67 URL: https://source.winehq.org/git/wine.git/?a=commit;h=716599703671fe0e003c022a2...
Author: Alexandre Julliard julliard@winehq.org Date: Thu Dec 2 09:59:08 2021 +0100
wow64: Add support for user callbacks.
Signed-off-by: Alexandre Julliard julliard@winehq.org
---
dlls/wow64/syscall.c | 112 ++++++++++++++++++++++++++++++++++++++++++++++++++ dlls/wow64/syscall.h | 1 + dlls/wow64/wow64.spec | 2 +- include/winternl.h | 7 ++-- 4 files changed, 118 insertions(+), 4 deletions(-)
diff --git a/dlls/wow64/syscall.c b/dlls/wow64/syscall.c index bee186456cc..75a5df5c453 100644 --- a/dlls/wow64/syscall.c +++ b/dlls/wow64/syscall.c @@ -70,6 +70,18 @@ struct mem_header BYTE data[1]; };
+/* stack frame for user callbacks */ +struct user_callback_frame +{ + struct user_callback_frame *prev_frame; + struct mem_header *temp_list; + void **ret_ptr; + ULONG *ret_len; + NTSTATUS status; + __wine_jmp_buf jmpbuf; +}; + + SYSTEM_DLL_INIT_BLOCK *pLdrSystemDllInitBlock = NULL;
/* wow64win syscall table */ @@ -143,6 +155,26 @@ NTSTATUS WINAPI wow64_NtAllocateUuids( UINT *args ) }
+/*********************************************************************** + * wow64_NtCallbackReturn + */ +NTSTATUS WINAPI wow64_NtCallbackReturn( UINT *args ) +{ + void *ret_ptr = get_ptr( &args ); + ULONG ret_len = get_ulong( &args ); + NTSTATUS status = get_ulong( &args ); + + struct user_callback_frame *frame = NtCurrentTeb()->TlsSlots[WOW64_TLS_USERCALLBACKDATA]; + + if (!frame) return STATUS_NO_CALLBACK_ACTIVE; + + *frame->ret_ptr = ret_ptr; + *frame->ret_len = ret_len; + frame->status = status; + __wine_longjmp( &frame->jmpbuf, 1 ); +} + + /********************************************************************** * wow64_NtClose */ @@ -793,6 +825,86 @@ void WINAPI Wow64ApcRoutine( ULONG_PTR arg1, ULONG_PTR arg2, ULONG_PTR arg3, CON }
+/********************************************************************** + * Wow64KiUserCallbackDispatcher (wow64.@) + */ +NTSTATUS WINAPI Wow64KiUserCallbackDispatcher( ULONG id, void *args, ULONG len, + void **ret_ptr, ULONG *ret_len ) +{ + struct user_callback_frame frame; + + frame.prev_frame = NtCurrentTeb()->TlsSlots[WOW64_TLS_USERCALLBACKDATA]; + frame.temp_list = NtCurrentTeb()->TlsSlots[WOW64_TLS_TEMPLIST]; + frame.ret_ptr = ret_ptr; + frame.ret_len = ret_len; + + NtCurrentTeb()->TlsSlots[WOW64_TLS_USERCALLBACKDATA] = &frame; + NtCurrentTeb()->TlsSlots[WOW64_TLS_TEMPLIST] = NULL; + + /* cf. 32-bit KeUserModeCallback */ + switch (current_machine) + { + case IMAGE_FILE_MACHINE_I386: + { + I386_CONTEXT orig_ctx, ctx = { CONTEXT_I386_FULL }; + void *args_data; + ULONG *stack; + + NtQueryInformationThread( GetCurrentThread(), ThreadWow64Context, &ctx, sizeof(ctx), NULL ); + + stack = args_data = ULongToPtr( (ctx.Esp - len) & ~15 ); + memcpy( args_data, args, len ); + *(--stack) = 0; + *(--stack) = len; + *(--stack) = PtrToUlong( args_data ); + *(--stack) = id; + *(--stack) = 0xdeadbabe; + + orig_ctx = ctx; + ctx.Esp = PtrToUlong( stack ); + ctx.Eip = pLdrSystemDllInitBlock->pKiUserCallbackDispatcher; + NtSetInformationThread( GetCurrentThread(), ThreadWow64Context, &ctx, sizeof(ctx) ); + + if (!__wine_setjmpex( &frame.jmpbuf, NULL )) + cpu_simulate(); + else + NtSetInformationThread( GetCurrentThread(), ThreadWow64Context, + &orig_ctx, sizeof(orig_ctx) ); + } + break; + + case IMAGE_FILE_MACHINE_ARMNT: + { + ARM_CONTEXT orig_ctx, ctx = { CONTEXT_ARM_FULL }; + void *args_data; + + NtQueryInformationThread( GetCurrentThread(), ThreadWow64Context, &ctx, sizeof(ctx), NULL ); + + args_data = ULongToPtr( (ctx.Sp - len) & ~15 ); + memcpy( args_data, args, len ); + + ctx.R0 = id; + ctx.R1 = PtrToUlong( args ); + ctx.R2 = len; + ctx.Sp = PtrToUlong( args_data ); + ctx.Pc = pLdrSystemDllInitBlock->pKiUserCallbackDispatcher; + NtSetInformationThread( GetCurrentThread(), ThreadWow64Context, &ctx, sizeof(ctx) ); + + if (!__wine_setjmpex( &frame.jmpbuf, NULL )) + cpu_simulate(); + else + NtSetInformationThread( GetCurrentThread(), ThreadWow64Context, + &orig_ctx, sizeof(orig_ctx) ); + } + break; + } + + NtCurrentTeb()->TlsSlots[WOW64_TLS_USERCALLBACKDATA] = frame.prev_frame; + NtCurrentTeb()->TlsSlots[WOW64_TLS_TEMPLIST] = frame.temp_list; + return frame.status; +} + + /********************************************************************** * Wow64LdrpInitialize (wow64.@) */ diff --git a/dlls/wow64/syscall.h b/dlls/wow64/syscall.h index cb8fed9b99c..1e122e97314 100644 --- a/dlls/wow64/syscall.h +++ b/dlls/wow64/syscall.h @@ -37,6 +37,7 @@ SYSCALL_ENTRY( NtAllocateVirtualMemoryEx ) \ SYSCALL_ENTRY( NtAreMappedFilesTheSame ) \ SYSCALL_ENTRY( NtAssignProcessToJobObject ) \ + SYSCALL_ENTRY( NtCallbackReturn ) \ SYSCALL_ENTRY( NtCancelIoFile ) \ SYSCALL_ENTRY( NtCancelIoFileEx ) \ SYSCALL_ENTRY( NtCancelTimer ) \ diff --git a/dlls/wow64/wow64.spec b/dlls/wow64/wow64.spec index 5c3f39c50f1..e05a608d319 100644 --- a/dlls/wow64/wow64.spec +++ b/dlls/wow64/wow64.spec @@ -9,7 +9,7 @@ @ stub Wow64GetWow64ImageOption @ stub Wow64IsControlFlowGuardEnforced @ stub Wow64IsStackExtentsCheckEnforced -@ stub Wow64KiUserCallbackDispatcher +@ stdcall Wow64KiUserCallbackDispatcher(long ptr long ptr ptr) @ stdcall Wow64LdrpInitialize(ptr) @ stub Wow64LogPrint @ stub Wow64NotifyUnsimulateComplete diff --git a/include/winternl.h b/include/winternl.h index 5c2a1c07aeb..5b6ba98be42 100644 --- a/include/winternl.h +++ b/include/winternl.h @@ -1080,9 +1080,10 @@ typedef struct _TEB64 } TEB64;
/* reserved TEB64 TLS slots for Wow64 */ -#define WOW64_TLS_CPURESERVED 1 -#define WOW64_TLS_TEMPLIST 3 -#define WOW64_TLS_FILESYSREDIR 8 +#define WOW64_TLS_CPURESERVED 1 +#define WOW64_TLS_TEMPLIST 3 +#define WOW64_TLS_USERCALLBACKDATA 5 +#define WOW64_TLS_FILESYSREDIR 8
/***********************************************************************