comctl32/tests: Flush events before testing edit control IME messages.
[wine.git] / dlls / wow64 / syscall.c
blob86c5b61157ee270a34f16a6107f7745241964aca
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;
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,
47 ALL_SYSCALLS
48 #undef SYSCALL_ENTRY
51 static const char *syscall_names[] =
53 #define SYSCALL_ENTRY(func) #func,
54 ALL_SYSCALLS
55 #undef SYSCALL_ENTRY
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 */
68 struct mem_header
70 struct mem_header *next;
71 void *__pad;
72 BYTE data[1];
75 /* stack frame for user callbacks */
76 struct user_callback_frame
78 struct user_callback_frame *prev_frame;
79 struct mem_header *temp_list;
80 void **ret_ptr;
81 ULONG *ret_len;
82 NTSTATUS status;
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 );
104 return TRUE;
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 /**********************************************************************
123 * wow64_NtAddAtom
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 /**********************************************************************
181 * wow64_NtClose
183 NTSTATUS WINAPI wow64_NtClose( UINT *args )
185 HANDLE handle = get_handle( &args );
187 return NtClose( handle );
191 /**********************************************************************
192 * wow64_NtDeleteAtom
194 NTSTATUS WINAPI wow64_NtDeleteAtom( UINT *args )
196 RTL_ATOM atom = get_ulong( &args );
198 return NtDeleteAtom( atom );
202 /**********************************************************************
203 * wow64_NtFindAtom
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;
344 char **argv;
346 while (argv32[count]) count++;
347 argv = Wow64AllocateTemp( (count + 1) * sizeof(*argv) );
348 for (i = 0; i < count; i++) argv[i] = ULongToPtr( argv32[i] );
349 argv[count] = NULL;
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 );
361 unsigned int i;
362 NTSTATUS status;
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;
375 return status;
379 /**********************************************************************
380 * get_syscall_num
382 static DWORD get_syscall_num( const BYTE *syscall )
384 DWORD id = ~0u;
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);
392 break;
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);
401 break;
403 return id;
407 /**********************************************************************
408 * init_image_mapping
410 void init_image_mapping( HMODULE module )
412 void **ptr = RtlFindExportedRoutineByName( module, "Wow64Transition" );
414 if (ptr) *ptr = pBTCpuGetBopCode();
418 /**********************************************************************
419 * init_syscall_table
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] );
440 int res = -1;
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 );
464 else if (res > 0)
466 FIXME( "no export for syscall %s\n", syscall_names[wrap_pos] );
467 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 /**********************************************************************
483 * load_64bit_module
485 static HMODULE load_64bit_module( const WCHAR *name )
487 NTSTATUS status;
488 HMODULE module;
489 UNICODE_STRING str;
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 );
500 return module;
504 /**********************************************************************
505 * load_32bit_module
507 static HMODULE load_32bit_module( const WCHAR *name )
509 NTSTATUS status;
510 UNICODE_STRING str;
511 WCHAR path[MAX_PATH];
512 HANDLE file, mapping;
513 LARGE_INTEGER size;
514 IO_STATUS_BLOCK io;
515 OBJECT_ATTRIBUTES attr;
516 SIZE_T len = 0;
517 void *module = NULL;
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;
527 size.QuadPart = 0;
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 );
531 NtClose( file );
532 if (status) goto failed;
534 status = NtMapViewOfSection( mapping, GetCurrentProcess(), &module, 0, 0, NULL, &len,
535 ViewShare, 0, PAGE_EXECUTE_READ );
536 NtClose( mapping );
537 if (!status) return module;
539 failed:
540 ERR( "failed to load dll %lx\n", status );
541 NtTerminateProcess( GetCurrentProcess(), status );
542 return NULL;
546 /**********************************************************************
547 * get_cpu_dll_name
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";
557 default:
558 ERR( "unsupported machine %04x\n", current_machine );
559 RtlExitUserProcess( 1 );
564 /**********************************************************************
565 * process_init
567 static DWORD WINAPI process_init( RTL_RUN_ONCE *once, void *param, void **context )
569 HMODULE module;
570 UNICODE_STRING str;
571 SYSTEM_BASIC_INFORMATION info;
573 RtlWow64GetProcessMachines( GetCurrentProcess(), &current_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 );
595 pBTCpuProcessInit();
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();
607 return TRUE;
609 #undef GET_PTR
613 /**********************************************************************
614 * thread_init
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 };
624 ULONG *stack;
626 NtQueryInformationThread( GetCurrentThread(), ThreadWow64Context, &ctx, sizeof(ctx), NULL );
627 ctx_ptr = (I386_CONTEXT *)ULongToPtr( ctx.Esp ) - 1;
628 *ctx_ptr = ctx;
630 stack = (ULONG *)ctx_ptr;
631 *(--stack) = 0;
632 *(--stack) = 0;
633 *(--stack) = 0;
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) );
640 break;
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;
648 *ctx_ptr = ctx;
650 ctx.R0 = PtrToUlong( ctx_ptr );
651 ctx.Sp = PtrToUlong( ctx_ptr );
652 ctx.Pc = pLdrSystemDllInitBlock->pLdrInitializeThunk;
653 NtSetInformationThread( GetCurrentThread(), ThreadWow64Context, &ctx, sizeof(ctx) );
655 break;
657 default:
658 ERR( "not supported machine %x\n", current_machine );
659 NtTerminateProcess( GetCurrentProcess(), STATUS_INVALID_IMAGE_FORMAT );
664 /**********************************************************************
665 * free_temp_data
667 static void free_temp_data(void)
669 struct mem_header *next, *mem;
671 for (mem = NtCurrentTeb()->TlsSlots[WOW64_TLS_TEMPLIST]; mem; mem = next)
673 next = mem->next;
674 RtlFreeHeap( GetProcessHeap(), 0, mem );
676 NtCurrentTeb()->TlsSlots[WOW64_TLS_TEMPLIST] = NULL;
680 /**********************************************************************
681 * syscall_filter
683 static LONG CALLBACK syscall_filter( EXCEPTION_POINTERS *ptrs )
685 switch (ptrs->ExceptionRecord->ExceptionCode)
687 case STATUS_INVALID_HANDLE:
688 Wow64PassExceptionToGuest( ptrs );
689 break;
691 return EXCEPTION_EXECUTE_HANDLER;
695 /**********************************************************************
696 * Wow64SystemServiceEx (wow64.@)
698 NTSTATUS WINAPI Wow64SystemServiceEx( UINT num, UINT *args )
700 NTSTATUS status;
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;
709 __TRY
711 syscall_thunk thunk = (syscall_thunk)table->ServiceTable[id];
712 status = thunk( args );
714 __EXCEPT( syscall_filter )
716 status = GetExceptionCode();
718 __ENDTRY;
719 free_temp_data();
720 return status;
724 /**********************************************************************
725 * simulate_filter
727 static LONG CALLBACK simulate_filter( EXCEPTION_POINTERS *ptrs )
729 Wow64PassExceptionToGuest( ptrs );
730 return EXCEPTION_EXECUTE_HANDLER;
734 /**********************************************************************
735 * cpu_simulate
737 static void cpu_simulate(void)
739 for (;;)
741 __TRY
743 pBTCpuSimulate();
745 __EXCEPT( simulate_filter )
747 /* restart simulation loop */
749 __ENDTRY
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] ))))
764 return NULL;
765 mem->next = NtCurrentTeb()->TlsSlots[WOW64_TLS_TEMPLIST];
766 NtCurrentTeb()->TlsSlots[WOW64_TLS_TEMPLIST] = mem;
767 return mem->data;
771 /**********************************************************************
772 * Wow64ApcRoutine (wow64.@)
774 void WINAPI Wow64ApcRoutine( ULONG_PTR arg1, ULONG_PTR arg2, ULONG_PTR arg3, CONTEXT *context )
776 NTSTATUS retval;
778 #ifdef __x86_64__
779 retval = context->Rax;
780 #elif defined(__aarch64__)
781 retval = context->X0;
782 #endif
784 /* cf. 32-bit call_user_apc_dispatcher */
785 switch (current_machine)
787 case IMAGE_FILE_MACHINE_I386:
789 struct apc_stack_layout
791 ULONG ret;
792 ULONG context_ptr;
793 ULONG arg1;
794 ULONG arg2;
795 ULONG arg3;
796 ULONG func;
797 I386_CONTEXT context;
798 } *stack;
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;
805 stack->arg1 = arg1;
806 stack->arg2 = arg2;
807 stack->arg3 = arg3;
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) );
814 break;
816 case IMAGE_FILE_MACHINE_ARMNT:
818 struct apc_stack_layout
820 ULONG func;
821 ULONG align[3];
822 ARM_CONTEXT context;
823 } *stack;
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 );
834 ctx.R1 = arg1;
835 ctx.R2 = arg2;
836 ctx.R3 = arg3;
837 NtSetInformationThread( GetCurrentThread(), ThreadWow64Context, &ctx, sizeof(ctx) );
839 break;
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;
868 void *args_data;
869 ULONG *stack;
871 RtlWow64GetCurrentCpuArea( NULL, (void **)&ctx, NULL );
872 orig_ctx = *ctx;
874 stack = args_data = ULongToPtr( (ctx->Esp - len) & ~15 );
875 memcpy( args_data, args, len );
876 *(--stack) = 0;
877 *(--stack) = len;
878 *(--stack) = PtrToUlong( args_data );
879 *(--stack) = id;
880 *(--stack) = 0xdeadbabe;
882 ctx->Esp = PtrToUlong( stack );
883 ctx->Eip = pLdrSystemDllInitBlock->pKiUserCallbackDispatcher;
885 if (!__wine_setjmpex( &frame.jmpbuf, NULL ))
886 cpu_simulate();
887 else
888 *ctx = orig_ctx;
890 break;
892 case IMAGE_FILE_MACHINE_ARMNT:
894 ARM_CONTEXT orig_ctx, ctx = { CONTEXT_ARM_FULL };
895 void *args_data;
897 NtQueryInformationThread( GetCurrentThread(), ThreadWow64Context, &ctx, sizeof(ctx), NULL );
899 args_data = ULongToPtr( (ctx.Sp - len) & ~15 );
900 memcpy( args_data, args, len );
902 ctx.R0 = id;
903 ctx.R1 = PtrToUlong( args );
904 ctx.R2 = len;
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 ))
910 cpu_simulate();
911 else
912 NtSetInformationThread( GetCurrentThread(), ThreadWow64Context,
913 &orig_ctx, sizeof(orig_ctx) );
915 break;
918 teb32->Tib.ExceptionList = teb_frame;
919 NtCurrentTeb()->TlsSlots[WOW64_TLS_USERCALLBACKDATA] = frame.prev_frame;
920 NtCurrentTeb()->TlsSlots[WOW64_TLS_TEMPLIST] = frame.temp_list;
921 return frame.status;
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 );
933 thread_init();
934 cpu_simulate();
938 /**********************************************************************
939 * Wow64PrepareForException (wow64.@)
941 void WINAPI Wow64PrepareForException( EXCEPTION_RECORD *rec, CONTEXT *context )
943 EXCEPTION_POINTERS ptrs = { rec, context };
945 pBTCpuResetToConsistentState( &ptrs );