2 * WoW64 syscall wrapping
4 * Copyright 2021 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #define WIN32_NO_STATUS
29 #include "wine/exception.h"
30 #include "wine/unixlib.h"
31 #include "wow64_private.h"
32 #include "wine/debug.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(wow
);
36 USHORT native_machine
= 0;
37 USHORT current_machine
= 0;
38 ULONG_PTR args_alignment
= 0;
40 typedef NTSTATUS (WINAPI
*syscall_thunk
)( UINT
*args
);
42 static const syscall_thunk syscall_thunks
[] =
44 #define SYSCALL_ENTRY(func) wow64_ ## func,
49 static const char *syscall_names
[] =
51 #define SYSCALL_ENTRY(func) #func,
56 static const SYSTEM_SERVICE_TABLE ntdll_syscall_table
=
58 (ULONG_PTR
*)syscall_thunks
,
59 (ULONG_PTR
*)syscall_names
,
60 ARRAY_SIZE(syscall_thunks
)
63 static SYSTEM_SERVICE_TABLE syscall_tables
[4];
65 /* header for Wow64AllocTemp blocks; probably not the right layout */
68 struct mem_header
*next
;
73 /* stack frame for user callbacks */
74 struct user_callback_frame
76 struct user_callback_frame
*prev_frame
;
77 struct mem_header
*temp_list
;
81 __wine_jmp_buf jmpbuf
;
85 SYSTEM_DLL_INIT_BLOCK
*pLdrSystemDllInitBlock
= NULL
;
87 /* wow64win syscall table */
88 static const SYSTEM_SERVICE_TABLE
*psdwhwin32
;
90 /* cpu backend dll functions */
91 static void * (WINAPI
*pBTCpuGetBopCode
)(void);
92 static void (WINAPI
*pBTCpuProcessInit
)(void);
93 static void (WINAPI
*pBTCpuSimulate
)(void);
94 static NTSTATUS (WINAPI
*pBTCpuResetToConsistentState
)( EXCEPTION_POINTERS
* );
97 void *dummy
= RtlUnwind
;
99 BOOL WINAPI
DllMain( HINSTANCE inst
, DWORD reason
, void *reserved
)
101 if (reason
== DLL_PROCESS_ATTACH
) LdrDisableThreadCalloutsForDll( inst
);
105 void __cdecl
__wine_spec_unimplemented_stub( const char *module
, const char *function
)
107 EXCEPTION_RECORD record
;
109 record
.ExceptionCode
= EXCEPTION_WINE_STUB
;
110 record
.ExceptionFlags
= EH_NONCONTINUABLE
;
111 record
.ExceptionRecord
= NULL
;
112 record
.ExceptionAddress
= __wine_spec_unimplemented_stub
;
113 record
.NumberParameters
= 2;
114 record
.ExceptionInformation
[0] = (ULONG_PTR
)module
;
115 record
.ExceptionInformation
[1] = (ULONG_PTR
)function
;
116 for (;;) RtlRaiseException( &record
);
120 /**********************************************************************
123 NTSTATUS WINAPI
wow64_NtAddAtom( UINT
*args
)
125 const WCHAR
*name
= get_ptr( &args
);
126 ULONG len
= get_ulong( &args
);
127 RTL_ATOM
*atom
= get_ptr( &args
);
129 return NtAddAtom( name
, len
, atom
);
133 /**********************************************************************
134 * wow64_NtAllocateLocallyUniqueId
136 NTSTATUS WINAPI
wow64_NtAllocateLocallyUniqueId( UINT
*args
)
138 LUID
*luid
= get_ptr( &args
);
140 return NtAllocateLocallyUniqueId( luid
);
144 /**********************************************************************
145 * wow64_NtAllocateUuids
147 NTSTATUS WINAPI
wow64_NtAllocateUuids( UINT
*args
)
149 ULARGE_INTEGER
*time
= get_ptr( &args
);
150 ULONG
*delta
= get_ptr( &args
);
151 ULONG
*sequence
= get_ptr( &args
);
152 UCHAR
*seed
= get_ptr( &args
);
154 return NtAllocateUuids( time
, delta
, sequence
, seed
);
158 /***********************************************************************
159 * wow64_NtCallbackReturn
161 NTSTATUS WINAPI
wow64_NtCallbackReturn( UINT
*args
)
163 void *ret_ptr
= get_ptr( &args
);
164 ULONG ret_len
= get_ulong( &args
);
165 NTSTATUS status
= get_ulong( &args
);
167 struct user_callback_frame
*frame
= NtCurrentTeb()->TlsSlots
[WOW64_TLS_USERCALLBACKDATA
];
169 if (!frame
) return STATUS_NO_CALLBACK_ACTIVE
;
171 *frame
->ret_ptr
= ret_ptr
;
172 *frame
->ret_len
= ret_len
;
173 frame
->status
= status
;
174 __wine_longjmp( &frame
->jmpbuf
, 1 );
178 /**********************************************************************
181 NTSTATUS WINAPI
wow64_NtClose( UINT
*args
)
183 HANDLE handle
= get_handle( &args
);
185 return NtClose( handle
);
189 /**********************************************************************
192 NTSTATUS WINAPI
wow64_NtDeleteAtom( UINT
*args
)
194 RTL_ATOM atom
= get_ulong( &args
);
196 return NtDeleteAtom( atom
);
200 /**********************************************************************
203 NTSTATUS WINAPI
wow64_NtFindAtom( UINT
*args
)
205 const WCHAR
*name
= get_ptr( &args
);
206 ULONG len
= get_ulong( &args
);
207 RTL_ATOM
*atom
= get_ptr( &args
);
209 return NtFindAtom( name
, len
, atom
);
213 /**********************************************************************
214 * wow64_NtGetCurrentProcessorNumber
216 NTSTATUS WINAPI
wow64_NtGetCurrentProcessorNumber( UINT
*args
)
218 return NtGetCurrentProcessorNumber();
222 /**********************************************************************
223 * wow64_NtQueryDefaultLocale
225 NTSTATUS WINAPI
wow64_NtQueryDefaultLocale( UINT
*args
)
227 BOOLEAN user
= get_ulong( &args
);
228 LCID
*lcid
= get_ptr( &args
);
230 return NtQueryDefaultLocale( user
, lcid
);
234 /**********************************************************************
235 * wow64_NtQueryDefaultUILanguage
237 NTSTATUS WINAPI
wow64_NtQueryDefaultUILanguage( UINT
*args
)
239 LANGID
*lang
= get_ptr( &args
);
241 return NtQueryDefaultUILanguage( lang
);
245 /**********************************************************************
246 * wow64_NtQueryInformationAtom
248 NTSTATUS WINAPI
wow64_NtQueryInformationAtom( UINT
*args
)
250 RTL_ATOM atom
= get_ulong( &args
);
251 ATOM_INFORMATION_CLASS
class = get_ulong( &args
);
252 void *info
= get_ptr( &args
);
253 ULONG len
= get_ulong( &args
);
254 ULONG
*retlen
= get_ptr( &args
);
256 if (class != AtomBasicInformation
) FIXME( "class %u not supported\n", class );
257 return NtQueryInformationAtom( atom
, class, info
, len
, retlen
);
261 /**********************************************************************
262 * wow64_NtQueryInstallUILanguage
264 NTSTATUS WINAPI
wow64_NtQueryInstallUILanguage( UINT
*args
)
266 LANGID
*lang
= get_ptr( &args
);
268 return NtQueryInstallUILanguage( lang
);
272 /**********************************************************************
273 * wow64_NtSetDebugFilterState
275 NTSTATUS WINAPI
wow64_NtSetDebugFilterState( UINT
*args
)
277 ULONG component_id
= get_ulong( &args
);
278 ULONG level
= get_ulong( &args
);
279 BOOLEAN state
= get_ulong( &args
);
281 return NtSetDebugFilterState( component_id
, level
, state
);
285 /**********************************************************************
286 * wow64_NtSetDefaultLocale
288 NTSTATUS WINAPI
wow64_NtSetDefaultLocale( UINT
*args
)
290 BOOLEAN user
= get_ulong( &args
);
291 LCID lcid
= get_ulong( &args
);
293 return NtSetDefaultLocale( user
, lcid
);
297 /**********************************************************************
298 * wow64_NtSetDefaultUILanguage
300 NTSTATUS WINAPI
wow64_NtSetDefaultUILanguage( UINT
*args
)
302 LANGID lang
= get_ulong( &args
);
304 return NtSetDefaultUILanguage( lang
);
308 /**********************************************************************
309 * wow64___wine_dbg_write
311 NTSTATUS WINAPI
wow64___wine_dbg_write( UINT
*args
)
313 const char *str
= get_ptr( &args
);
314 ULONG len
= get_ulong( &args
);
316 return __wine_dbg_write( str
, len
);
320 /**********************************************************************
321 * wow64___wine_unix_call
323 NTSTATUS WINAPI
wow64___wine_unix_call( UINT
*args
)
325 unixlib_handle_t handle
= get_ulong64( &args
);
326 unsigned int code
= get_ulong( &args
);
327 void *args_ptr
= get_ptr( &args
);
329 return __wine_unix_call( handle
, code
, args_ptr
);
333 /**********************************************************************
334 * wow64___wine_unix_spawnvp
336 NTSTATUS WINAPI
wow64___wine_unix_spawnvp( UINT
*args
)
338 ULONG
*argv32
= get_ptr( &args
);
339 int wait
= get_ulong( &args
);
341 unsigned int i
, count
= 0;
344 while (argv32
[count
]) count
++;
345 argv
= Wow64AllocateTemp( (count
+ 1) * sizeof(*argv
) );
346 for (i
= 0; i
< count
; i
++) argv
[i
] = ULongToPtr( argv32
[i
] );
348 return __wine_unix_spawnvp( argv
, wait
);
352 /**********************************************************************
353 * wow64_wine_server_call
355 NTSTATUS WINAPI
wow64_wine_server_call( UINT
*args
)
357 struct __server_request_info32
*req32
= get_ptr( &args
);
361 struct __server_request_info req
;
363 req
.u
.req
= req32
->u
.req
;
364 req
.data_count
= req32
->data_count
;
365 for (i
= 0; i
< req
.data_count
; i
++)
367 req
.data
[i
].ptr
= ULongToPtr( req32
->data
[i
].ptr
);
368 req
.data
[i
].size
= req32
->data
[i
].size
;
370 req
.reply_data
= ULongToPtr( req32
->reply_data
);
371 status
= wine_server_call( &req
);
372 req32
->u
.reply
= req
.u
.reply
;
377 /**********************************************************************
380 static DWORD
get_syscall_num( const BYTE
*syscall
)
384 if (!syscall
) return id
;
385 switch (current_machine
)
387 case IMAGE_FILE_MACHINE_I386
:
388 if (syscall
[0] == 0xb8 && syscall
[5] == 0xba && syscall
[10] == 0xff && syscall
[11] == 0xd2)
389 id
= *(DWORD
*)(syscall
+ 1);
392 case IMAGE_FILE_MACHINE_ARM
:
393 if (*(WORD
*)syscall
== 0xb40f)
395 DWORD inst
= *(DWORD
*)((WORD
*)syscall
+ 1);
396 id
= ((inst
<< 1) & 0x0800) + ((inst
<< 12) & 0xf000) +
397 ((inst
>> 20) & 0x0700) + ((inst
>> 16) & 0x00ff);
405 /**********************************************************************
408 void init_image_mapping( HMODULE module
)
410 void **ptr
= RtlFindExportedRoutineByName( module
, "Wow64Transition" );
412 if (ptr
) *ptr
= pBTCpuGetBopCode();
416 /**********************************************************************
419 static void init_syscall_table( HMODULE module
, ULONG idx
, const SYSTEM_SERVICE_TABLE
*orig_table
)
421 static syscall_thunk thunks
[2048];
422 static ULONG start_pos
;
424 const IMAGE_EXPORT_DIRECTORY
*exports
;
425 const ULONG
*functions
, *names
;
426 const USHORT
*ordinals
;
427 ULONG id
, exp_size
, exp_pos
, wrap_pos
, max_pos
= 0;
428 const char **syscall_names
= (const char **)orig_table
->CounterTable
;
430 exports
= RtlImageDirectoryEntryToData( module
, TRUE
, IMAGE_DIRECTORY_ENTRY_EXPORT
, &exp_size
);
431 ordinals
= get_rva( module
, exports
->AddressOfNameOrdinals
);
432 functions
= get_rva( module
, exports
->AddressOfFunctions
);
433 names
= get_rva( module
, exports
->AddressOfNames
);
435 for (exp_pos
= wrap_pos
= 0; exp_pos
< exports
->NumberOfNames
; exp_pos
++)
437 char *name
= get_rva( module
, names
[exp_pos
] );
440 if (strncmp( name
, "Nt", 2 ) && strncmp( name
, "wine", 4 ) && strncmp( name
, "__wine", 6 ))
441 continue; /* not a syscall */
443 if ((id
= get_syscall_num( get_rva( module
, functions
[ordinals
[exp_pos
]] ))) == ~0u)
444 continue; /* not a syscall */
446 if (wrap_pos
< orig_table
->ServiceLimit
) res
= strcmp( name
, syscall_names
[wrap_pos
] );
448 if (!res
) /* got a match */
450 ULONG table_idx
= (id
>> 12) & 3, table_pos
= id
& 0xfff;
451 if (table_idx
== idx
)
453 if (start_pos
+ table_pos
< ARRAY_SIZE(thunks
))
455 thunks
[start_pos
+ table_pos
] = (syscall_thunk
)orig_table
->ServiceTable
[wrap_pos
++];
456 max_pos
= max( table_pos
, max_pos
);
458 else ERR( "invalid syscall id %04lx for %s\n", id
, name
);
460 else ERR( "wrong syscall table id %04lx for %s\n", id
, name
);
464 FIXME( "no export for syscall %s\n", syscall_names
[wrap_pos
] );
466 exp_pos
--; /* try again */
468 else FIXME( "missing wrapper for syscall %04lx %s\n", id
, name
);
471 for ( ; wrap_pos
< orig_table
->ServiceLimit
; wrap_pos
++)
472 FIXME( "no export for syscall %s\n", syscall_names
[wrap_pos
] );
474 syscall_tables
[idx
].ServiceTable
= (ULONG_PTR
*)(thunks
+ start_pos
);
475 syscall_tables
[idx
].ServiceLimit
= max_pos
+ 1;
476 start_pos
+= max_pos
+ 1;
480 /**********************************************************************
483 static HMODULE
load_64bit_module( const WCHAR
*name
)
488 WCHAR path
[MAX_PATH
];
489 const WCHAR
*dir
= get_machine_wow64_dir( IMAGE_FILE_MACHINE_TARGET_HOST
);
491 swprintf( path
, MAX_PATH
, L
"%s\\%s", dir
, name
);
492 RtlInitUnicodeString( &str
, path
);
493 if ((status
= LdrLoadDll( NULL
, 0, &str
, &module
)))
495 ERR( "failed to load dll %lx\n", status
);
496 NtTerminateProcess( GetCurrentProcess(), status
);
502 /**********************************************************************
505 static HMODULE
load_32bit_module( const WCHAR
*name
)
509 WCHAR path
[MAX_PATH
];
510 HANDLE file
, mapping
;
513 OBJECT_ATTRIBUTES attr
;
516 const WCHAR
*dir
= get_machine_wow64_dir( current_machine
);
518 swprintf( path
, MAX_PATH
, L
"%s\\%s", dir
, name
);
519 RtlInitUnicodeString( &str
, path
);
520 InitializeObjectAttributes( &attr
, &str
, OBJ_CASE_INSENSITIVE
, 0, NULL
);
521 if ((status
= NtOpenFile( &file
, GENERIC_READ
| SYNCHRONIZE
, &attr
, &io
,
522 FILE_SHARE_READ
| FILE_SHARE_DELETE
,
523 FILE_SYNCHRONOUS_IO_NONALERT
| FILE_NON_DIRECTORY_FILE
))) goto failed
;
526 status
= NtCreateSection( &mapping
, STANDARD_RIGHTS_REQUIRED
| SECTION_QUERY
|
527 SECTION_MAP_READ
| SECTION_MAP_EXECUTE
,
528 NULL
, &size
, PAGE_EXECUTE_READ
, SEC_IMAGE
, file
);
530 if (status
) goto failed
;
532 status
= NtMapViewOfSection( mapping
, GetCurrentProcess(), &module
, 0, 0, NULL
, &len
,
533 ViewShare
, 0, PAGE_EXECUTE_READ
);
535 if (!status
) return module
;
538 ERR( "failed to load dll %lx\n", status
);
539 NtTerminateProcess( GetCurrentProcess(), status
);
544 /**********************************************************************
547 static const WCHAR
*get_cpu_dll_name(void)
549 switch (current_machine
)
551 case IMAGE_FILE_MACHINE_I386
:
552 return (native_machine
== IMAGE_FILE_MACHINE_ARM64
? L
"xtajit.dll" : L
"wow64cpu.dll");
553 case IMAGE_FILE_MACHINE_ARM
:
554 return L
"wowarmhw.dll";
556 ERR( "unsupported machine %04x\n", current_machine
);
557 RtlExitUserProcess( 1 );
562 /**********************************************************************
565 static DWORD WINAPI
process_init( RTL_RUN_ONCE
*once
, void *param
, void **context
)
570 RtlWow64GetProcessMachines( GetCurrentProcess(), ¤t_machine
, &native_machine
);
571 if (!current_machine
) current_machine
= native_machine
;
572 args_alignment
= (current_machine
== IMAGE_FILE_MACHINE_I386
) ? sizeof(ULONG
) : sizeof(ULONG64
);
574 #define GET_PTR(name) p ## name = RtlFindExportedRoutineByName( module, #name )
576 RtlInitUnicodeString( &str
, L
"ntdll.dll" );
577 LdrGetDllHandle( NULL
, 0, &str
, &module
);
578 GET_PTR( LdrSystemDllInitBlock
);
580 module
= load_64bit_module( get_cpu_dll_name() );
581 GET_PTR( BTCpuGetBopCode
);
582 GET_PTR( BTCpuProcessInit
);
583 GET_PTR( BTCpuResetToConsistentState
);
584 GET_PTR( BTCpuSimulate
);
586 module
= load_64bit_module( L
"wow64win.dll" );
587 GET_PTR( sdwhwin32
);
591 module
= (HMODULE
)(ULONG_PTR
)pLdrSystemDllInitBlock
->ntdll_handle
;
592 init_image_mapping( module
);
593 init_syscall_table( module
, 0, &ntdll_syscall_table
);
594 *(void **)RtlFindExportedRoutineByName( module
, "__wine_syscall_dispatcher" ) = pBTCpuGetBopCode();
596 module
= load_32bit_module( L
"win32u.dll" );
597 init_syscall_table( module
, 1, psdwhwin32
);
598 NtUnmapViewOfSection( GetCurrentProcess(), module
);
600 init_file_redirects();
607 /**********************************************************************
610 static void thread_init(void)
612 /* update initial context to jump to 32-bit LdrInitializeThunk (cf. 32-bit call_init_thunk) */
613 switch (current_machine
)
615 case IMAGE_FILE_MACHINE_I386
:
617 I386_CONTEXT
*ctx_ptr
, ctx
= { CONTEXT_I386_ALL
};
620 NtQueryInformationThread( GetCurrentThread(), ThreadWow64Context
, &ctx
, sizeof(ctx
), NULL
);
621 ctx_ptr
= (I386_CONTEXT
*)ULongToPtr( ctx
.Esp
) - 1;
624 stack
= (ULONG
*)ctx_ptr
;
628 *(--stack
) = PtrToUlong( ctx_ptr
);
629 *(--stack
) = 0xdeadbabe;
630 ctx
.Esp
= PtrToUlong( stack
);
631 ctx
.Eip
= pLdrSystemDllInitBlock
->pLdrInitializeThunk
;
632 NtSetInformationThread( GetCurrentThread(), ThreadWow64Context
, &ctx
, sizeof(ctx
) );
636 case IMAGE_FILE_MACHINE_ARMNT
:
638 ARM_CONTEXT
*ctx_ptr
, ctx
= { CONTEXT_ARM_ALL
};
640 NtQueryInformationThread( GetCurrentThread(), ThreadWow64Context
, &ctx
, sizeof(ctx
), NULL
);
641 ctx_ptr
= (ARM_CONTEXT
*)ULongToPtr( ctx
.Sp
& ~15 ) - 1;
644 ctx
.R0
= PtrToUlong( ctx_ptr
);
645 ctx
.Sp
= PtrToUlong( ctx_ptr
);
646 ctx
.Pc
= pLdrSystemDllInitBlock
->pLdrInitializeThunk
;
647 NtSetInformationThread( GetCurrentThread(), ThreadWow64Context
, &ctx
, sizeof(ctx
) );
652 ERR( "not supported machine %x\n", current_machine
);
653 NtTerminateProcess( GetCurrentProcess(), STATUS_INVALID_IMAGE_FORMAT
);
658 /**********************************************************************
661 static void free_temp_data(void)
663 struct mem_header
*next
, *mem
;
665 for (mem
= NtCurrentTeb()->TlsSlots
[WOW64_TLS_TEMPLIST
]; mem
; mem
= next
)
668 RtlFreeHeap( GetProcessHeap(), 0, mem
);
670 NtCurrentTeb()->TlsSlots
[WOW64_TLS_TEMPLIST
] = NULL
;
674 /**********************************************************************
677 static LONG CALLBACK
syscall_filter( EXCEPTION_POINTERS
*ptrs
)
679 switch (ptrs
->ExceptionRecord
->ExceptionCode
)
681 case STATUS_INVALID_HANDLE
:
682 Wow64PassExceptionToGuest( ptrs
);
685 return EXCEPTION_EXECUTE_HANDLER
;
689 /**********************************************************************
690 * Wow64SystemServiceEx (wow64.@)
692 NTSTATUS WINAPI
Wow64SystemServiceEx( UINT num
, UINT
*args
)
695 UINT id
= num
& 0xfff;
696 const SYSTEM_SERVICE_TABLE
*table
= &syscall_tables
[(num
>> 12) & 3];
698 if (id
>= table
->ServiceLimit
|| !table
->ServiceTable
[id
])
700 ERR( "unsupported syscall %04x\n", num
);
701 return STATUS_INVALID_SYSTEM_SERVICE
;
705 syscall_thunk thunk
= (syscall_thunk
)table
->ServiceTable
[id
];
706 status
= thunk( args
);
708 __EXCEPT( syscall_filter
)
710 status
= GetExceptionCode();
718 static void cpu_simulate(void);
720 /**********************************************************************
723 static LONG CALLBACK
simulate_filter( EXCEPTION_POINTERS
*ptrs
)
725 Wow64PassExceptionToGuest( ptrs
);
726 cpu_simulate(); /* re-enter simulation to run the exception dispatcher */
727 return EXCEPTION_EXECUTE_HANDLER
;
731 /**********************************************************************
734 static void cpu_simulate(void)
742 __EXCEPT( simulate_filter
)
744 /* restart simulation loop */
751 /**********************************************************************
752 * Wow64AllocateTemp (wow64.@)
754 * FIXME: probably not 100% compatible.
756 void * WINAPI
Wow64AllocateTemp( SIZE_T size
)
758 struct mem_header
*mem
;
760 if (!(mem
= RtlAllocateHeap( GetProcessHeap(), 0, offsetof( struct mem_header
, data
[size
] ))))
762 mem
->next
= NtCurrentTeb()->TlsSlots
[WOW64_TLS_TEMPLIST
];
763 NtCurrentTeb()->TlsSlots
[WOW64_TLS_TEMPLIST
] = mem
;
768 /**********************************************************************
769 * Wow64ApcRoutine (wow64.@)
771 void WINAPI
Wow64ApcRoutine( ULONG_PTR arg1
, ULONG_PTR arg2
, ULONG_PTR arg3
, CONTEXT
*context
)
776 retval
= context
->Rax
;
777 #elif defined(__aarch64__)
778 retval
= context
->X0
;
781 /* cf. 32-bit call_user_apc_dispatcher */
782 switch (current_machine
)
784 case IMAGE_FILE_MACHINE_I386
:
786 struct apc_stack_layout
794 I386_CONTEXT context
;
796 I386_CONTEXT ctx
= { CONTEXT_I386_FULL
};
798 NtQueryInformationThread( GetCurrentThread(), ThreadWow64Context
, &ctx
, sizeof(ctx
), NULL
);
799 stack
= (struct apc_stack_layout
*)ULongToPtr( ctx
.Esp
& ~3 ) - 1;
800 stack
->context_ptr
= PtrToUlong( &stack
->context
);
801 stack
->func
= arg1
>> 32;
805 stack
->context
= ctx
;
806 stack
->context
.Eax
= retval
;
807 ctx
.Esp
= PtrToUlong( stack
);
808 ctx
.Eip
= pLdrSystemDllInitBlock
->pKiUserApcDispatcher
;
809 NtSetInformationThread( GetCurrentThread(), ThreadWow64Context
, &ctx
, sizeof(ctx
) );
813 case IMAGE_FILE_MACHINE_ARMNT
:
815 struct apc_stack_layout
821 ARM_CONTEXT ctx
= { CONTEXT_ARM_FULL
};
823 NtQueryInformationThread( GetCurrentThread(), ThreadWow64Context
, &ctx
, sizeof(ctx
), NULL
);
824 stack
= (struct apc_stack_layout
*)ULongToPtr( ctx
.Sp
& ~15 ) - 1;
825 stack
->func
= arg1
>> 32;
826 stack
->context
= ctx
;
827 stack
->context
.R0
= retval
;
828 ctx
.Sp
= PtrToUlong( stack
);
829 ctx
.Pc
= pLdrSystemDllInitBlock
->pKiUserApcDispatcher
;
830 ctx
.R0
= PtrToUlong( &stack
->context
);
834 NtSetInformationThread( GetCurrentThread(), ThreadWow64Context
, &ctx
, sizeof(ctx
) );
841 /**********************************************************************
842 * Wow64KiUserCallbackDispatcher (wow64.@)
844 NTSTATUS WINAPI
Wow64KiUserCallbackDispatcher( ULONG id
, void *args
, ULONG len
,
845 void **ret_ptr
, ULONG
*ret_len
)
847 struct user_callback_frame frame
;
849 frame
.prev_frame
= NtCurrentTeb()->TlsSlots
[WOW64_TLS_USERCALLBACKDATA
];
850 frame
.temp_list
= NtCurrentTeb()->TlsSlots
[WOW64_TLS_TEMPLIST
];
851 frame
.ret_ptr
= ret_ptr
;
852 frame
.ret_len
= ret_len
;
854 NtCurrentTeb()->TlsSlots
[WOW64_TLS_USERCALLBACKDATA
] = &frame
;
855 NtCurrentTeb()->TlsSlots
[WOW64_TLS_TEMPLIST
] = NULL
;
857 /* cf. 32-bit KeUserModeCallback */
858 switch (current_machine
)
860 case IMAGE_FILE_MACHINE_I386
:
862 I386_CONTEXT orig_ctx
, ctx
= { CONTEXT_I386_FULL
};
866 NtQueryInformationThread( GetCurrentThread(), ThreadWow64Context
, &ctx
, sizeof(ctx
), NULL
);
868 stack
= args_data
= ULongToPtr( (ctx
.Esp
- len
) & ~15 );
869 memcpy( args_data
, args
, len
);
872 *(--stack
) = PtrToUlong( args_data
);
874 *(--stack
) = 0xdeadbabe;
877 ctx
.Esp
= PtrToUlong( stack
);
878 ctx
.Eip
= pLdrSystemDllInitBlock
->pKiUserCallbackDispatcher
;
879 NtSetInformationThread( GetCurrentThread(), ThreadWow64Context
, &ctx
, sizeof(ctx
) );
881 if (!__wine_setjmpex( &frame
.jmpbuf
, NULL
))
884 NtSetInformationThread( GetCurrentThread(), ThreadWow64Context
,
885 &orig_ctx
, sizeof(orig_ctx
) );
889 case IMAGE_FILE_MACHINE_ARMNT
:
891 ARM_CONTEXT orig_ctx
, ctx
= { CONTEXT_ARM_FULL
};
894 NtQueryInformationThread( GetCurrentThread(), ThreadWow64Context
, &ctx
, sizeof(ctx
), NULL
);
896 args_data
= ULongToPtr( (ctx
.Sp
- len
) & ~15 );
897 memcpy( args_data
, args
, len
);
900 ctx
.R1
= PtrToUlong( args
);
902 ctx
.Sp
= PtrToUlong( args_data
);
903 ctx
.Pc
= pLdrSystemDllInitBlock
->pKiUserCallbackDispatcher
;
904 NtSetInformationThread( GetCurrentThread(), ThreadWow64Context
, &ctx
, sizeof(ctx
) );
906 if (!__wine_setjmpex( &frame
.jmpbuf
, NULL
))
909 NtSetInformationThread( GetCurrentThread(), ThreadWow64Context
,
910 &orig_ctx
, sizeof(orig_ctx
) );
915 NtCurrentTeb()->TlsSlots
[WOW64_TLS_USERCALLBACKDATA
] = frame
.prev_frame
;
916 NtCurrentTeb()->TlsSlots
[WOW64_TLS_TEMPLIST
] = frame
.temp_list
;
921 /**********************************************************************
922 * Wow64LdrpInitialize (wow64.@)
924 void WINAPI
Wow64LdrpInitialize( CONTEXT
*context
)
926 static RTL_RUN_ONCE init_done
;
928 RtlRunOnceExecuteOnce( &init_done
, process_init
, NULL
, NULL
);
934 /**********************************************************************
935 * Wow64PrepareForException (wow64.@)
937 void WINAPI
Wow64PrepareForException( EXCEPTION_RECORD
*rec
, CONTEXT
*context
)
939 EXCEPTION_POINTERS ptrs
= { rec
, context
};
941 pBTCpuResetToConsistentState( &ptrs
);