widl: Add support for function parameter flags to SLTG typelib generator.
[wine.git] / dlls / wow64 / syscall.c
blob9ad1194b21e8ac9dd7936b3a7010dd240077a5ea
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>
22 #include <setjmp.h>
24 #include "ntstatus.h"
25 #define WIN32_NO_STATUS
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winnt.h"
29 #include "winternl.h"
30 #include "rtlsupportapi.h"
31 #include "wine/unixlib.h"
32 #include "wine/asm.h"
33 #include "wow64_private.h"
34 #include "wine/debug.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(wow);
38 USHORT native_machine = 0;
39 USHORT current_machine = 0;
40 ULONG_PTR args_alignment = 0;
41 ULONG_PTR highest_user_address = 0x7ffeffff;
42 ULONG_PTR default_zero_bits = 0x7fffffff;
44 typedef NTSTATUS (WINAPI *syscall_thunk)( UINT *args );
46 static const syscall_thunk syscall_thunks[] =
48 #define SYSCALL_ENTRY(id,name,args) wow64_ ## name,
49 ALL_SYSCALLS32
50 #undef SYSCALL_ENTRY
53 static BYTE syscall_args[ARRAY_SIZE(syscall_thunks)] =
55 #define SYSCALL_ENTRY(id,name,args) args,
56 ALL_SYSCALLS32
57 #undef SYSCALL_ENTRY
60 static SYSTEM_SERVICE_TABLE syscall_tables[4] =
62 { (ULONG_PTR *)syscall_thunks, NULL, ARRAY_SIZE(syscall_thunks), syscall_args }
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 jmp_buf jmpbuf;
84 /* stack frame for user APCs */
85 struct user_apc_frame
87 struct user_apc_frame *prev_frame;
88 CONTEXT *context;
89 void *wow_context;
92 SYSTEM_DLL_INIT_BLOCK *pLdrSystemDllInitBlock = NULL;
94 static WOW64INFO *wow64info;
96 /* cpu backend dll functions */
97 /* the function prototypes most likely differ from Windows */
98 static void * (WINAPI *pBTCpuGetBopCode)(void);
99 static NTSTATUS (WINAPI *pBTCpuGetContext)(HANDLE,HANDLE,void *,void *);
100 static BOOLEAN (WINAPI *pBTCpuIsProcessorFeaturePresent)(UINT);
101 static void (WINAPI *pBTCpuProcessInit)(void);
102 static NTSTATUS (WINAPI *pBTCpuSetContext)(HANDLE,HANDLE,void *,void *);
103 static void (WINAPI *pBTCpuThreadInit)(void);
104 static void (WINAPI *pBTCpuSimulate)(void) __attribute__((used));
105 static void * (WINAPI *p__wine_get_unix_opcode)(void);
106 static void * (WINAPI *pKiRaiseUserExceptionDispatcher)(void);
107 void (WINAPI *pBTCpuNotifyFlushInstructionCache2)( const void *, SIZE_T ) = NULL;
108 void (WINAPI *pBTCpuNotifyMapViewOfSection)( void * ) = NULL;
109 void (WINAPI *pBTCpuNotifyMemoryAlloc)( void *, SIZE_T, ULONG, ULONG ) = NULL;
110 void (WINAPI *pBTCpuNotifyMemoryDirty)( void *, SIZE_T ) = NULL;
111 void (WINAPI *pBTCpuNotifyMemoryFree)( void *, SIZE_T, ULONG ) = NULL;
112 void (WINAPI *pBTCpuNotifyMemoryProtect)( void *, SIZE_T, ULONG ) = NULL;
113 void (WINAPI *pBTCpuNotifyUnmapViewOfSection)( void * ) = NULL;
114 NTSTATUS (WINAPI *pBTCpuResetToConsistentState)( EXCEPTION_POINTERS * ) = NULL;
115 void (WINAPI *pBTCpuUpdateProcessorInformation)( SYSTEM_CPU_INFORMATION * ) = NULL;
116 void (WINAPI *pBTCpuThreadTerm)( HANDLE ) = NULL;
118 BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, void *reserved )
120 if (reason == DLL_PROCESS_ATTACH) LdrDisableThreadCalloutsForDll( inst );
121 return TRUE;
124 void __cdecl __wine_spec_unimplemented_stub( const char *module, const char *function )
126 EXCEPTION_RECORD record;
128 record.ExceptionCode = EXCEPTION_WINE_STUB;
129 record.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
130 record.ExceptionRecord = NULL;
131 record.ExceptionAddress = __wine_spec_unimplemented_stub;
132 record.NumberParameters = 2;
133 record.ExceptionInformation[0] = (ULONG_PTR)module;
134 record.ExceptionInformation[1] = (ULONG_PTR)function;
135 for (;;) RtlRaiseException( &record );
139 static EXCEPTION_RECORD *exception_record_32to64( const EXCEPTION_RECORD32 *rec32 )
141 EXCEPTION_RECORD *rec;
142 unsigned int i;
144 rec = Wow64AllocateTemp( sizeof(*rec) );
145 rec->ExceptionCode = rec32->ExceptionCode;
146 rec->ExceptionFlags = rec32->ExceptionFlags;
147 rec->ExceptionRecord = rec32->ExceptionRecord ? exception_record_32to64( ULongToPtr(rec32->ExceptionRecord) ) : NULL;
148 rec->ExceptionAddress = ULongToPtr( rec32->ExceptionAddress );
149 rec->NumberParameters = rec32->NumberParameters;
150 for (i = 0; i < EXCEPTION_MAXIMUM_PARAMETERS; i++)
151 rec->ExceptionInformation[i] = rec32->ExceptionInformation[i];
152 return rec;
156 static void exception_record_64to32( EXCEPTION_RECORD32 *rec32, const EXCEPTION_RECORD *rec )
158 unsigned int i;
160 rec32->ExceptionCode = rec->ExceptionCode;
161 rec32->ExceptionFlags = rec->ExceptionFlags;
162 rec32->ExceptionRecord = PtrToUlong( rec->ExceptionRecord );
163 rec32->ExceptionAddress = PtrToUlong( rec->ExceptionAddress );
164 rec32->NumberParameters = rec->NumberParameters;
165 for (i = 0; i < rec->NumberParameters; i++)
166 rec32->ExceptionInformation[i] = rec->ExceptionInformation[i];
170 static NTSTATUS get_context_return_value( void *wow_context )
172 switch (current_machine)
174 case IMAGE_FILE_MACHINE_I386:
175 return ((I386_CONTEXT *)wow_context)->Eax;
176 case IMAGE_FILE_MACHINE_ARMNT:
177 return ((ARM_CONTEXT *)wow_context)->R0;
179 return 0;
183 /**********************************************************************
184 * call_user_exception_dispatcher
186 static void __attribute__((used)) call_user_exception_dispatcher( EXCEPTION_RECORD32 *rec, void *ctx32_ptr,
187 void *ctx64_ptr )
189 switch (current_machine)
191 case IMAGE_FILE_MACHINE_I386:
193 /* stack layout when calling 32-bit KiUserExceptionDispatcher */
194 struct exc_stack_layout32
196 ULONG rec_ptr; /* 000 */
197 ULONG context_ptr; /* 004 */
198 EXCEPTION_RECORD32 rec; /* 008 */
199 I386_CONTEXT context; /* 058 */
200 } *stack;
201 I386_CONTEXT ctx = { CONTEXT_I386_ALL };
202 CONTEXT_EX *context_ex, *src_ex = NULL;
203 ULONG flags, context_length;
205 C_ASSERT( offsetof(struct exc_stack_layout32, context) == 0x58 );
207 pBTCpuGetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx );
209 if (ctx32_ptr)
211 I386_CONTEXT *ctx32 = ctx32_ptr;
213 if ((ctx32->ContextFlags & CONTEXT_I386_XSTATE) == CONTEXT_I386_XSTATE)
214 src_ex = (CONTEXT_EX *)(ctx32 + 1);
216 else if (native_machine == IMAGE_FILE_MACHINE_AMD64)
218 AMD64_CONTEXT *ctx64 = ctx64_ptr;
220 if ((ctx64->ContextFlags & CONTEXT_AMD64_FLOATING_POINT) == CONTEXT_AMD64_FLOATING_POINT)
221 memcpy( ctx.ExtendedRegisters, &ctx64->FltSave, sizeof(ctx.ExtendedRegisters) );
222 if ((ctx64->ContextFlags & CONTEXT_AMD64_XSTATE) == CONTEXT_AMD64_XSTATE)
223 src_ex = (CONTEXT_EX *)(ctx64 + 1);
226 flags = ctx.ContextFlags;
227 if (src_ex) flags |= CONTEXT_I386_XSTATE;
229 RtlGetExtendedContextLength( flags, &context_length );
231 stack = (struct exc_stack_layout32 *)ULongToPtr( (ctx.Esp - offsetof(struct exc_stack_layout32, context) - context_length) & ~3 );
232 stack->rec_ptr = PtrToUlong( &stack->rec );
233 stack->context_ptr = PtrToUlong( &stack->context );
234 stack->rec = *rec;
235 stack->context = ctx;
236 RtlInitializeExtendedContext( &stack->context, flags, &context_ex );
237 if (src_ex) RtlCopyExtendedContext( context_ex, WOW64_CONTEXT_XSTATE, src_ex );
239 /* adjust Eip for breakpoints in software emulation (hardware exceptions already adjust Rip) */
240 if (rec->ExceptionCode == EXCEPTION_BREAKPOINT && (wow64info->CpuFlags & WOW64_CPUFLAGS_SOFTWARE))
241 stack->context.Eip--;
243 ctx.Esp = PtrToUlong( stack );
244 ctx.Eip = pLdrSystemDllInitBlock->pKiUserExceptionDispatcher;
245 ctx.EFlags &= ~(0x100|0x400|0x40000);
246 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx );
248 TRACE( "exception %08lx dispatcher %08lx stack %08lx eip %08lx\n",
249 rec->ExceptionCode, ctx.Eip, ctx.Esp, stack->context.Eip );
251 break;
253 case IMAGE_FILE_MACHINE_ARMNT:
255 struct stack_layout
257 ARM_CONTEXT context;
258 EXCEPTION_RECORD32 rec;
259 } *stack;
260 ARM_CONTEXT ctx = { CONTEXT_ARM_ALL };
262 pBTCpuGetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx );
263 stack = (struct stack_layout *)(ULONG_PTR)(ctx.Sp & ~3) - 1;
264 stack->rec = *rec;
265 stack->context = ctx;
267 ctx.R0 = PtrToUlong( &stack->rec ); /* first arg for KiUserExceptionDispatcher */
268 ctx.R1 = PtrToUlong( &stack->context ); /* second arg for KiUserExceptionDispatcher */
269 ctx.Sp = PtrToUlong( stack );
270 ctx.Pc = pLdrSystemDllInitBlock->pKiUserExceptionDispatcher;
271 if (ctx.Pc & 1) ctx.Cpsr |= 0x20;
272 else ctx.Cpsr &= ~0x20;
273 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx );
275 TRACE( "exception %08lx dispatcher %08lx stack %08lx pc %08lx\n",
276 rec->ExceptionCode, ctx.Pc, ctx.Sp, stack->context.Sp );
278 break;
283 /**********************************************************************
284 * call_raise_user_exception_dispatcher
286 static void __attribute__((used)) call_raise_user_exception_dispatcher( ULONG code )
288 TEB32 *teb32 = (TEB32 *)((char *)NtCurrentTeb() + NtCurrentTeb()->WowTebOffset);
290 teb32->ExceptionCode = code;
292 switch (current_machine)
294 case IMAGE_FILE_MACHINE_I386:
296 I386_CONTEXT ctx = { CONTEXT_I386_ALL };
298 pBTCpuGetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx );
299 ctx.Esp -= sizeof(ULONG);
300 *(ULONG *)ULongToPtr( ctx.Esp ) = ctx.Eip;
301 ctx.Eip = (ULONG_PTR)pKiRaiseUserExceptionDispatcher;
302 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx );
304 break;
306 case IMAGE_FILE_MACHINE_ARMNT:
308 ARM_CONTEXT ctx = { CONTEXT_ARM_ALL };
310 pBTCpuGetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx );
311 ctx.Pc = (ULONG_PTR)pKiRaiseUserExceptionDispatcher;
312 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx );
314 break;
319 /* based on RtlRaiseException: call NtRaiseException with context setup to return to caller */
320 void WINAPI raise_exception( EXCEPTION_RECORD32 *rec32, void *ctx32,
321 BOOL first_chance, EXCEPTION_RECORD *rec );
322 #ifdef __aarch64__
323 __ASM_GLOBAL_FUNC( raise_exception,
324 "sub sp, sp, #0x390\n\t" /* sizeof(context) */
325 ".seh_stackalloc 0x390\n\t"
326 "stp x29, x30, [sp, #-48]!\n\t"
327 ".seh_save_fplr_x 48\n\t"
328 ".seh_endprologue\n\t"
329 ".seh_handler raise_exception_handler, @except\n\t"
330 "stp x0, x1, [sp, #16]\n\t"
331 "stp x2, x3, [sp, #32]\n\t"
332 "add x0, sp, #48\n\t"
333 "bl RtlCaptureContext\n\t"
334 "add x1, sp, #48\n\t" /* context */
335 "adr x2, 1f\n\t" /* return address */
336 "str x2, [x1, #0x108]\n\t" /* context->Pc */
337 "ldp x2, x0, [sp, #32]\n\t" /* first_chance, rec */
338 "bl NtRaiseException\n"
339 "raise_exception_ret:\n\t"
340 "ldp x0, x1, [sp, #16]\n\t" /* rec32, ctx32 */
341 "add x2, sp, #48\n\t" /* context */
342 "bl call_user_exception_dispatcher\n"
343 "1:\tnop\n\t"
344 "ldp x29, x30, [sp], #48\n\t"
345 "add sp, sp, #0x390\n\t"
346 "ret" )
347 __ASM_GLOBAL_FUNC( raise_exception_handler,
348 "stp x29, x30, [sp, #-16]!\n\t"
349 ".seh_save_fplr_x 16\n\t"
350 ".seh_endprologue\n\t"
351 "ldr w4, [x0, #4]\n\t" /* record->ExceptionFlags */
352 "tst w4, #6\n\t" /* EXCEPTION_UNWINDING | EXCEPTION_EXIT_UNWIND */
353 "b.ne 1f\n\t"
354 "mov x2, x0\n\t" /* rec */
355 "mov x0, x1\n\t" /* frame */
356 "adr x1, raise_exception_ret\n\t"
357 "bl RtlUnwind\n"
358 "1:\tmov w0, #1\n\t" /* ExceptionContinueSearch */
359 "ldp x29, x30, [sp], #16\n\t"
360 "ret" )
361 #else
362 __ASM_GLOBAL_FUNC( raise_exception,
363 "sub $0x4d8,%rsp\n\t" /* sizeof(context) + alignment */
364 ".seh_stackalloc 0x4d8\n\t"
365 ".seh_endprologue\n\t"
366 ".seh_handler raise_exception_handler, @except\n\t"
367 "movq %rcx,0x4e0(%rsp)\n\t"
368 "movq %rdx,0x4e8(%rsp)\n\t"
369 "movq %r8,0x4f0(%rsp)\n\t"
370 "movq %r9,0x4f8(%rsp)\n\t"
371 "movq %rsp,%rcx\n\t"
372 "call RtlCaptureContext\n\t"
373 "movq %rsp,%rdx\n\t" /* context */
374 "leaq 1f(%rip),%rax\n\t" /* return address */
375 "movq %rax,0xf8(%rdx)\n\t" /* context->Rip */
376 "movq 0x4f8(%rsp),%rcx\n\t" /* rec */
377 "movq 0x4f0(%rsp),%r8\n\t" /* first_chance */
378 "call NtRaiseException\n"
379 "raise_exception_ret:\n\t"
380 "mov 0x4e0(%rsp),%rcx\n\t" /* rec32 */
381 "mov 0x4e8(%rsp),%rdx\n\t" /* ctx32 */
382 "movq %rsp,%r8\n\t" /* context */
383 "call call_user_exception_dispatcher\n"
384 "1:\tnop\n\t"
385 "add $0x4d8,%rsp\n\t"
386 "ret" )
387 __ASM_GLOBAL_FUNC( raise_exception_handler,
388 "sub $0x28,%rsp\n\t"
389 ".seh_stackalloc 0x28\n\t"
390 ".seh_endprologue\n\t"
391 "movq %rcx,%r8\n\t" /* rec */
392 "movq %rdx,%rcx\n\t" /* frame */
393 "leaq raise_exception_ret(%rip),%rdx\n\t"
394 "call RtlUnwind\n\t"
395 "int3" )
396 #endif
399 /**********************************************************************
400 * wow64_NtAddAtom
402 NTSTATUS WINAPI wow64_NtAddAtom( UINT *args )
404 const WCHAR *name = get_ptr( &args );
405 ULONG len = get_ulong( &args );
406 RTL_ATOM *atom = get_ptr( &args );
408 return NtAddAtom( name, len, atom );
412 /**********************************************************************
413 * wow64_NtAllocateLocallyUniqueId
415 NTSTATUS WINAPI wow64_NtAllocateLocallyUniqueId( UINT *args )
417 LUID *luid = get_ptr( &args );
419 return NtAllocateLocallyUniqueId( luid );
423 /**********************************************************************
424 * wow64_NtAllocateUuids
426 NTSTATUS WINAPI wow64_NtAllocateUuids( UINT *args )
428 ULARGE_INTEGER *time = get_ptr( &args );
429 ULONG *delta = get_ptr( &args );
430 ULONG *sequence = get_ptr( &args );
431 UCHAR *seed = get_ptr( &args );
433 return NtAllocateUuids( time, delta, sequence, seed );
437 /***********************************************************************
438 * wow64_NtCallbackReturn
440 NTSTATUS WINAPI wow64_NtCallbackReturn( UINT *args )
442 void *ret_ptr = get_ptr( &args );
443 ULONG ret_len = get_ulong( &args );
444 NTSTATUS status = get_ulong( &args );
446 struct user_callback_frame *frame = NtCurrentTeb()->TlsSlots[WOW64_TLS_USERCALLBACKDATA];
448 if (!frame) return STATUS_NO_CALLBACK_ACTIVE;
450 *frame->ret_ptr = ret_ptr;
451 *frame->ret_len = ret_len;
452 frame->status = status;
453 longjmp( frame->jmpbuf, 1 );
454 return STATUS_SUCCESS;
458 /**********************************************************************
459 * wow64_NtClose
461 NTSTATUS WINAPI wow64_NtClose( UINT *args )
463 HANDLE handle = get_handle( &args );
465 return NtClose( handle );
469 /**********************************************************************
470 * wow64_NtContinue
472 NTSTATUS WINAPI wow64_NtContinue( UINT *args )
474 void *context = get_ptr( &args );
475 BOOLEAN alertable = get_ulong( &args );
477 NTSTATUS status = get_context_return_value( context );
478 struct user_apc_frame *frame = NtCurrentTeb()->TlsSlots[WOW64_TLS_APCLIST];
480 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL, context );
482 while (frame && frame->wow_context != context) frame = frame->prev_frame;
483 NtCurrentTeb()->TlsSlots[WOW64_TLS_APCLIST] = frame ? frame->prev_frame : NULL;
484 if (frame) NtContinue( frame->context, alertable );
486 if (alertable) NtTestAlert();
487 return status;
491 /**********************************************************************
492 * wow64_NtDeleteAtom
494 NTSTATUS WINAPI wow64_NtDeleteAtom( UINT *args )
496 RTL_ATOM atom = get_ulong( &args );
498 return NtDeleteAtom( atom );
502 /**********************************************************************
503 * wow64_NtFindAtom
505 NTSTATUS WINAPI wow64_NtFindAtom( UINT *args )
507 const WCHAR *name = get_ptr( &args );
508 ULONG len = get_ulong( &args );
509 RTL_ATOM *atom = get_ptr( &args );
511 return NtFindAtom( name, len, atom );
515 /**********************************************************************
516 * wow64_NtGetContextThread
518 NTSTATUS WINAPI wow64_NtGetContextThread( UINT *args )
520 HANDLE handle = get_handle( &args );
521 WOW64_CONTEXT *context = get_ptr( &args );
523 return RtlWow64GetThreadContext( handle, context );
527 /**********************************************************************
528 * wow64_NtGetCurrentProcessorNumber
530 NTSTATUS WINAPI wow64_NtGetCurrentProcessorNumber( UINT *args )
532 return NtGetCurrentProcessorNumber();
536 /**********************************************************************
537 * wow64_NtQueryDefaultLocale
539 NTSTATUS WINAPI wow64_NtQueryDefaultLocale( UINT *args )
541 BOOLEAN user = get_ulong( &args );
542 LCID *lcid = get_ptr( &args );
544 return NtQueryDefaultLocale( user, lcid );
548 /**********************************************************************
549 * wow64_NtQueryDefaultUILanguage
551 NTSTATUS WINAPI wow64_NtQueryDefaultUILanguage( UINT *args )
553 LANGID *lang = get_ptr( &args );
555 return NtQueryDefaultUILanguage( lang );
559 /**********************************************************************
560 * wow64_NtQueryInformationAtom
562 NTSTATUS WINAPI wow64_NtQueryInformationAtom( UINT *args )
564 RTL_ATOM atom = get_ulong( &args );
565 ATOM_INFORMATION_CLASS class = get_ulong( &args );
566 void *info = get_ptr( &args );
567 ULONG len = get_ulong( &args );
568 ULONG *retlen = get_ptr( &args );
570 if (class != AtomBasicInformation) FIXME( "class %u not supported\n", class );
571 return NtQueryInformationAtom( atom, class, info, len, retlen );
575 /**********************************************************************
576 * wow64_NtQueryInstallUILanguage
578 NTSTATUS WINAPI wow64_NtQueryInstallUILanguage( UINT *args )
580 LANGID *lang = get_ptr( &args );
582 return NtQueryInstallUILanguage( lang );
586 /**********************************************************************
587 * wow64_NtRaiseException
589 NTSTATUS WINAPI wow64_NtRaiseException( UINT *args )
591 EXCEPTION_RECORD32 *rec32 = get_ptr( &args );
592 void *context32 = get_ptr( &args );
593 BOOL first_chance = get_ulong( &args );
595 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL, context32 );
596 raise_exception( rec32, context32, first_chance, exception_record_32to64( rec32 ));
597 return STATUS_SUCCESS;
601 /**********************************************************************
602 * wow64_NtSetContextThread
604 NTSTATUS WINAPI wow64_NtSetContextThread( UINT *args )
606 HANDLE handle = get_handle( &args );
607 WOW64_CONTEXT *context = get_ptr( &args );
609 return RtlWow64SetThreadContext( handle, context );
613 /**********************************************************************
614 * wow64_NtSetDebugFilterState
616 NTSTATUS WINAPI wow64_NtSetDebugFilterState( UINT *args )
618 ULONG component_id = get_ulong( &args );
619 ULONG level = get_ulong( &args );
620 BOOLEAN state = get_ulong( &args );
622 return NtSetDebugFilterState( component_id, level, state );
626 /**********************************************************************
627 * wow64_NtSetDefaultLocale
629 NTSTATUS WINAPI wow64_NtSetDefaultLocale( UINT *args )
631 BOOLEAN user = get_ulong( &args );
632 LCID lcid = get_ulong( &args );
634 return NtSetDefaultLocale( user, lcid );
638 /**********************************************************************
639 * wow64_NtSetDefaultUILanguage
641 NTSTATUS WINAPI wow64_NtSetDefaultUILanguage( UINT *args )
643 LANGID lang = get_ulong( &args );
645 return NtSetDefaultUILanguage( lang );
649 /**********************************************************************
650 * wow64_NtWow64IsProcessorFeaturePresent
652 NTSTATUS WINAPI wow64_NtWow64IsProcessorFeaturePresent( UINT *args )
654 UINT feature = get_ulong( &args );
656 return pBTCpuIsProcessorFeaturePresent && pBTCpuIsProcessorFeaturePresent( feature );
660 /**********************************************************************
661 * init_image_mapping
663 void init_image_mapping( HMODULE module )
665 ULONG *ptr = RtlFindExportedRoutineByName( module, "Wow64Transition" );
667 if (ptr) *ptr = PtrToUlong( pBTCpuGetBopCode() );
671 /**********************************************************************
672 * load_64bit_module
674 static HMODULE load_64bit_module( const WCHAR *name )
676 NTSTATUS status;
677 HMODULE module;
678 UNICODE_STRING str;
679 WCHAR path[MAX_PATH];
680 const WCHAR *dir = get_machine_wow64_dir( IMAGE_FILE_MACHINE_TARGET_HOST );
682 swprintf( path, MAX_PATH, L"%s\\%s", dir, name );
683 RtlInitUnicodeString( &str, path );
684 if ((status = LdrLoadDll( dir, 0, &str, &module )))
686 ERR( "failed to load dll %lx\n", status );
687 NtTerminateProcess( GetCurrentProcess(), status );
689 return module;
693 /**********************************************************************
694 * get_cpu_dll_name
696 static const WCHAR *get_cpu_dll_name(void)
698 static ULONG buffer[32];
699 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
700 OBJECT_ATTRIBUTES attr;
701 UNICODE_STRING nameW;
702 const WCHAR *ret;
703 HANDLE key;
704 ULONG size;
706 switch (current_machine)
708 case IMAGE_FILE_MACHINE_I386:
709 RtlInitUnicodeString( &nameW, L"\\Registry\\Machine\\Software\\Microsoft\\Wow64\\x86" );
710 ret = (native_machine == IMAGE_FILE_MACHINE_ARM64 ? L"xtajit.dll" : L"wow64cpu.dll");
711 break;
712 case IMAGE_FILE_MACHINE_ARMNT:
713 RtlInitUnicodeString( &nameW, L"\\Registry\\Machine\\Software\\Microsoft\\Wow64\\arm" );
714 ret = L"wowarmhw.dll";
715 break;
716 default:
717 ERR( "unsupported machine %04x\n", current_machine );
718 RtlExitUserProcess( 1 );
720 InitializeObjectAttributes( &attr, &nameW, OBJ_CASE_INSENSITIVE, 0, NULL );
721 if (NtOpenKey( &key, KEY_READ | KEY_WOW64_64KEY, &attr )) return ret;
722 RtlInitUnicodeString( &nameW, L"" );
723 size = sizeof(buffer) - sizeof(WCHAR);
724 if (!NtQueryValueKey( key, &nameW, KeyValuePartialInformation, buffer, size, &size ) && info->Type == REG_SZ)
726 ((WCHAR *)info->Data)[info->DataLength / sizeof(WCHAR)] = 0;
727 ret = (WCHAR *)info->Data;
729 NtClose( key );
730 return ret;
734 /**********************************************************************
735 * create_cross_process_work_list
737 static NTSTATUS create_cross_process_work_list( WOW64INFO *wow64info )
739 SIZE_T map_size = 0x4000;
740 LARGE_INTEGER size;
741 NTSTATUS status;
742 HANDLE section;
743 CROSS_PROCESS_WORK_LIST *list = NULL;
744 CROSS_PROCESS_WORK_ENTRY *end;
745 UINT i;
747 size.QuadPart = map_size;
748 status = NtCreateSection( &section, SECTION_ALL_ACCESS, NULL, &size, PAGE_READWRITE, SEC_COMMIT, 0 );
749 if (status) return status;
750 status = NtMapViewOfSection( section, GetCurrentProcess(), (void **)&list, default_zero_bits, 0, NULL,
751 &map_size, ViewShare, MEM_TOP_DOWN, PAGE_READWRITE );
752 if (status)
754 NtClose( section );
755 return status;
758 end = (CROSS_PROCESS_WORK_ENTRY *)((char *)list + map_size);
759 for (i = 0; list->entries + i + 1 <= end; i++)
760 RtlWow64PushCrossProcessWorkOntoFreeList( &list->free_list, &list->entries[i] );
762 wow64info->SectionHandle = (ULONG_PTR)section;
763 wow64info->CrossProcessWorkList = (ULONG_PTR)list;
764 return STATUS_SUCCESS;
768 /**********************************************************************
769 * process_init
771 static DWORD WINAPI process_init( RTL_RUN_ONCE *once, void *param, void **context )
773 PEB32 *peb32;
774 HMODULE module;
775 UNICODE_STRING str = RTL_CONSTANT_STRING( L"ntdll.dll" );
776 SYSTEM_BASIC_INFORMATION info;
777 ULONG *p__wine_syscall_dispatcher, *p__wine_unix_call_dispatcher;
778 const SYSTEM_SERVICE_TABLE *psdwhwin32;
780 RtlWow64GetProcessMachines( GetCurrentProcess(), &current_machine, &native_machine );
781 if (!current_machine) current_machine = native_machine;
782 args_alignment = (current_machine == IMAGE_FILE_MACHINE_I386) ? sizeof(ULONG) : sizeof(ULONG64);
783 NtQuerySystemInformation( SystemEmulationBasicInformation, &info, sizeof(info), NULL );
784 highest_user_address = (ULONG_PTR)info.HighestUserAddress;
785 default_zero_bits = (ULONG_PTR)info.HighestUserAddress | 0x7fffffff;
786 NtQueryInformationProcess( GetCurrentProcess(), ProcessWow64Information, &peb32, sizeof(peb32), NULL );
787 wow64info = (WOW64INFO *)(peb32 + 1);
788 wow64info->NativeSystemPageSize = 0x1000;
789 wow64info->NativeMachineType = native_machine;
790 wow64info->EmulatedMachineType = current_machine;
791 NtCurrentTeb()->TlsSlots[WOW64_TLS_WOW64INFO] = wow64info;
793 #define GET_PTR(name) p ## name = RtlFindExportedRoutineByName( module, #name )
795 LdrGetDllHandle( NULL, 0, &str, &module );
796 GET_PTR( LdrSystemDllInitBlock );
798 module = load_64bit_module( get_cpu_dll_name() );
799 GET_PTR( BTCpuGetBopCode );
800 GET_PTR( BTCpuGetContext );
801 GET_PTR( BTCpuIsProcessorFeaturePresent );
802 GET_PTR( BTCpuProcessInit );
803 GET_PTR( BTCpuThreadInit );
804 GET_PTR( BTCpuResetToConsistentState );
805 GET_PTR( BTCpuSetContext );
806 GET_PTR( BTCpuSimulate );
807 GET_PTR( BTCpuNotifyFlushInstructionCache2 );
808 GET_PTR( BTCpuNotifyMapViewOfSection );
809 GET_PTR( BTCpuNotifyMemoryAlloc );
810 GET_PTR( BTCpuNotifyMemoryDirty );
811 GET_PTR( BTCpuNotifyMemoryFree );
812 GET_PTR( BTCpuNotifyMemoryProtect );
813 GET_PTR( BTCpuNotifyUnmapViewOfSection );
814 GET_PTR( BTCpuUpdateProcessorInformation );
815 GET_PTR( BTCpuThreadTerm );
816 GET_PTR( __wine_get_unix_opcode );
818 module = load_64bit_module( L"wow64win.dll" );
819 GET_PTR( sdwhwin32 );
820 syscall_tables[1] = *psdwhwin32;
822 pBTCpuProcessInit();
824 module = (HMODULE)(ULONG_PTR)pLdrSystemDllInitBlock->ntdll_handle;
825 init_image_mapping( module );
826 GET_PTR( KiRaiseUserExceptionDispatcher );
827 GET_PTR( __wine_syscall_dispatcher );
828 GET_PTR( __wine_unix_call_dispatcher );
830 *p__wine_syscall_dispatcher = PtrToUlong( pBTCpuGetBopCode() );
831 *p__wine_unix_call_dispatcher = PtrToUlong( p__wine_get_unix_opcode() );
833 if (wow64info->CpuFlags & WOW64_CPUFLAGS_SOFTWARE) create_cross_process_work_list( wow64info );
835 init_file_redirects();
836 return TRUE;
838 #undef GET_PTR
842 /**********************************************************************
843 * thread_init
845 static void thread_init(void)
847 TEB32 *teb32 = (TEB32 *)((char *)NtCurrentTeb() + NtCurrentTeb()->WowTebOffset);
848 void *cpu_area_ctx;
850 teb32->WOW32Reserved = PtrToUlong( pBTCpuGetBopCode() );
851 RtlWow64GetCurrentCpuArea( NULL, &cpu_area_ctx, NULL );
852 NtCurrentTeb()->TlsSlots[WOW64_TLS_WOW64INFO] = wow64info;
853 if (pBTCpuThreadInit) pBTCpuThreadInit();
855 /* update initial context to jump to 32-bit LdrInitializeThunk (cf. 32-bit call_init_thunk) */
856 switch (current_machine)
858 case IMAGE_FILE_MACHINE_I386:
860 I386_CONTEXT *ctx_ptr, *ctx = cpu_area_ctx;
861 ULONG *stack;
863 ctx_ptr = (I386_CONTEXT *)ULongToPtr( ctx->Esp ) - 1;
864 *ctx_ptr = *ctx;
866 stack = (ULONG *)ctx_ptr;
867 *(--stack) = 0;
868 *(--stack) = 0;
869 *(--stack) = 0;
870 *(--stack) = PtrToUlong( ctx_ptr );
871 *(--stack) = 0xdeadbabe;
872 ctx->Esp = PtrToUlong( stack );
873 ctx->Eip = pLdrSystemDllInitBlock->pLdrInitializeThunk;
874 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL, ctx );
876 break;
878 case IMAGE_FILE_MACHINE_ARMNT:
880 ARM_CONTEXT *ctx_ptr, *ctx = cpu_area_ctx;
882 ctx_ptr = (ARM_CONTEXT *)ULongToPtr( ctx->Sp & ~15 ) - 1;
883 *ctx_ptr = *ctx;
885 ctx->R0 = PtrToUlong( ctx_ptr );
886 ctx->Sp = PtrToUlong( ctx_ptr );
887 ctx->Pc = pLdrSystemDllInitBlock->pLdrInitializeThunk;
888 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL, ctx );
890 break;
892 default:
893 ERR( "not supported machine %x\n", current_machine );
894 NtTerminateProcess( GetCurrentProcess(), STATUS_INVALID_IMAGE_FORMAT );
899 /**********************************************************************
900 * free_temp_data
902 static void free_temp_data(void)
904 struct mem_header *next, *mem;
906 for (mem = NtCurrentTeb()->TlsSlots[WOW64_TLS_TEMPLIST]; mem; mem = next)
908 next = mem->next;
909 RtlFreeHeap( GetProcessHeap(), 0, mem );
911 NtCurrentTeb()->TlsSlots[WOW64_TLS_TEMPLIST] = NULL;
915 /**********************************************************************
916 * wow64_syscall
918 #ifdef __aarch64__
919 NTSTATUS wow64_syscall( UINT *args, ULONG_PTR thunk );
920 __ASM_GLOBAL_FUNC( wow64_syscall,
921 "stp x29, x30, [sp, #-16]!\n\t"
922 ".seh_save_fplr_x 16\n\t"
923 ".seh_endprologue\n\t"
924 ".seh_handler wow64_syscall_handler, @except\n"
925 "blr x1\n\t"
926 "b 1f\n"
927 "wow64_syscall_ret:\n\t"
928 "eor w1, w0, #0xc0000000\n\t"
929 "cmp w1, #8\n\t" /* STATUS_INVALID_HANDLE */
930 "b.ne 1f\n\t"
931 "bl call_raise_user_exception_dispatcher\n"
932 "1:\tldp x29, x30, [sp], #16\n\t"
933 "ret" )
934 __ASM_GLOBAL_FUNC( wow64_syscall_handler,
935 "stp x29, x30, [sp, #-16]!\n\t"
936 ".seh_save_fplr_x 16\n\t"
937 ".seh_endprologue\n\t"
938 "ldr w4, [x0, #4]\n\t" /* record->ExceptionFlags */
939 "tst w4, #6\n\t" /* EXCEPTION_UNWINDING | EXCEPTION_EXIT_UNWIND */
940 "b.ne 1f\n\t"
941 "mov x2, x0\n\t" /* record */
942 "mov x0, x1\n\t" /* frame */
943 "adr x1, wow64_syscall_ret\n\t" /* target */
944 "ldr w3, [x2]\n\t" /* retval = record->ExceptionCode */
945 "bl RtlUnwind\n\t"
946 "1:\tmov w0, #1\n\t" /* ExceptionContinueSearch */
947 "ldp x29, x30, [sp], #16\n\t"
948 "ret" )
949 #else
950 NTSTATUS wow64_syscall( UINT *args, ULONG_PTR thunk );
951 __ASM_GLOBAL_FUNC( wow64_syscall,
952 "subq $0x28, %rsp\n\t"
953 ".seh_stackalloc 0x28\n\t"
954 ".seh_endprologue\n\t"
955 ".seh_handler wow64_syscall_handler, @except\n\t"
956 "call *%rdx\n\t"
957 "jmp 1f\n"
958 "wow64_syscall_ret:\n\t"
959 "cmpl $0xc0000008,%eax\n\t" /* STATUS_INVALID_HANDLE */
960 "jne 1f\n\t"
961 "movl %eax,%ecx\n\t"
962 "call call_raise_user_exception_dispatcher\n"
963 "1:\taddq $0x28, %rsp\n\t"
964 "ret" )
965 __ASM_GLOBAL_FUNC( wow64_syscall_handler,
966 "subq $0x28,%rsp\n\t"
967 ".seh_stackalloc 0x28\n\t"
968 ".seh_endprologue\n\t"
969 "movl (%rcx),%r9d\n\t" /* retval = rec->ExceptionCode */
970 "movq %rcx,%r8\n\t" /* rec */
971 "movq %rdx,%rcx\n\t" /* frame */
972 "leaq wow64_syscall_ret(%rip),%rdx\n\t"
973 "call RtlUnwind\n\t"
974 "int3" )
975 #endif
978 /**********************************************************************
979 * Wow64SystemServiceEx (wow64.@)
981 NTSTATUS WINAPI Wow64SystemServiceEx( UINT num, UINT *args )
983 NTSTATUS status;
984 UINT id = num & 0xfff;
985 const SYSTEM_SERVICE_TABLE *table = &syscall_tables[(num >> 12) & 3];
987 if (id >= table->ServiceLimit)
989 ERR( "unsupported syscall %04x\n", num );
990 return STATUS_INVALID_SYSTEM_SERVICE;
992 status = wow64_syscall( args, table->ServiceTable[id] );
993 free_temp_data();
994 return status;
998 /**********************************************************************
999 * cpu_simulate
1001 #ifdef __aarch64__
1002 extern void DECLSPEC_NORETURN cpu_simulate(void);
1003 __ASM_GLOBAL_FUNC( cpu_simulate,
1004 "stp x29, x30, [sp, #-16]!\n\t"
1005 ".seh_save_fplr_x 16\n\t"
1006 ".seh_endprologue\n\t"
1007 ".seh_handler cpu_simulate_handler, @except\n"
1008 ".Lcpu_simulate_loop:\n\t"
1009 "adrp x16, pBTCpuSimulate\n\t"
1010 "ldr x16, [x16, :lo12:pBTCpuSimulate]\n\t"
1011 "blr x16\n\t"
1012 "b .Lcpu_simulate_loop" )
1013 __ASM_GLOBAL_FUNC( cpu_simulate_handler,
1014 "stp x29, x30, [sp, #-48]!\n\t"
1015 ".seh_save_fplr_x 48\n\t"
1016 "stp x19, x20, [sp, #16]\n\t"
1017 ".seh_save_regp x19, 16\n\t"
1018 ".seh_endprologue\n\t"
1019 "mov x19, x0\n\t" /* record */
1020 "mov x20, x1\n\t" /* frame */
1021 "ldr w4, [x0, #4]\n\t" /* record->ExceptionFlags */
1022 "tst w4, #6\n\t" /* EXCEPTION_UNWINDING | EXCEPTION_EXIT_UNWIND */
1023 "b.ne 1f\n\t"
1024 "stp x0, x2, [sp, #32]\n\t" /* record, context */
1025 "add x0, sp, #32\n\t"
1026 "bl Wow64PassExceptionToGuest\n\t"
1027 "mov x0, x20\n\t" /* frame */
1028 "adr x1, .Lcpu_simulate_loop\n\t" /* target */
1029 "mov x2, x19\n\t" /* record */
1030 "bl RtlUnwind\n\t"
1031 "1:\tmov w0, #1\n\t" /* ExceptionContinueSearch */
1032 "ldp x19, x20, [sp, #16]\n\t"
1033 "ldp x29, x30, [sp], #48\n\t"
1034 "ret" )
1035 #else
1036 extern void DECLSPEC_NORETURN cpu_simulate(void);
1037 __ASM_GLOBAL_FUNC( cpu_simulate,
1038 "subq $0x28, %rsp\n\t"
1039 ".seh_stackalloc 0x28\n\t"
1040 ".seh_endprologue\n\t"
1041 ".seh_handler cpu_simulate_handler, @except\n\t"
1042 ".Lcpu_simulate_loop:\n\t"
1043 "call *pBTCpuSimulate(%rip)\n\t"
1044 "jmp .Lcpu_simulate_loop" )
1045 __ASM_GLOBAL_FUNC( cpu_simulate_handler,
1046 "subq $0x38, %rsp\n\t"
1047 ".seh_stackalloc 0x38\n\t"
1048 ".seh_endprologue\n\t"
1049 "movq %rcx,%rsi\n\t" /* record */
1050 "movq %rcx,0x20(%rsp)\n\t"
1051 "movq %rdx,%rdi\n\t" /* frame */
1052 "movq %r8,0x28(%rsp)\n\t" /* context */
1053 "leaq 0x20(%rsp),%rcx\n\t"
1054 "call Wow64PassExceptionToGuest\n\t"
1055 "movq %rdi,%rcx\n\t" /* frame */
1056 "leaq .Lcpu_simulate_loop(%rip), %rdx\n\t" /* target */
1057 "movq %rsi,%r8\n\t" /* record */
1058 "call RtlUnwind\n\t"
1059 "int3" )
1060 #endif
1063 /**********************************************************************
1064 * Wow64AllocateTemp (wow64.@)
1066 * FIXME: probably not 100% compatible.
1068 void * WINAPI Wow64AllocateTemp( SIZE_T size )
1070 struct mem_header *mem;
1072 if (!(mem = RtlAllocateHeap( GetProcessHeap(), 0, offsetof( struct mem_header, data[size] ))))
1073 return NULL;
1074 mem->next = NtCurrentTeb()->TlsSlots[WOW64_TLS_TEMPLIST];
1075 NtCurrentTeb()->TlsSlots[WOW64_TLS_TEMPLIST] = mem;
1076 return mem->data;
1080 /**********************************************************************
1081 * Wow64ApcRoutine (wow64.@)
1083 void WINAPI Wow64ApcRoutine( ULONG_PTR arg1, ULONG_PTR arg2, ULONG_PTR arg3, CONTEXT *context )
1085 struct user_apc_frame frame;
1087 frame.prev_frame = NtCurrentTeb()->TlsSlots[WOW64_TLS_APCLIST];
1088 frame.context = context;
1089 NtCurrentTeb()->TlsSlots[WOW64_TLS_APCLIST] = &frame;
1091 /* cf. 32-bit call_user_apc_dispatcher */
1092 switch (current_machine)
1094 case IMAGE_FILE_MACHINE_I386:
1096 /* stack layout when calling 32-bit KiUserApcDispatcher */
1097 struct apc_stack_layout32
1099 ULONG func; /* 000 */
1100 UINT arg1; /* 004 */
1101 UINT arg2; /* 008 */
1102 UINT arg3; /* 00c */
1103 UINT alertable; /* 010 */
1104 I386_CONTEXT context; /* 014 */
1105 CONTEXT_EX32 xctx; /* 2e0 */
1106 UINT unk2[4]; /* 2f8 */
1107 } *stack;
1108 I386_CONTEXT ctx = { CONTEXT_I386_FULL };
1110 C_ASSERT( offsetof(struct apc_stack_layout32, context) == 0x14 );
1111 C_ASSERT( sizeof(struct apc_stack_layout32) == 0x308 );
1113 pBTCpuGetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx );
1115 stack = (struct apc_stack_layout32 *)ULongToPtr( ctx.Esp & ~3 ) - 1;
1116 stack->func = arg1 >> 32;
1117 stack->arg1 = arg1;
1118 stack->arg2 = arg2;
1119 stack->arg3 = arg3;
1120 stack->alertable = TRUE;
1121 stack->context = ctx;
1122 stack->xctx.Legacy.Offset = -(LONG)sizeof(stack->context);
1123 stack->xctx.Legacy.Length = sizeof(stack->context);
1124 stack->xctx.All.Offset = -(LONG)sizeof(stack->context);
1125 stack->xctx.All.Length = sizeof(stack->context) + sizeof(stack->xctx);
1126 stack->xctx.XState.Offset = 25;
1127 stack->xctx.XState.Length = 0;
1129 ctx.Esp = PtrToUlong( stack );
1130 ctx.Eip = pLdrSystemDllInitBlock->pKiUserApcDispatcher;
1131 frame.wow_context = &stack->context;
1132 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx );
1133 cpu_simulate();
1135 break;
1137 case IMAGE_FILE_MACHINE_ARMNT:
1139 struct apc_stack_layout
1141 ULONG func;
1142 ULONG align[3];
1143 ARM_CONTEXT context;
1144 } *stack;
1145 ARM_CONTEXT ctx = { CONTEXT_ARM_FULL };
1147 pBTCpuGetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx );
1148 stack = (struct apc_stack_layout *)ULongToPtr( ctx.Sp & ~15 ) - 1;
1149 stack->func = arg1 >> 32;
1150 stack->context = ctx;
1151 ctx.Sp = PtrToUlong( stack );
1152 ctx.Pc = pLdrSystemDllInitBlock->pKiUserApcDispatcher;
1153 ctx.R0 = PtrToUlong( &stack->context );
1154 ctx.R1 = arg1;
1155 ctx.R2 = arg2;
1156 ctx.R3 = arg3;
1157 frame.wow_context = &stack->context;
1158 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx );
1159 cpu_simulate();
1161 break;
1166 /**********************************************************************
1167 * Wow64KiUserCallbackDispatcher (wow64.@)
1169 NTSTATUS WINAPI Wow64KiUserCallbackDispatcher( ULONG id, void *args, ULONG len,
1170 void **ret_ptr, ULONG *ret_len )
1172 WOW64_CPURESERVED *cpu = NtCurrentTeb()->TlsSlots[WOW64_TLS_CPURESERVED];
1173 TEB32 *teb32 = (TEB32 *)((char *)NtCurrentTeb() + NtCurrentTeb()->WowTebOffset);
1174 ULONG teb_frame = teb32->Tib.ExceptionList;
1175 struct user_callback_frame frame;
1176 USHORT flags = cpu->Flags;
1178 frame.prev_frame = NtCurrentTeb()->TlsSlots[WOW64_TLS_USERCALLBACKDATA];
1179 frame.temp_list = NtCurrentTeb()->TlsSlots[WOW64_TLS_TEMPLIST];
1180 frame.ret_ptr = ret_ptr;
1181 frame.ret_len = ret_len;
1183 NtCurrentTeb()->TlsSlots[WOW64_TLS_USERCALLBACKDATA] = &frame;
1184 NtCurrentTeb()->TlsSlots[WOW64_TLS_TEMPLIST] = NULL;
1186 /* cf. 32-bit KeUserModeCallback */
1187 switch (current_machine)
1189 case IMAGE_FILE_MACHINE_I386:
1191 /* stack layout when calling 32-bit KiUserCallbackDispatcher */
1192 struct callback_stack_layout32
1194 ULONG eip; /* 000 */
1195 ULONG id; /* 004 */
1196 ULONG args; /* 008 */
1197 ULONG len; /* 00c */
1198 ULONG unk[2]; /* 010 */
1199 ULONG esp; /* 018 */
1200 BYTE args_data[0]; /* 01c */
1201 } *stack;
1202 I386_CONTEXT orig_ctx, ctx = { CONTEXT_I386_FULL };
1204 C_ASSERT( sizeof(struct callback_stack_layout32) == 0x1c );
1206 pBTCpuGetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx );
1207 orig_ctx = ctx;
1209 stack = ULongToPtr( (ctx.Esp - offsetof(struct callback_stack_layout32,args_data[len])) & ~15 );
1210 stack->eip = ctx.Eip;
1211 stack->id = id;
1212 stack->args = PtrToUlong( stack->args_data );
1213 stack->len = len;
1214 stack->esp = ctx.Esp;
1215 memcpy( stack->args_data, args, len );
1217 ctx.Esp = PtrToUlong( stack );
1218 ctx.Eip = pLdrSystemDllInitBlock->pKiUserCallbackDispatcher;
1219 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx );
1221 if (!setjmp( frame.jmpbuf ))
1222 cpu_simulate();
1223 else
1224 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &orig_ctx );
1226 break;
1228 case IMAGE_FILE_MACHINE_ARMNT:
1230 ARM_CONTEXT orig_ctx, ctx = { CONTEXT_ARM_FULL };
1231 void *args_data;
1233 pBTCpuGetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx );
1234 orig_ctx = ctx;
1236 args_data = ULongToPtr( (ctx.Sp - len) & ~15 );
1237 memcpy( args_data, args, len );
1239 ctx.R0 = id;
1240 ctx.R1 = PtrToUlong( args_data );
1241 ctx.R2 = len;
1242 ctx.Sp = PtrToUlong( args_data );
1243 ctx.Pc = pLdrSystemDllInitBlock->pKiUserCallbackDispatcher;
1244 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx );
1246 if (!setjmp( frame.jmpbuf ))
1247 cpu_simulate();
1248 else
1249 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &orig_ctx );
1251 break;
1254 teb32->Tib.ExceptionList = teb_frame;
1255 NtCurrentTeb()->TlsSlots[WOW64_TLS_USERCALLBACKDATA] = frame.prev_frame;
1256 NtCurrentTeb()->TlsSlots[WOW64_TLS_TEMPLIST] = frame.temp_list;
1257 cpu->Flags = flags;
1258 return frame.status;
1262 /**********************************************************************
1263 * Wow64LdrpInitialize (wow64.@)
1265 void WINAPI Wow64LdrpInitialize( CONTEXT *context )
1267 static RTL_RUN_ONCE init_done;
1269 RtlRunOnceExecuteOnce( &init_done, process_init, NULL, NULL );
1270 thread_init();
1271 cpu_simulate();
1275 /**********************************************************************
1276 * Wow64PrepareForException (wow64.@)
1278 #ifdef __x86_64__
1279 __ASM_GLOBAL_FUNC( Wow64PrepareForException,
1280 "sub $0x38,%rsp\n\t"
1281 "mov %rcx,%r10\n\t" /* rec */
1282 "movw %cs,%ax\n\t"
1283 "cmpw %ax,0x38(%rdx)\n\t" /* context->SegCs */
1284 "je 1f\n\t" /* already in 64-bit mode? */
1285 /* copy arguments to 64-bit stack */
1286 "mov %rsp,%rsi\n\t"
1287 "mov 0x98(%rdx),%rcx\n\t" /* context->Rsp */
1288 "sub %rsi,%rcx\n\t" /* stack size */
1289 "sub %rcx,%r14\n\t" /* reserve same size on 64-bit stack */
1290 "and $~0x0f,%r14\n\t"
1291 "mov %r14,%rdi\n\t"
1292 "shr $3,%rcx\n\t"
1293 "rep; movsq\n\t"
1294 /* update arguments to point to the new stack */
1295 "mov %r14,%rax\n\t"
1296 "sub %rsp,%rax\n\t"
1297 "add %rax,%r10\n\t" /* rec */
1298 "add %rax,%rdx\n\t" /* context */
1299 /* switch to 64-bit stack */
1300 "mov %r14,%rsp\n"
1301 /* build EXCEPTION_POINTERS structure and call BTCpuResetToConsistentState */
1302 "1:\tlea 0x20(%rsp),%rcx\n\t" /* pointers */
1303 "mov %r10,(%rcx)\n\t" /* rec */
1304 "mov %rdx,8(%rcx)\n\t" /* context */
1305 "mov " __ASM_NAME("pBTCpuResetToConsistentState") "(%rip),%rax\n\t"
1306 "call *%rax\n\t"
1307 "add $0x38,%rsp\n\t"
1308 "ret" )
1309 #else
1310 void WINAPI Wow64PrepareForException( EXCEPTION_RECORD *rec, CONTEXT *context )
1312 EXCEPTION_POINTERS ptrs = { rec, context };
1314 pBTCpuResetToConsistentState( &ptrs );
1316 #endif
1319 /**********************************************************************
1320 * Wow64PassExceptionToGuest (wow64.@)
1322 void WINAPI Wow64PassExceptionToGuest( EXCEPTION_POINTERS *ptrs )
1324 EXCEPTION_RECORD32 rec32;
1326 exception_record_64to32( &rec32, ptrs->ExceptionRecord );
1327 call_user_exception_dispatcher( &rec32, NULL, ptrs->ContextRecord );
1331 /**********************************************************************
1332 * Wow64ProcessPendingCrossProcessItems (wow64.@)
1334 void WINAPI Wow64ProcessPendingCrossProcessItems(void)
1336 CROSS_PROCESS_WORK_LIST *list = (void *)wow64info->CrossProcessWorkList;
1337 CROSS_PROCESS_WORK_ENTRY *entry;
1338 BOOLEAN flush = FALSE;
1339 UINT next;
1341 if (!list) return;
1342 entry = RtlWow64PopAllCrossProcessWorkFromWorkList( &list->work_list, &flush );
1344 if (flush)
1346 if (pBTCpuNotifyFlushInstructionCache2) pBTCpuNotifyFlushInstructionCache2( NULL, ~0ull );
1347 while (entry)
1349 next = entry->next;
1350 RtlWow64PushCrossProcessWorkOntoFreeList( &list->free_list, entry );
1351 entry = CROSS_PROCESS_LIST_ENTRY( &list->work_list, next );
1353 return;
1356 while (entry)
1358 switch (entry->id)
1360 case CrossProcessPreVirtualAlloc:
1361 /* FIXME */
1362 break;
1363 case CrossProcessPostVirtualAlloc:
1364 if (!pBTCpuNotifyMemoryAlloc) break;
1365 if (entry->args[2]) break;
1366 pBTCpuNotifyMemoryAlloc( (void *)entry->addr, entry->size, entry->args[0], entry->args[1] );
1367 break;
1368 case CrossProcessPreVirtualFree:
1369 if (!pBTCpuNotifyMemoryFree) break;
1370 pBTCpuNotifyMemoryFree( (void *)entry->addr, entry->size, entry->args[0] );
1371 break;
1372 case CrossProcessPostVirtualFree:
1373 /* FIXME */
1374 break;
1375 case CrossProcessPreVirtualProtect:
1376 if (!pBTCpuNotifyMemoryProtect) break;
1377 pBTCpuNotifyMemoryProtect( (void *)entry->addr, entry->size, entry->args[0] );
1378 break;
1379 case CrossProcessPostVirtualProtect:
1380 /* FIXME */
1381 break;
1382 case CrossProcessFlushCache:
1383 if (!pBTCpuNotifyFlushInstructionCache2) break;
1384 pBTCpuNotifyFlushInstructionCache2( (void *)entry->addr, entry->size );
1385 break;
1387 next = entry->next;
1388 RtlWow64PushCrossProcessWorkOntoFreeList( &list->free_list, entry );
1389 entry = CROSS_PROCESS_LIST_ENTRY( &list->work_list, next );
1394 /**********************************************************************
1395 * Wow64RaiseException (wow64.@)
1397 NTSTATUS WINAPI Wow64RaiseException( int code, EXCEPTION_RECORD *rec )
1399 EXCEPTION_RECORD32 rec32;
1400 BOOL first_chance = TRUE;
1401 union
1403 I386_CONTEXT i386;
1404 ARM_CONTEXT arm;
1405 } ctx32 = { 0 };
1407 switch (current_machine)
1409 case IMAGE_FILE_MACHINE_I386:
1411 EXCEPTION_RECORD int_rec = { 0 };
1413 ctx32.i386.ContextFlags = CONTEXT_I386_ALL;
1414 pBTCpuGetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx32.i386 );
1415 if (code == -1) break;
1416 int_rec.ExceptionAddress = (void *)(ULONG_PTR)ctx32.i386.Eip;
1417 switch (code)
1419 case 0x00: /* division by zero */
1420 int_rec.ExceptionCode = EXCEPTION_INT_DIVIDE_BY_ZERO;
1421 break;
1422 case 0x01: /* single-step */
1423 ctx32.i386.EFlags &= ~0x100;
1424 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx32.i386 );
1425 int_rec.ExceptionCode = EXCEPTION_SINGLE_STEP;
1426 break;
1427 case 0x03: /* breakpoint */
1428 int_rec.ExceptionCode = EXCEPTION_BREAKPOINT;
1429 int_rec.ExceptionAddress = (void *)(ULONG_PTR)(ctx32.i386.Eip - 1);
1430 int_rec.NumberParameters = 1;
1431 break;
1432 case 0x04: /* overflow */
1433 int_rec.ExceptionCode = EXCEPTION_INT_OVERFLOW;
1434 break;
1435 case 0x05: /* array bounds */
1436 int_rec.ExceptionCode = EXCEPTION_ARRAY_BOUNDS_EXCEEDED;
1437 break;
1438 case 0x06: /* invalid opcode */
1439 int_rec.ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION;
1440 break;
1441 case 0x09: /* coprocessor segment overrun */
1442 int_rec.ExceptionCode = EXCEPTION_FLT_INVALID_OPERATION;
1443 break;
1444 case 0x0c: /* stack fault */
1445 int_rec.ExceptionCode = EXCEPTION_STACK_OVERFLOW;
1446 break;
1447 case 0x0d: /* general protection fault */
1448 int_rec.ExceptionCode = EXCEPTION_PRIV_INSTRUCTION;
1449 break;
1450 case 0x29: /* __fastfail */
1451 int_rec.ExceptionCode = STATUS_STACK_BUFFER_OVERRUN;
1452 int_rec.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
1453 int_rec.NumberParameters = 1;
1454 int_rec.ExceptionInformation[0] = ctx32.i386.Ecx;
1455 first_chance = FALSE;
1456 break;
1457 case 0x2d: /* debug service */
1458 ctx32.i386.Eip += 3;
1459 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx32.i386 );
1460 int_rec.ExceptionCode = EXCEPTION_BREAKPOINT;
1461 int_rec.ExceptionAddress = (void *)(ULONG_PTR)ctx32.i386.Eip;
1462 int_rec.NumberParameters = 1;
1463 int_rec.ExceptionInformation[0] = ctx32.i386.Eax;
1464 break;
1465 default:
1466 int_rec.ExceptionCode = EXCEPTION_ACCESS_VIOLATION;
1467 int_rec.ExceptionAddress = (void *)(ULONG_PTR)ctx32.i386.Eip;
1468 int_rec.NumberParameters = 2;
1469 int_rec.ExceptionInformation[1] = 0xffffffff;
1470 break;
1472 *rec = int_rec;
1473 break;
1476 case IMAGE_FILE_MACHINE_ARMNT:
1477 ctx32.arm.ContextFlags = CONTEXT_ARM_ALL;
1478 pBTCpuGetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx32.arm );
1479 break;
1482 exception_record_64to32( &rec32, rec );
1483 raise_exception( &rec32, &ctx32, first_chance, rec );
1485 return STATUS_SUCCESS;