ntdll: Rename local variables in heap_reallocate.
[wine.git] / dlls / wow64 / syscall.c
blob7cab0894738647e66e0e4fa6f98ec10562819366
1 /*
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
21 #include <stdarg.h>
23 #include "ntstatus.h"
24 #define WIN32_NO_STATUS
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winnt.h"
28 #include "winternl.h"
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,
45 ALL_SYSCALLS
46 #undef SYSCALL_ENTRY
49 static const char *syscall_names[] =
51 #define SYSCALL_ENTRY(func) #func,
52 ALL_SYSCALLS
53 #undef SYSCALL_ENTRY
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 */
66 struct mem_header
68 struct mem_header *next;
69 void *__pad;
70 BYTE data[1];
73 /* stack frame for user callbacks */
74 struct user_callback_frame
76 struct user_callback_frame *prev_frame;
77 struct mem_header *temp_list;
78 void **ret_ptr;
79 ULONG *ret_len;
80 NTSTATUS status;
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 );
102 return TRUE;
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 /**********************************************************************
121 * wow64_NtAddAtom
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 /**********************************************************************
179 * wow64_NtClose
181 NTSTATUS WINAPI wow64_NtClose( UINT *args )
183 HANDLE handle = get_handle( &args );
185 return NtClose( handle );
189 /**********************************************************************
190 * wow64_NtDeleteAtom
192 NTSTATUS WINAPI wow64_NtDeleteAtom( UINT *args )
194 RTL_ATOM atom = get_ulong( &args );
196 return NtDeleteAtom( atom );
200 /**********************************************************************
201 * wow64_NtFindAtom
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;
342 char **argv;
344 while (argv32[count]) count++;
345 argv = Wow64AllocateTemp( (count + 1) * sizeof(*argv) );
346 for (i = 0; i < count; i++) argv[i] = ULongToPtr( argv32[i] );
347 argv[count] = NULL;
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 );
359 unsigned int i;
360 NTSTATUS status;
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;
373 return status;
377 /**********************************************************************
378 * get_syscall_num
380 static DWORD get_syscall_num( const BYTE *syscall )
382 DWORD id = ~0u;
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);
390 break;
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);
399 break;
401 return id;
405 /**********************************************************************
406 * init_image_mapping
408 void init_image_mapping( HMODULE module )
410 void **ptr = RtlFindExportedRoutineByName( module, "Wow64Transition" );
412 if (ptr) *ptr = pBTCpuGetBopCode();
416 /**********************************************************************
417 * init_syscall_table
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] );
438 int res = -1;
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 );
462 else if (res > 0)
464 FIXME( "no export for syscall %s\n", syscall_names[wrap_pos] );
465 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 /**********************************************************************
481 * load_64bit_module
483 static HMODULE load_64bit_module( const WCHAR *name )
485 NTSTATUS status;
486 HMODULE module;
487 UNICODE_STRING str;
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 );
498 return module;
502 /**********************************************************************
503 * load_32bit_module
505 static HMODULE load_32bit_module( const WCHAR *name )
507 NTSTATUS status;
508 UNICODE_STRING str;
509 WCHAR path[MAX_PATH];
510 HANDLE file, mapping;
511 LARGE_INTEGER size;
512 IO_STATUS_BLOCK io;
513 OBJECT_ATTRIBUTES attr;
514 SIZE_T len = 0;
515 void *module = NULL;
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;
525 size.QuadPart = 0;
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 );
529 NtClose( file );
530 if (status) goto failed;
532 status = NtMapViewOfSection( mapping, GetCurrentProcess(), &module, 0, 0, NULL, &len,
533 ViewShare, 0, PAGE_EXECUTE_READ );
534 NtClose( mapping );
535 if (!status) return module;
537 failed:
538 ERR( "failed to load dll %lx\n", status );
539 NtTerminateProcess( GetCurrentProcess(), status );
540 return NULL;
544 /**********************************************************************
545 * get_cpu_dll_name
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";
555 default:
556 ERR( "unsupported machine %04x\n", current_machine );
557 RtlExitUserProcess( 1 );
562 /**********************************************************************
563 * process_init
565 static DWORD WINAPI process_init( RTL_RUN_ONCE *once, void *param, void **context )
567 HMODULE module;
568 UNICODE_STRING str;
570 RtlWow64GetProcessMachines( GetCurrentProcess(), &current_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 );
589 pBTCpuProcessInit();
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();
601 return TRUE;
603 #undef GET_PTR
607 /**********************************************************************
608 * thread_init
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 };
618 ULONG *stack;
620 NtQueryInformationThread( GetCurrentThread(), ThreadWow64Context, &ctx, sizeof(ctx), NULL );
621 ctx_ptr = (I386_CONTEXT *)ULongToPtr( ctx.Esp ) - 1;
622 *ctx_ptr = ctx;
624 stack = (ULONG *)ctx_ptr;
625 *(--stack) = 0;
626 *(--stack) = 0;
627 *(--stack) = 0;
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) );
634 break;
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;
642 *ctx_ptr = ctx;
644 ctx.R0 = PtrToUlong( ctx_ptr );
645 ctx.Sp = PtrToUlong( ctx_ptr );
646 ctx.Pc = pLdrSystemDllInitBlock->pLdrInitializeThunk;
647 NtSetInformationThread( GetCurrentThread(), ThreadWow64Context, &ctx, sizeof(ctx) );
649 break;
651 default:
652 ERR( "not supported machine %x\n", current_machine );
653 NtTerminateProcess( GetCurrentProcess(), STATUS_INVALID_IMAGE_FORMAT );
658 /**********************************************************************
659 * free_temp_data
661 static void free_temp_data(void)
663 struct mem_header *next, *mem;
665 for (mem = NtCurrentTeb()->TlsSlots[WOW64_TLS_TEMPLIST]; mem; mem = next)
667 next = mem->next;
668 RtlFreeHeap( GetProcessHeap(), 0, mem );
670 NtCurrentTeb()->TlsSlots[WOW64_TLS_TEMPLIST] = NULL;
674 /**********************************************************************
675 * syscall_filter
677 static LONG CALLBACK syscall_filter( EXCEPTION_POINTERS *ptrs )
679 switch (ptrs->ExceptionRecord->ExceptionCode)
681 case STATUS_INVALID_HANDLE:
682 Wow64PassExceptionToGuest( ptrs );
683 break;
685 return EXCEPTION_EXECUTE_HANDLER;
689 /**********************************************************************
690 * Wow64SystemServiceEx (wow64.@)
692 NTSTATUS WINAPI Wow64SystemServiceEx( UINT num, UINT *args )
694 NTSTATUS status;
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;
703 __TRY
705 syscall_thunk thunk = (syscall_thunk)table->ServiceTable[id];
706 status = thunk( args );
708 __EXCEPT( syscall_filter )
710 status = GetExceptionCode();
712 __ENDTRY;
713 free_temp_data();
714 return status;
718 static void cpu_simulate(void);
720 /**********************************************************************
721 * simulate_filter
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 /**********************************************************************
732 * cpu_simulate
734 static void cpu_simulate(void)
736 for (;;)
738 __TRY
740 pBTCpuSimulate();
742 __EXCEPT( simulate_filter )
744 /* restart simulation loop */
746 __ENDTRY
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] ))))
761 return NULL;
762 mem->next = NtCurrentTeb()->TlsSlots[WOW64_TLS_TEMPLIST];
763 NtCurrentTeb()->TlsSlots[WOW64_TLS_TEMPLIST] = mem;
764 return mem->data;
768 /**********************************************************************
769 * Wow64ApcRoutine (wow64.@)
771 void WINAPI Wow64ApcRoutine( ULONG_PTR arg1, ULONG_PTR arg2, ULONG_PTR arg3, CONTEXT *context )
773 NTSTATUS retval;
775 #ifdef __x86_64__
776 retval = context->Rax;
777 #elif defined(__aarch64__)
778 retval = context->X0;
779 #endif
781 /* cf. 32-bit call_user_apc_dispatcher */
782 switch (current_machine)
784 case IMAGE_FILE_MACHINE_I386:
786 struct apc_stack_layout
788 ULONG ret;
789 ULONG context_ptr;
790 ULONG arg1;
791 ULONG arg2;
792 ULONG arg3;
793 ULONG func;
794 I386_CONTEXT context;
795 } *stack;
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;
802 stack->arg1 = arg1;
803 stack->arg2 = arg2;
804 stack->arg3 = arg3;
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) );
811 break;
813 case IMAGE_FILE_MACHINE_ARMNT:
815 struct apc_stack_layout
817 ULONG func;
818 ULONG align[3];
819 ARM_CONTEXT context;
820 } *stack;
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 );
831 ctx.R1 = arg1;
832 ctx.R2 = arg2;
833 ctx.R3 = arg3;
834 NtSetInformationThread( GetCurrentThread(), ThreadWow64Context, &ctx, sizeof(ctx) );
836 break;
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 };
863 void *args_data;
864 ULONG *stack;
866 NtQueryInformationThread( GetCurrentThread(), ThreadWow64Context, &ctx, sizeof(ctx), NULL );
868 stack = args_data = ULongToPtr( (ctx.Esp - len) & ~15 );
869 memcpy( args_data, args, len );
870 *(--stack) = 0;
871 *(--stack) = len;
872 *(--stack) = PtrToUlong( args_data );
873 *(--stack) = id;
874 *(--stack) = 0xdeadbabe;
876 orig_ctx = ctx;
877 ctx.Esp = PtrToUlong( stack );
878 ctx.Eip = pLdrSystemDllInitBlock->pKiUserCallbackDispatcher;
879 NtSetInformationThread( GetCurrentThread(), ThreadWow64Context, &ctx, sizeof(ctx) );
881 if (!__wine_setjmpex( &frame.jmpbuf, NULL ))
882 cpu_simulate();
883 else
884 NtSetInformationThread( GetCurrentThread(), ThreadWow64Context,
885 &orig_ctx, sizeof(orig_ctx) );
887 break;
889 case IMAGE_FILE_MACHINE_ARMNT:
891 ARM_CONTEXT orig_ctx, ctx = { CONTEXT_ARM_FULL };
892 void *args_data;
894 NtQueryInformationThread( GetCurrentThread(), ThreadWow64Context, &ctx, sizeof(ctx), NULL );
896 args_data = ULongToPtr( (ctx.Sp - len) & ~15 );
897 memcpy( args_data, args, len );
899 ctx.R0 = id;
900 ctx.R1 = PtrToUlong( args );
901 ctx.R2 = len;
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 ))
907 cpu_simulate();
908 else
909 NtSetInformationThread( GetCurrentThread(), ThreadWow64Context,
910 &orig_ctx, sizeof(orig_ctx) );
912 break;
915 NtCurrentTeb()->TlsSlots[WOW64_TLS_USERCALLBACKDATA] = frame.prev_frame;
916 NtCurrentTeb()->TlsSlots[WOW64_TLS_TEMPLIST] = frame.temp_list;
917 return frame.status;
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 );
929 thread_init();
930 cpu_simulate();
934 /**********************************************************************
935 * Wow64PrepareForException (wow64.@)
937 void WINAPI Wow64PrepareForException( EXCEPTION_RECORD *rec, CONTEXT *context )
939 EXCEPTION_POINTERS ptrs = { rec, context };
941 pBTCpuResetToConsistentState( &ptrs );