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;
39 ULONG_PTR highest_user_address
= 0x7ffeffff;
40 ULONG_PTR default_zero_bits
= 0x7fffffff;
42 typedef NTSTATUS (WINAPI
*syscall_thunk
)( UINT
*args
);
44 static const syscall_thunk syscall_thunks
[] =
46 #define SYSCALL_ENTRY(func) wow64_ ## func,
51 static const char *syscall_names
[] =
53 #define SYSCALL_ENTRY(func) #func,
58 static const SYSTEM_SERVICE_TABLE ntdll_syscall_table
=
60 (ULONG_PTR
*)syscall_thunks
,
61 (ULONG_PTR
*)syscall_names
,
62 ARRAY_SIZE(syscall_thunks
)
65 static SYSTEM_SERVICE_TABLE syscall_tables
[4];
67 /* header for Wow64AllocTemp blocks; probably not the right layout */
70 struct mem_header
*next
;
75 /* stack frame for user callbacks */
76 struct user_callback_frame
78 struct user_callback_frame
*prev_frame
;
79 struct mem_header
*temp_list
;
83 __wine_jmp_buf jmpbuf
;
87 SYSTEM_DLL_INIT_BLOCK
*pLdrSystemDllInitBlock
= NULL
;
89 /* wow64win syscall table */
90 static const SYSTEM_SERVICE_TABLE
*psdwhwin32
;
92 /* cpu backend dll functions */
93 static void * (WINAPI
*pBTCpuGetBopCode
)(void);
94 static void (WINAPI
*pBTCpuProcessInit
)(void);
95 static void (WINAPI
*pBTCpuSimulate
)(void);
96 static NTSTATUS (WINAPI
*pBTCpuResetToConsistentState
)( EXCEPTION_POINTERS
* );
99 void *dummy
= RtlUnwind
;
101 BOOL WINAPI
DllMain( HINSTANCE inst
, DWORD reason
, void *reserved
)
103 if (reason
== DLL_PROCESS_ATTACH
) LdrDisableThreadCalloutsForDll( inst
);
107 void __cdecl
__wine_spec_unimplemented_stub( const char *module
, const char *function
)
109 EXCEPTION_RECORD record
;
111 record
.ExceptionCode
= EXCEPTION_WINE_STUB
;
112 record
.ExceptionFlags
= EH_NONCONTINUABLE
;
113 record
.ExceptionRecord
= NULL
;
114 record
.ExceptionAddress
= __wine_spec_unimplemented_stub
;
115 record
.NumberParameters
= 2;
116 record
.ExceptionInformation
[0] = (ULONG_PTR
)module
;
117 record
.ExceptionInformation
[1] = (ULONG_PTR
)function
;
118 for (;;) RtlRaiseException( &record
);
122 /**********************************************************************
125 NTSTATUS WINAPI
wow64_NtAddAtom( UINT
*args
)
127 const WCHAR
*name
= get_ptr( &args
);
128 ULONG len
= get_ulong( &args
);
129 RTL_ATOM
*atom
= get_ptr( &args
);
131 return NtAddAtom( name
, len
, atom
);
135 /**********************************************************************
136 * wow64_NtAllocateLocallyUniqueId
138 NTSTATUS WINAPI
wow64_NtAllocateLocallyUniqueId( UINT
*args
)
140 LUID
*luid
= get_ptr( &args
);
142 return NtAllocateLocallyUniqueId( luid
);
146 /**********************************************************************
147 * wow64_NtAllocateUuids
149 NTSTATUS WINAPI
wow64_NtAllocateUuids( UINT
*args
)
151 ULARGE_INTEGER
*time
= get_ptr( &args
);
152 ULONG
*delta
= get_ptr( &args
);
153 ULONG
*sequence
= get_ptr( &args
);
154 UCHAR
*seed
= get_ptr( &args
);
156 return NtAllocateUuids( time
, delta
, sequence
, seed
);
160 /***********************************************************************
161 * wow64_NtCallbackReturn
163 NTSTATUS WINAPI
wow64_NtCallbackReturn( UINT
*args
)
165 void *ret_ptr
= get_ptr( &args
);
166 ULONG ret_len
= get_ulong( &args
);
167 NTSTATUS status
= get_ulong( &args
);
169 struct user_callback_frame
*frame
= NtCurrentTeb()->TlsSlots
[WOW64_TLS_USERCALLBACKDATA
];
171 if (!frame
) return STATUS_NO_CALLBACK_ACTIVE
;
173 *frame
->ret_ptr
= ret_ptr
;
174 *frame
->ret_len
= ret_len
;
175 frame
->status
= status
;
176 __wine_longjmp( &frame
->jmpbuf
, 1 );
180 /**********************************************************************
183 NTSTATUS WINAPI
wow64_NtClose( UINT
*args
)
185 HANDLE handle
= get_handle( &args
);
187 return NtClose( handle
);
191 /**********************************************************************
194 NTSTATUS WINAPI
wow64_NtDeleteAtom( UINT
*args
)
196 RTL_ATOM atom
= get_ulong( &args
);
198 return NtDeleteAtom( atom
);
202 /**********************************************************************
205 NTSTATUS WINAPI
wow64_NtFindAtom( UINT
*args
)
207 const WCHAR
*name
= get_ptr( &args
);
208 ULONG len
= get_ulong( &args
);
209 RTL_ATOM
*atom
= get_ptr( &args
);
211 return NtFindAtom( name
, len
, atom
);
215 /**********************************************************************
216 * wow64_NtGetCurrentProcessorNumber
218 NTSTATUS WINAPI
wow64_NtGetCurrentProcessorNumber( UINT
*args
)
220 return NtGetCurrentProcessorNumber();
224 /**********************************************************************
225 * wow64_NtQueryDefaultLocale
227 NTSTATUS WINAPI
wow64_NtQueryDefaultLocale( UINT
*args
)
229 BOOLEAN user
= get_ulong( &args
);
230 LCID
*lcid
= get_ptr( &args
);
232 return NtQueryDefaultLocale( user
, lcid
);
236 /**********************************************************************
237 * wow64_NtQueryDefaultUILanguage
239 NTSTATUS WINAPI
wow64_NtQueryDefaultUILanguage( UINT
*args
)
241 LANGID
*lang
= get_ptr( &args
);
243 return NtQueryDefaultUILanguage( lang
);
247 /**********************************************************************
248 * wow64_NtQueryInformationAtom
250 NTSTATUS WINAPI
wow64_NtQueryInformationAtom( UINT
*args
)
252 RTL_ATOM atom
= get_ulong( &args
);
253 ATOM_INFORMATION_CLASS
class = get_ulong( &args
);
254 void *info
= get_ptr( &args
);
255 ULONG len
= get_ulong( &args
);
256 ULONG
*retlen
= get_ptr( &args
);
258 if (class != AtomBasicInformation
) FIXME( "class %u not supported\n", class );
259 return NtQueryInformationAtom( atom
, class, info
, len
, retlen
);
263 /**********************************************************************
264 * wow64_NtQueryInstallUILanguage
266 NTSTATUS WINAPI
wow64_NtQueryInstallUILanguage( UINT
*args
)
268 LANGID
*lang
= get_ptr( &args
);
270 return NtQueryInstallUILanguage( lang
);
274 /**********************************************************************
275 * wow64_NtSetDebugFilterState
277 NTSTATUS WINAPI
wow64_NtSetDebugFilterState( UINT
*args
)
279 ULONG component_id
= get_ulong( &args
);
280 ULONG level
= get_ulong( &args
);
281 BOOLEAN state
= get_ulong( &args
);
283 return NtSetDebugFilterState( component_id
, level
, state
);
287 /**********************************************************************
288 * wow64_NtSetDefaultLocale
290 NTSTATUS WINAPI
wow64_NtSetDefaultLocale( UINT
*args
)
292 BOOLEAN user
= get_ulong( &args
);
293 LCID lcid
= get_ulong( &args
);
295 return NtSetDefaultLocale( user
, lcid
);
299 /**********************************************************************
300 * wow64_NtSetDefaultUILanguage
302 NTSTATUS WINAPI
wow64_NtSetDefaultUILanguage( UINT
*args
)
304 LANGID lang
= get_ulong( &args
);
306 return NtSetDefaultUILanguage( lang
);
310 /**********************************************************************
311 * wow64___wine_dbg_write
313 NTSTATUS WINAPI
wow64___wine_dbg_write( UINT
*args
)
315 const char *str
= get_ptr( &args
);
316 ULONG len
= get_ulong( &args
);
318 return __wine_dbg_write( str
, len
);
322 /**********************************************************************
323 * wow64___wine_unix_call
325 NTSTATUS WINAPI
wow64___wine_unix_call( UINT
*args
)
327 unixlib_handle_t handle
= get_ulong64( &args
);
328 unsigned int code
= get_ulong( &args
);
329 void *args_ptr
= get_ptr( &args
);
331 return __wine_unix_call( handle
, code
, args_ptr
);
335 /**********************************************************************
336 * wow64___wine_unix_spawnvp
338 NTSTATUS WINAPI
wow64___wine_unix_spawnvp( UINT
*args
)
340 ULONG
*argv32
= get_ptr( &args
);
341 int wait
= get_ulong( &args
);
343 unsigned int i
, count
= 0;
346 while (argv32
[count
]) count
++;
347 argv
= Wow64AllocateTemp( (count
+ 1) * sizeof(*argv
) );
348 for (i
= 0; i
< count
; i
++) argv
[i
] = ULongToPtr( argv32
[i
] );
350 return __wine_unix_spawnvp( argv
, wait
);
354 /**********************************************************************
355 * wow64_wine_server_call
357 NTSTATUS WINAPI
wow64_wine_server_call( UINT
*args
)
359 struct __server_request_info32
*req32
= get_ptr( &args
);
363 struct __server_request_info req
;
365 req
.u
.req
= req32
->u
.req
;
366 req
.data_count
= req32
->data_count
;
367 for (i
= 0; i
< req
.data_count
; i
++)
369 req
.data
[i
].ptr
= ULongToPtr( req32
->data
[i
].ptr
);
370 req
.data
[i
].size
= req32
->data
[i
].size
;
372 req
.reply_data
= ULongToPtr( req32
->reply_data
);
373 status
= wine_server_call( &req
);
374 req32
->u
.reply
= req
.u
.reply
;
379 /**********************************************************************
382 static DWORD
get_syscall_num( const BYTE
*syscall
)
386 if (!syscall
) return id
;
387 switch (current_machine
)
389 case IMAGE_FILE_MACHINE_I386
:
390 if (syscall
[0] == 0xb8 && syscall
[5] == 0xba && syscall
[10] == 0xff && syscall
[11] == 0xd2)
391 id
= *(DWORD
*)(syscall
+ 1);
394 case IMAGE_FILE_MACHINE_ARMNT
:
395 if (*(WORD
*)syscall
== 0xb40f)
397 DWORD inst
= *(DWORD
*)((WORD
*)syscall
+ 1);
398 id
= ((inst
<< 1) & 0x0800) + ((inst
<< 12) & 0xf000) +
399 ((inst
>> 20) & 0x0700) + ((inst
>> 16) & 0x00ff);
407 /**********************************************************************
410 void init_image_mapping( HMODULE module
)
412 void **ptr
= RtlFindExportedRoutineByName( module
, "Wow64Transition" );
414 if (ptr
) *ptr
= pBTCpuGetBopCode();
418 /**********************************************************************
421 static void init_syscall_table( HMODULE module
, ULONG idx
, const SYSTEM_SERVICE_TABLE
*orig_table
)
423 static syscall_thunk thunks
[2048];
424 static ULONG start_pos
;
426 const IMAGE_EXPORT_DIRECTORY
*exports
;
427 const ULONG
*functions
, *names
;
428 const USHORT
*ordinals
;
429 ULONG id
, exp_size
, exp_pos
, wrap_pos
, max_pos
= 0;
430 const char **syscall_names
= (const char **)orig_table
->CounterTable
;
432 exports
= RtlImageDirectoryEntryToData( module
, TRUE
, IMAGE_DIRECTORY_ENTRY_EXPORT
, &exp_size
);
433 ordinals
= get_rva( module
, exports
->AddressOfNameOrdinals
);
434 functions
= get_rva( module
, exports
->AddressOfFunctions
);
435 names
= get_rva( module
, exports
->AddressOfNames
);
437 for (exp_pos
= wrap_pos
= 0; exp_pos
< exports
->NumberOfNames
; exp_pos
++)
439 char *name
= get_rva( module
, names
[exp_pos
] );
442 if (strncmp( name
, "Nt", 2 ) && strncmp( name
, "wine", 4 ) && strncmp( name
, "__wine", 6 ))
443 continue; /* not a syscall */
445 if ((id
= get_syscall_num( get_rva( module
, functions
[ordinals
[exp_pos
]] ))) == ~0u)
446 continue; /* not a syscall */
448 if (wrap_pos
< orig_table
->ServiceLimit
) res
= strcmp( name
, syscall_names
[wrap_pos
] );
450 if (!res
) /* got a match */
452 ULONG table_idx
= (id
>> 12) & 3, table_pos
= id
& 0xfff;
453 if (table_idx
== idx
)
455 if (start_pos
+ table_pos
< ARRAY_SIZE(thunks
))
457 thunks
[start_pos
+ table_pos
] = (syscall_thunk
)orig_table
->ServiceTable
[wrap_pos
++];
458 max_pos
= max( table_pos
, max_pos
);
460 else ERR( "invalid syscall id %04lx for %s\n", id
, name
);
462 else ERR( "wrong syscall table id %04lx for %s\n", id
, name
);
466 FIXME( "no export for syscall %s\n", syscall_names
[wrap_pos
] );
468 exp_pos
--; /* try again */
470 else FIXME( "missing wrapper for syscall %04lx %s\n", id
, name
);
473 for ( ; wrap_pos
< orig_table
->ServiceLimit
; wrap_pos
++)
474 FIXME( "no export for syscall %s\n", syscall_names
[wrap_pos
] );
476 syscall_tables
[idx
].ServiceTable
= (ULONG_PTR
*)(thunks
+ start_pos
);
477 syscall_tables
[idx
].ServiceLimit
= max_pos
+ 1;
478 start_pos
+= max_pos
+ 1;
482 /**********************************************************************
485 static HMODULE
load_64bit_module( const WCHAR
*name
)
490 WCHAR path
[MAX_PATH
];
491 const WCHAR
*dir
= get_machine_wow64_dir( IMAGE_FILE_MACHINE_TARGET_HOST
);
493 swprintf( path
, MAX_PATH
, L
"%s\\%s", dir
, name
);
494 RtlInitUnicodeString( &str
, path
);
495 if ((status
= LdrLoadDll( dir
, 0, &str
, &module
)))
497 ERR( "failed to load dll %lx\n", status
);
498 NtTerminateProcess( GetCurrentProcess(), status
);
504 /**********************************************************************
507 static HMODULE
load_32bit_module( const WCHAR
*name
)
511 WCHAR path
[MAX_PATH
];
512 HANDLE file
, mapping
;
515 OBJECT_ATTRIBUTES attr
;
518 const WCHAR
*dir
= get_machine_wow64_dir( current_machine
);
520 swprintf( path
, MAX_PATH
, L
"%s\\%s", dir
, name
);
521 RtlInitUnicodeString( &str
, path
);
522 InitializeObjectAttributes( &attr
, &str
, OBJ_CASE_INSENSITIVE
, 0, NULL
);
523 if ((status
= NtOpenFile( &file
, GENERIC_READ
| SYNCHRONIZE
, &attr
, &io
,
524 FILE_SHARE_READ
| FILE_SHARE_DELETE
,
525 FILE_SYNCHRONOUS_IO_NONALERT
| FILE_NON_DIRECTORY_FILE
))) goto failed
;
528 status
= NtCreateSection( &mapping
, STANDARD_RIGHTS_REQUIRED
| SECTION_QUERY
|
529 SECTION_MAP_READ
| SECTION_MAP_EXECUTE
,
530 NULL
, &size
, PAGE_EXECUTE_READ
, SEC_IMAGE
, file
);
532 if (status
) goto failed
;
534 status
= NtMapViewOfSection( mapping
, GetCurrentProcess(), &module
, 0, 0, NULL
, &len
,
535 ViewShare
, 0, PAGE_EXECUTE_READ
);
537 if (!status
) return module
;
540 ERR( "failed to load dll %lx\n", status
);
541 NtTerminateProcess( GetCurrentProcess(), status
);
546 /**********************************************************************
549 static const WCHAR
*get_cpu_dll_name(void)
551 switch (current_machine
)
553 case IMAGE_FILE_MACHINE_I386
:
554 return (native_machine
== IMAGE_FILE_MACHINE_ARM64
? L
"xtajit.dll" : L
"wow64cpu.dll");
555 case IMAGE_FILE_MACHINE_ARMNT
:
556 return L
"wowarmhw.dll";
558 ERR( "unsupported machine %04x\n", current_machine
);
559 RtlExitUserProcess( 1 );
564 /**********************************************************************
567 static DWORD WINAPI
process_init( RTL_RUN_ONCE
*once
, void *param
, void **context
)
571 SYSTEM_BASIC_INFORMATION info
;
573 RtlWow64GetProcessMachines( GetCurrentProcess(), ¤t_machine
, &native_machine
);
574 if (!current_machine
) current_machine
= native_machine
;
575 args_alignment
= (current_machine
== IMAGE_FILE_MACHINE_I386
) ? sizeof(ULONG
) : sizeof(ULONG64
);
576 NtQuerySystemInformation( SystemEmulationBasicInformation
, &info
, sizeof(info
), NULL
);
577 highest_user_address
= (ULONG_PTR
)info
.HighestUserAddress
;
578 default_zero_bits
= (ULONG_PTR
)info
.HighestUserAddress
| 0x7fffffff;
580 #define GET_PTR(name) p ## name = RtlFindExportedRoutineByName( module, #name )
582 RtlInitUnicodeString( &str
, L
"ntdll.dll" );
583 LdrGetDllHandle( NULL
, 0, &str
, &module
);
584 GET_PTR( LdrSystemDllInitBlock
);
586 module
= load_64bit_module( get_cpu_dll_name() );
587 GET_PTR( BTCpuGetBopCode
);
588 GET_PTR( BTCpuProcessInit
);
589 GET_PTR( BTCpuResetToConsistentState
);
590 GET_PTR( BTCpuSimulate
);
592 module
= load_64bit_module( L
"wow64win.dll" );
593 GET_PTR( sdwhwin32
);
597 module
= (HMODULE
)(ULONG_PTR
)pLdrSystemDllInitBlock
->ntdll_handle
;
598 init_image_mapping( module
);
599 init_syscall_table( module
, 0, &ntdll_syscall_table
);
600 *(void **)RtlFindExportedRoutineByName( module
, "__wine_syscall_dispatcher" ) = pBTCpuGetBopCode();
602 module
= load_32bit_module( L
"win32u.dll" );
603 init_syscall_table( module
, 1, psdwhwin32
);
604 NtUnmapViewOfSection( GetCurrentProcess(), module
);
606 init_file_redirects();
613 /**********************************************************************
616 static void thread_init(void)
618 /* update initial context to jump to 32-bit LdrInitializeThunk (cf. 32-bit call_init_thunk) */
619 switch (current_machine
)
621 case IMAGE_FILE_MACHINE_I386
:
623 I386_CONTEXT
*ctx_ptr
, ctx
= { CONTEXT_I386_ALL
};
626 NtQueryInformationThread( GetCurrentThread(), ThreadWow64Context
, &ctx
, sizeof(ctx
), NULL
);
627 ctx_ptr
= (I386_CONTEXT
*)ULongToPtr( ctx
.Esp
) - 1;
630 stack
= (ULONG
*)ctx_ptr
;
634 *(--stack
) = PtrToUlong( ctx_ptr
);
635 *(--stack
) = 0xdeadbabe;
636 ctx
.Esp
= PtrToUlong( stack
);
637 ctx
.Eip
= pLdrSystemDllInitBlock
->pLdrInitializeThunk
;
638 NtSetInformationThread( GetCurrentThread(), ThreadWow64Context
, &ctx
, sizeof(ctx
) );
642 case IMAGE_FILE_MACHINE_ARMNT
:
644 ARM_CONTEXT
*ctx_ptr
, ctx
= { CONTEXT_ARM_ALL
};
646 NtQueryInformationThread( GetCurrentThread(), ThreadWow64Context
, &ctx
, sizeof(ctx
), NULL
);
647 ctx_ptr
= (ARM_CONTEXT
*)ULongToPtr( ctx
.Sp
& ~15 ) - 1;
650 ctx
.R0
= PtrToUlong( ctx_ptr
);
651 ctx
.Sp
= PtrToUlong( ctx_ptr
);
652 ctx
.Pc
= pLdrSystemDllInitBlock
->pLdrInitializeThunk
;
653 NtSetInformationThread( GetCurrentThread(), ThreadWow64Context
, &ctx
, sizeof(ctx
) );
658 ERR( "not supported machine %x\n", current_machine
);
659 NtTerminateProcess( GetCurrentProcess(), STATUS_INVALID_IMAGE_FORMAT
);
664 /**********************************************************************
667 static void free_temp_data(void)
669 struct mem_header
*next
, *mem
;
671 for (mem
= NtCurrentTeb()->TlsSlots
[WOW64_TLS_TEMPLIST
]; mem
; mem
= next
)
674 RtlFreeHeap( GetProcessHeap(), 0, mem
);
676 NtCurrentTeb()->TlsSlots
[WOW64_TLS_TEMPLIST
] = NULL
;
680 /**********************************************************************
683 static LONG CALLBACK
syscall_filter( EXCEPTION_POINTERS
*ptrs
)
685 switch (ptrs
->ExceptionRecord
->ExceptionCode
)
687 case STATUS_INVALID_HANDLE
:
688 Wow64PassExceptionToGuest( ptrs
);
691 return EXCEPTION_EXECUTE_HANDLER
;
695 /**********************************************************************
696 * Wow64SystemServiceEx (wow64.@)
698 NTSTATUS WINAPI
Wow64SystemServiceEx( UINT num
, UINT
*args
)
701 UINT id
= num
& 0xfff;
702 const SYSTEM_SERVICE_TABLE
*table
= &syscall_tables
[(num
>> 12) & 3];
704 if (id
>= table
->ServiceLimit
|| !table
->ServiceTable
[id
])
706 ERR( "unsupported syscall %04x\n", num
);
707 return STATUS_INVALID_SYSTEM_SERVICE
;
711 syscall_thunk thunk
= (syscall_thunk
)table
->ServiceTable
[id
];
712 status
= thunk( args
);
714 __EXCEPT( syscall_filter
)
716 status
= GetExceptionCode();
724 /**********************************************************************
727 static LONG CALLBACK
simulate_filter( EXCEPTION_POINTERS
*ptrs
)
729 Wow64PassExceptionToGuest( ptrs
);
730 return EXCEPTION_EXECUTE_HANDLER
;
734 /**********************************************************************
737 static void cpu_simulate(void)
745 __EXCEPT( simulate_filter
)
747 /* restart simulation loop */
754 /**********************************************************************
755 * Wow64AllocateTemp (wow64.@)
757 * FIXME: probably not 100% compatible.
759 void * WINAPI
Wow64AllocateTemp( SIZE_T size
)
761 struct mem_header
*mem
;
763 if (!(mem
= RtlAllocateHeap( GetProcessHeap(), 0, offsetof( struct mem_header
, data
[size
] ))))
765 mem
->next
= NtCurrentTeb()->TlsSlots
[WOW64_TLS_TEMPLIST
];
766 NtCurrentTeb()->TlsSlots
[WOW64_TLS_TEMPLIST
] = mem
;
771 /**********************************************************************
772 * Wow64ApcRoutine (wow64.@)
774 void WINAPI
Wow64ApcRoutine( ULONG_PTR arg1
, ULONG_PTR arg2
, ULONG_PTR arg3
, CONTEXT
*context
)
779 retval
= context
->Rax
;
780 #elif defined(__aarch64__)
781 retval
= context
->X0
;
784 /* cf. 32-bit call_user_apc_dispatcher */
785 switch (current_machine
)
787 case IMAGE_FILE_MACHINE_I386
:
789 struct apc_stack_layout
797 I386_CONTEXT context
;
799 I386_CONTEXT ctx
= { CONTEXT_I386_FULL
};
801 NtQueryInformationThread( GetCurrentThread(), ThreadWow64Context
, &ctx
, sizeof(ctx
), NULL
);
802 stack
= (struct apc_stack_layout
*)ULongToPtr( ctx
.Esp
& ~3 ) - 1;
803 stack
->context_ptr
= PtrToUlong( &stack
->context
);
804 stack
->func
= arg1
>> 32;
808 stack
->context
= ctx
;
809 stack
->context
.Eax
= retval
;
810 ctx
.Esp
= PtrToUlong( stack
);
811 ctx
.Eip
= pLdrSystemDllInitBlock
->pKiUserApcDispatcher
;
812 NtSetInformationThread( GetCurrentThread(), ThreadWow64Context
, &ctx
, sizeof(ctx
) );
816 case IMAGE_FILE_MACHINE_ARMNT
:
818 struct apc_stack_layout
824 ARM_CONTEXT ctx
= { CONTEXT_ARM_FULL
};
826 NtQueryInformationThread( GetCurrentThread(), ThreadWow64Context
, &ctx
, sizeof(ctx
), NULL
);
827 stack
= (struct apc_stack_layout
*)ULongToPtr( ctx
.Sp
& ~15 ) - 1;
828 stack
->func
= arg1
>> 32;
829 stack
->context
= ctx
;
830 stack
->context
.R0
= retval
;
831 ctx
.Sp
= PtrToUlong( stack
);
832 ctx
.Pc
= pLdrSystemDllInitBlock
->pKiUserApcDispatcher
;
833 ctx
.R0
= PtrToUlong( &stack
->context
);
837 NtSetInformationThread( GetCurrentThread(), ThreadWow64Context
, &ctx
, sizeof(ctx
) );
844 /**********************************************************************
845 * Wow64KiUserCallbackDispatcher (wow64.@)
847 NTSTATUS WINAPI
Wow64KiUserCallbackDispatcher( ULONG id
, void *args
, ULONG len
,
848 void **ret_ptr
, ULONG
*ret_len
)
850 TEB32
*teb32
= (TEB32
*)((char *)NtCurrentTeb() + NtCurrentTeb()->WowTebOffset
);
851 ULONG teb_frame
= teb32
->Tib
.ExceptionList
;
852 struct user_callback_frame frame
;
854 frame
.prev_frame
= NtCurrentTeb()->TlsSlots
[WOW64_TLS_USERCALLBACKDATA
];
855 frame
.temp_list
= NtCurrentTeb()->TlsSlots
[WOW64_TLS_TEMPLIST
];
856 frame
.ret_ptr
= ret_ptr
;
857 frame
.ret_len
= ret_len
;
859 NtCurrentTeb()->TlsSlots
[WOW64_TLS_USERCALLBACKDATA
] = &frame
;
860 NtCurrentTeb()->TlsSlots
[WOW64_TLS_TEMPLIST
] = NULL
;
862 /* cf. 32-bit KeUserModeCallback */
863 switch (current_machine
)
865 case IMAGE_FILE_MACHINE_I386
:
867 I386_CONTEXT orig_ctx
, *ctx
;
871 RtlWow64GetCurrentCpuArea( NULL
, (void **)&ctx
, NULL
);
874 stack
= args_data
= ULongToPtr( (ctx
->Esp
- len
) & ~15 );
875 memcpy( args_data
, args
, len
);
878 *(--stack
) = PtrToUlong( args_data
);
880 *(--stack
) = 0xdeadbabe;
882 ctx
->Esp
= PtrToUlong( stack
);
883 ctx
->Eip
= pLdrSystemDllInitBlock
->pKiUserCallbackDispatcher
;
885 if (!__wine_setjmpex( &frame
.jmpbuf
, NULL
))
892 case IMAGE_FILE_MACHINE_ARMNT
:
894 ARM_CONTEXT orig_ctx
, ctx
= { CONTEXT_ARM_FULL
};
897 NtQueryInformationThread( GetCurrentThread(), ThreadWow64Context
, &ctx
, sizeof(ctx
), NULL
);
899 args_data
= ULongToPtr( (ctx
.Sp
- len
) & ~15 );
900 memcpy( args_data
, args
, len
);
903 ctx
.R1
= PtrToUlong( args
);
905 ctx
.Sp
= PtrToUlong( args_data
);
906 ctx
.Pc
= pLdrSystemDllInitBlock
->pKiUserCallbackDispatcher
;
907 NtSetInformationThread( GetCurrentThread(), ThreadWow64Context
, &ctx
, sizeof(ctx
) );
909 if (!__wine_setjmpex( &frame
.jmpbuf
, NULL
))
912 NtSetInformationThread( GetCurrentThread(), ThreadWow64Context
,
913 &orig_ctx
, sizeof(orig_ctx
) );
918 teb32
->Tib
.ExceptionList
= teb_frame
;
919 NtCurrentTeb()->TlsSlots
[WOW64_TLS_USERCALLBACKDATA
] = frame
.prev_frame
;
920 NtCurrentTeb()->TlsSlots
[WOW64_TLS_TEMPLIST
] = frame
.temp_list
;
925 /**********************************************************************
926 * Wow64LdrpInitialize (wow64.@)
928 void WINAPI
Wow64LdrpInitialize( CONTEXT
*context
)
930 static RTL_RUN_ONCE init_done
;
932 RtlRunOnceExecuteOnce( &init_done
, process_init
, NULL
, NULL
);
938 /**********************************************************************
939 * Wow64PrepareForException (wow64.@)
941 void WINAPI
Wow64PrepareForException( EXCEPTION_RECORD
*rec
, CONTEXT
*context
)
943 EXCEPTION_POINTERS ptrs
= { rec
, context
};
945 pBTCpuResetToConsistentState( &ptrs
);