include: Add STORAGE_HOTPLUG_INFO structure.
[wine.git] / dlls / wow64 / syscall.c
blob40eb532793457ef172edcb10a590ff9f0d99d42f
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 CONTEXT_EX32 context_ex; /* 324 */
201 BYTE xstate[sizeof(XSTATE)+64]; /* 33c */
202 DWORD align; /* 4bc */
203 } *stack;
204 I386_CONTEXT ctx = { CONTEXT_I386_ALL };
205 CONTEXT_EX *context_ex, *src_ex = NULL;
206 ULONG flags;
208 C_ASSERT( offsetof(struct exc_stack_layout32, context) == 0x58 );
209 C_ASSERT( offsetof(struct exc_stack_layout32, xstate) == 0x33c );
210 C_ASSERT( sizeof(struct exc_stack_layout32) == 0x4c0 );
212 pBTCpuGetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx );
214 if (ctx32_ptr)
216 I386_CONTEXT *ctx32 = ctx32_ptr;
218 if ((ctx32->ContextFlags & CONTEXT_I386_XSTATE) == CONTEXT_I386_XSTATE)
219 src_ex = (CONTEXT_EX *)(ctx32 + 1);
221 else if (native_machine == IMAGE_FILE_MACHINE_AMD64)
223 AMD64_CONTEXT *ctx64 = ctx64_ptr;
225 if ((ctx64->ContextFlags & CONTEXT_AMD64_FLOATING_POINT) == CONTEXT_AMD64_FLOATING_POINT)
226 memcpy( ctx.ExtendedRegisters, &ctx64->FltSave, sizeof(ctx.ExtendedRegisters) );
227 if ((ctx64->ContextFlags & CONTEXT_AMD64_XSTATE) == CONTEXT_AMD64_XSTATE)
228 src_ex = (CONTEXT_EX *)(ctx64 + 1);
231 flags = ctx.ContextFlags;
232 if (src_ex) flags |= CONTEXT_I386_XSTATE;
234 stack = (struct exc_stack_layout32 *)ULongToPtr( ctx.Esp & ~3 ) - 1;
235 stack->rec_ptr = PtrToUlong( &stack->rec );
236 stack->context_ptr = PtrToUlong( &stack->context );
237 stack->rec = *rec;
238 stack->context = ctx;
239 RtlInitializeExtendedContext( &stack->context, flags, &context_ex );
240 /* adjust Eip for breakpoints in software emulation (hardware exceptions already adjust Rip) */
241 if (rec->ExceptionCode == EXCEPTION_BREAKPOINT && (wow64info->CpuFlags & WOW64_CPUFLAGS_SOFTWARE))
242 stack->context.Eip--;
244 if (src_ex)
246 XSTATE *src_xs = (XSTATE *)((char *)src_ex + src_ex->XState.Offset);
247 XSTATE *dst_xs = (XSTATE *)((char *)context_ex + context_ex->XState.Offset);
249 dst_xs->Mask = src_xs->Mask & ~(ULONG64)3;
250 dst_xs->CompactionMask = src_xs->CompactionMask;
251 if ((dst_xs->Mask & 4) &&
252 src_ex->XState.Length >= sizeof(XSTATE) &&
253 context_ex->XState.Length >= sizeof(XSTATE))
254 memcpy( &dst_xs->YmmContext, &src_xs->YmmContext, sizeof(dst_xs->YmmContext) );
257 ctx.Esp = PtrToUlong( stack );
258 ctx.Eip = pLdrSystemDllInitBlock->pKiUserExceptionDispatcher;
259 ctx.EFlags &= ~(0x100|0x400|0x40000);
260 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx );
262 TRACE( "exception %08lx dispatcher %08lx stack %08lx eip %08lx\n",
263 rec->ExceptionCode, ctx.Eip, ctx.Esp, stack->context.Eip );
265 break;
267 case IMAGE_FILE_MACHINE_ARMNT:
269 struct stack_layout
271 ARM_CONTEXT context;
272 EXCEPTION_RECORD32 rec;
273 } *stack;
274 ARM_CONTEXT ctx = { CONTEXT_ARM_ALL };
276 pBTCpuGetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx );
277 stack = (struct stack_layout *)(ULONG_PTR)(ctx.Sp & ~3) - 1;
278 stack->rec = *rec;
279 stack->context = ctx;
281 ctx.R0 = PtrToUlong( &stack->rec ); /* first arg for KiUserExceptionDispatcher */
282 ctx.R1 = PtrToUlong( &stack->context ); /* second arg for KiUserExceptionDispatcher */
283 ctx.Sp = PtrToUlong( stack );
284 ctx.Pc = pLdrSystemDllInitBlock->pKiUserExceptionDispatcher;
285 if (ctx.Pc & 1) ctx.Cpsr |= 0x20;
286 else ctx.Cpsr &= ~0x20;
287 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx );
289 TRACE( "exception %08lx dispatcher %08lx stack %08lx pc %08lx\n",
290 rec->ExceptionCode, ctx.Pc, ctx.Sp, stack->context.Sp );
292 break;
297 /**********************************************************************
298 * call_raise_user_exception_dispatcher
300 static void __attribute__((used)) call_raise_user_exception_dispatcher( ULONG code )
302 TEB32 *teb32 = (TEB32 *)((char *)NtCurrentTeb() + NtCurrentTeb()->WowTebOffset);
304 teb32->ExceptionCode = code;
306 switch (current_machine)
308 case IMAGE_FILE_MACHINE_I386:
310 I386_CONTEXT ctx = { CONTEXT_I386_ALL };
312 pBTCpuGetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx );
313 ctx.Esp -= sizeof(ULONG);
314 *(ULONG *)ULongToPtr( ctx.Esp ) = ctx.Eip;
315 ctx.Eip = (ULONG_PTR)pKiRaiseUserExceptionDispatcher;
316 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx );
318 break;
320 case IMAGE_FILE_MACHINE_ARMNT:
322 ARM_CONTEXT ctx = { CONTEXT_ARM_ALL };
324 pBTCpuGetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx );
325 ctx.Pc = (ULONG_PTR)pKiRaiseUserExceptionDispatcher;
326 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx );
328 break;
333 /* based on RtlRaiseException: call NtRaiseException with context setup to return to caller */
334 void WINAPI raise_exception( EXCEPTION_RECORD32 *rec32, void *ctx32,
335 BOOL first_chance, EXCEPTION_RECORD *rec );
336 #ifdef __aarch64__
337 __ASM_GLOBAL_FUNC( raise_exception,
338 "sub sp, sp, #0x390\n\t" /* sizeof(context) */
339 ".seh_stackalloc 0x390\n\t"
340 "stp x29, x30, [sp, #-48]!\n\t"
341 ".seh_save_fplr_x 48\n\t"
342 ".seh_endprologue\n\t"
343 ".seh_handler raise_exception_handler, @except\n\t"
344 "stp x0, x1, [sp, #16]\n\t"
345 "stp x2, x3, [sp, #32]\n\t"
346 "add x0, sp, #48\n\t"
347 "bl RtlCaptureContext\n\t"
348 "add x1, sp, #48\n\t" /* context */
349 "adr x2, 1f\n\t" /* return address */
350 "str x2, [x1, #0x108]\n\t" /* context->Pc */
351 "ldp x2, x0, [sp, #32]\n\t" /* first_chance, rec */
352 "bl NtRaiseException\n"
353 "raise_exception_ret:\n\t"
354 "ldp x0, x1, [sp, #16]\n\t" /* rec32, ctx32 */
355 "add x2, sp, #48\n\t" /* context */
356 "bl call_user_exception_dispatcher\n"
357 "1:\tnop\n\t"
358 "ldp x29, x30, [sp], #48\n\t"
359 "add sp, sp, #0x390\n\t"
360 "ret" )
361 __ASM_GLOBAL_FUNC( raise_exception_handler,
362 "stp x29, x30, [sp, #-16]!\n\t"
363 ".seh_save_fplr_x 16\n\t"
364 ".seh_endprologue\n\t"
365 "ldr w4, [x0, #4]\n\t" /* record->ExceptionFlags */
366 "tst w4, #6\n\t" /* EXCEPTION_UNWINDING | EXCEPTION_EXIT_UNWIND */
367 "b.ne 1f\n\t"
368 "mov x2, x0\n\t" /* rec */
369 "mov x0, x1\n\t" /* frame */
370 "adr x1, raise_exception_ret\n\t"
371 "bl RtlUnwind\n"
372 "1:\tmov w0, #1\n\t" /* ExceptionContinueSearch */
373 "ldp x29, x30, [sp], #16\n\t"
374 "ret" )
375 #else
376 __ASM_GLOBAL_FUNC( raise_exception,
377 "sub $0x4d8,%rsp\n\t" /* sizeof(context) + alignment */
378 ".seh_stackalloc 0x4d8\n\t"
379 ".seh_endprologue\n\t"
380 ".seh_handler raise_exception_handler, @except\n\t"
381 "movq %rcx,0x4e0(%rsp)\n\t"
382 "movq %rdx,0x4e8(%rsp)\n\t"
383 "movq %r8,0x4f0(%rsp)\n\t"
384 "movq %r9,0x4f8(%rsp)\n\t"
385 "movq %rsp,%rcx\n\t"
386 "call RtlCaptureContext\n\t"
387 "movq %rsp,%rdx\n\t" /* context */
388 "leaq 1f(%rip),%rax\n\t" /* return address */
389 "movq %rax,0xf8(%rdx)\n\t" /* context->Rip */
390 "movq 0x4f8(%rsp),%rcx\n\t" /* rec */
391 "movq 0x4f0(%rsp),%r8\n\t" /* first_chance */
392 "call NtRaiseException\n"
393 "raise_exception_ret:\n\t"
394 "mov 0x4e0(%rsp),%rcx\n\t" /* rec32 */
395 "mov 0x4e8(%rsp),%rdx\n\t" /* ctx32 */
396 "movq %rsp,%r8\n\t" /* context */
397 "call call_user_exception_dispatcher\n"
398 "1:\tnop\n\t"
399 "add $0x4d8,%rsp\n\t"
400 "ret" )
401 __ASM_GLOBAL_FUNC( raise_exception_handler,
402 "sub $0x28,%rsp\n\t"
403 ".seh_stackalloc 0x28\n\t"
404 ".seh_endprologue\n\t"
405 "movq %rcx,%r8\n\t" /* rec */
406 "movq %rdx,%rcx\n\t" /* frame */
407 "leaq raise_exception_ret(%rip),%rdx\n\t"
408 "call RtlUnwind\n\t"
409 "int3" )
410 #endif
413 /**********************************************************************
414 * wow64_NtAddAtom
416 NTSTATUS WINAPI wow64_NtAddAtom( UINT *args )
418 const WCHAR *name = get_ptr( &args );
419 ULONG len = get_ulong( &args );
420 RTL_ATOM *atom = get_ptr( &args );
422 return NtAddAtom( name, len, atom );
426 /**********************************************************************
427 * wow64_NtAllocateLocallyUniqueId
429 NTSTATUS WINAPI wow64_NtAllocateLocallyUniqueId( UINT *args )
431 LUID *luid = get_ptr( &args );
433 return NtAllocateLocallyUniqueId( luid );
437 /**********************************************************************
438 * wow64_NtAllocateUuids
440 NTSTATUS WINAPI wow64_NtAllocateUuids( UINT *args )
442 ULARGE_INTEGER *time = get_ptr( &args );
443 ULONG *delta = get_ptr( &args );
444 ULONG *sequence = get_ptr( &args );
445 UCHAR *seed = get_ptr( &args );
447 return NtAllocateUuids( time, delta, sequence, seed );
451 /***********************************************************************
452 * wow64_NtCallbackReturn
454 NTSTATUS WINAPI wow64_NtCallbackReturn( UINT *args )
456 void *ret_ptr = get_ptr( &args );
457 ULONG ret_len = get_ulong( &args );
458 NTSTATUS status = get_ulong( &args );
460 struct user_callback_frame *frame = NtCurrentTeb()->TlsSlots[WOW64_TLS_USERCALLBACKDATA];
462 if (!frame) return STATUS_NO_CALLBACK_ACTIVE;
464 *frame->ret_ptr = ret_ptr;
465 *frame->ret_len = ret_len;
466 frame->status = status;
467 longjmp( frame->jmpbuf, 1 );
468 return STATUS_SUCCESS;
472 /**********************************************************************
473 * wow64_NtClose
475 NTSTATUS WINAPI wow64_NtClose( UINT *args )
477 HANDLE handle = get_handle( &args );
479 return NtClose( handle );
483 /**********************************************************************
484 * wow64_NtContinue
486 NTSTATUS WINAPI wow64_NtContinue( UINT *args )
488 void *context = get_ptr( &args );
489 BOOLEAN alertable = get_ulong( &args );
491 NTSTATUS status = get_context_return_value( context );
492 struct user_apc_frame *frame = NtCurrentTeb()->TlsSlots[WOW64_TLS_APCLIST];
494 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL, context );
496 while (frame && frame->wow_context != context) frame = frame->prev_frame;
497 NtCurrentTeb()->TlsSlots[WOW64_TLS_APCLIST] = frame ? frame->prev_frame : NULL;
498 if (frame) NtContinue( frame->context, alertable );
500 if (alertable) NtTestAlert();
501 return status;
505 /**********************************************************************
506 * wow64_NtDeleteAtom
508 NTSTATUS WINAPI wow64_NtDeleteAtom( UINT *args )
510 RTL_ATOM atom = get_ulong( &args );
512 return NtDeleteAtom( atom );
516 /**********************************************************************
517 * wow64_NtFindAtom
519 NTSTATUS WINAPI wow64_NtFindAtom( UINT *args )
521 const WCHAR *name = get_ptr( &args );
522 ULONG len = get_ulong( &args );
523 RTL_ATOM *atom = get_ptr( &args );
525 return NtFindAtom( name, len, atom );
529 /**********************************************************************
530 * wow64_NtGetContextThread
532 NTSTATUS WINAPI wow64_NtGetContextThread( UINT *args )
534 HANDLE handle = get_handle( &args );
535 WOW64_CONTEXT *context = get_ptr( &args );
537 return RtlWow64GetThreadContext( handle, context );
541 /**********************************************************************
542 * wow64_NtGetCurrentProcessorNumber
544 NTSTATUS WINAPI wow64_NtGetCurrentProcessorNumber( UINT *args )
546 return NtGetCurrentProcessorNumber();
550 /**********************************************************************
551 * wow64_NtQueryDefaultLocale
553 NTSTATUS WINAPI wow64_NtQueryDefaultLocale( UINT *args )
555 BOOLEAN user = get_ulong( &args );
556 LCID *lcid = get_ptr( &args );
558 return NtQueryDefaultLocale( user, lcid );
562 /**********************************************************************
563 * wow64_NtQueryDefaultUILanguage
565 NTSTATUS WINAPI wow64_NtQueryDefaultUILanguage( UINT *args )
567 LANGID *lang = get_ptr( &args );
569 return NtQueryDefaultUILanguage( lang );
573 /**********************************************************************
574 * wow64_NtQueryInformationAtom
576 NTSTATUS WINAPI wow64_NtQueryInformationAtom( UINT *args )
578 RTL_ATOM atom = get_ulong( &args );
579 ATOM_INFORMATION_CLASS class = get_ulong( &args );
580 void *info = get_ptr( &args );
581 ULONG len = get_ulong( &args );
582 ULONG *retlen = get_ptr( &args );
584 if (class != AtomBasicInformation) FIXME( "class %u not supported\n", class );
585 return NtQueryInformationAtom( atom, class, info, len, retlen );
589 /**********************************************************************
590 * wow64_NtQueryInstallUILanguage
592 NTSTATUS WINAPI wow64_NtQueryInstallUILanguage( UINT *args )
594 LANGID *lang = get_ptr( &args );
596 return NtQueryInstallUILanguage( lang );
600 /**********************************************************************
601 * wow64_NtRaiseException
603 NTSTATUS WINAPI wow64_NtRaiseException( UINT *args )
605 EXCEPTION_RECORD32 *rec32 = get_ptr( &args );
606 void *context32 = get_ptr( &args );
607 BOOL first_chance = get_ulong( &args );
609 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL, context32 );
610 raise_exception( rec32, context32, first_chance, exception_record_32to64( rec32 ));
611 return STATUS_SUCCESS;
615 /**********************************************************************
616 * wow64_NtSetContextThread
618 NTSTATUS WINAPI wow64_NtSetContextThread( UINT *args )
620 HANDLE handle = get_handle( &args );
621 WOW64_CONTEXT *context = get_ptr( &args );
623 return RtlWow64SetThreadContext( handle, context );
627 /**********************************************************************
628 * wow64_NtSetDebugFilterState
630 NTSTATUS WINAPI wow64_NtSetDebugFilterState( UINT *args )
632 ULONG component_id = get_ulong( &args );
633 ULONG level = get_ulong( &args );
634 BOOLEAN state = get_ulong( &args );
636 return NtSetDebugFilterState( component_id, level, state );
640 /**********************************************************************
641 * wow64_NtSetDefaultLocale
643 NTSTATUS WINAPI wow64_NtSetDefaultLocale( UINT *args )
645 BOOLEAN user = get_ulong( &args );
646 LCID lcid = get_ulong( &args );
648 return NtSetDefaultLocale( user, lcid );
652 /**********************************************************************
653 * wow64_NtSetDefaultUILanguage
655 NTSTATUS WINAPI wow64_NtSetDefaultUILanguage( UINT *args )
657 LANGID lang = get_ulong( &args );
659 return NtSetDefaultUILanguage( lang );
663 /**********************************************************************
664 * wow64_NtWow64IsProcessorFeaturePresent
666 NTSTATUS WINAPI wow64_NtWow64IsProcessorFeaturePresent( UINT *args )
668 UINT feature = get_ulong( &args );
670 return pBTCpuIsProcessorFeaturePresent && pBTCpuIsProcessorFeaturePresent( feature );
674 /**********************************************************************
675 * init_image_mapping
677 void init_image_mapping( HMODULE module )
679 ULONG *ptr = RtlFindExportedRoutineByName( module, "Wow64Transition" );
681 if (ptr) *ptr = PtrToUlong( pBTCpuGetBopCode() );
685 /**********************************************************************
686 * load_64bit_module
688 static HMODULE load_64bit_module( const WCHAR *name )
690 NTSTATUS status;
691 HMODULE module;
692 UNICODE_STRING str;
693 WCHAR path[MAX_PATH];
694 const WCHAR *dir = get_machine_wow64_dir( IMAGE_FILE_MACHINE_TARGET_HOST );
696 swprintf( path, MAX_PATH, L"%s\\%s", dir, name );
697 RtlInitUnicodeString( &str, path );
698 if ((status = LdrLoadDll( dir, 0, &str, &module )))
700 ERR( "failed to load dll %lx\n", status );
701 NtTerminateProcess( GetCurrentProcess(), status );
703 return module;
707 /**********************************************************************
708 * get_cpu_dll_name
710 static const WCHAR *get_cpu_dll_name(void)
712 static ULONG buffer[32];
713 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
714 OBJECT_ATTRIBUTES attr;
715 UNICODE_STRING nameW;
716 const WCHAR *ret;
717 HANDLE key;
718 ULONG size;
720 switch (current_machine)
722 case IMAGE_FILE_MACHINE_I386:
723 RtlInitUnicodeString( &nameW, L"\\Registry\\Machine\\Software\\Microsoft\\Wow64\\x86" );
724 ret = (native_machine == IMAGE_FILE_MACHINE_ARM64 ? L"xtajit.dll" : L"wow64cpu.dll");
725 break;
726 case IMAGE_FILE_MACHINE_ARMNT:
727 RtlInitUnicodeString( &nameW, L"\\Registry\\Machine\\Software\\Microsoft\\Wow64\\arm" );
728 ret = L"wowarmhw.dll";
729 break;
730 default:
731 ERR( "unsupported machine %04x\n", current_machine );
732 RtlExitUserProcess( 1 );
734 InitializeObjectAttributes( &attr, &nameW, OBJ_CASE_INSENSITIVE, 0, NULL );
735 if (NtOpenKey( &key, KEY_READ | KEY_WOW64_64KEY, &attr )) return ret;
736 RtlInitUnicodeString( &nameW, L"" );
737 size = sizeof(buffer) - sizeof(WCHAR);
738 if (!NtQueryValueKey( key, &nameW, KeyValuePartialInformation, buffer, size, &size ) && info->Type == REG_SZ)
740 ((WCHAR *)info->Data)[info->DataLength / sizeof(WCHAR)] = 0;
741 ret = (WCHAR *)info->Data;
743 NtClose( key );
744 return ret;
748 /**********************************************************************
749 * create_cross_process_work_list
751 static NTSTATUS create_cross_process_work_list( WOW64INFO *wow64info )
753 SIZE_T map_size = 0x4000;
754 LARGE_INTEGER size;
755 NTSTATUS status;
756 HANDLE section;
757 CROSS_PROCESS_WORK_LIST *list = NULL;
758 CROSS_PROCESS_WORK_ENTRY *end;
759 UINT i;
761 size.QuadPart = map_size;
762 status = NtCreateSection( &section, SECTION_ALL_ACCESS, NULL, &size, PAGE_READWRITE, SEC_COMMIT, 0 );
763 if (status) return status;
764 status = NtMapViewOfSection( section, GetCurrentProcess(), (void **)&list, default_zero_bits, 0, NULL,
765 &map_size, ViewShare, MEM_TOP_DOWN, PAGE_READWRITE );
766 if (status)
768 NtClose( section );
769 return status;
772 end = (CROSS_PROCESS_WORK_ENTRY *)((char *)list + map_size);
773 for (i = 0; list->entries + i + 1 <= end; i++)
774 RtlWow64PushCrossProcessWorkOntoFreeList( &list->free_list, &list->entries[i] );
776 wow64info->SectionHandle = (ULONG_PTR)section;
777 wow64info->CrossProcessWorkList = (ULONG_PTR)list;
778 return STATUS_SUCCESS;
782 /**********************************************************************
783 * process_init
785 static DWORD WINAPI process_init( RTL_RUN_ONCE *once, void *param, void **context )
787 PEB32 *peb32;
788 HMODULE module;
789 UNICODE_STRING str = RTL_CONSTANT_STRING( L"ntdll.dll" );
790 SYSTEM_BASIC_INFORMATION info;
791 ULONG *p__wine_syscall_dispatcher, *p__wine_unix_call_dispatcher;
792 const SYSTEM_SERVICE_TABLE *psdwhwin32;
794 RtlWow64GetProcessMachines( GetCurrentProcess(), &current_machine, &native_machine );
795 if (!current_machine) current_machine = native_machine;
796 args_alignment = (current_machine == IMAGE_FILE_MACHINE_I386) ? sizeof(ULONG) : sizeof(ULONG64);
797 NtQuerySystemInformation( SystemEmulationBasicInformation, &info, sizeof(info), NULL );
798 highest_user_address = (ULONG_PTR)info.HighestUserAddress;
799 default_zero_bits = (ULONG_PTR)info.HighestUserAddress | 0x7fffffff;
800 NtQueryInformationProcess( GetCurrentProcess(), ProcessWow64Information, &peb32, sizeof(peb32), NULL );
801 wow64info = (WOW64INFO *)(peb32 + 1);
802 wow64info->NativeSystemPageSize = 0x1000;
803 wow64info->NativeMachineType = native_machine;
804 wow64info->EmulatedMachineType = current_machine;
805 NtCurrentTeb()->TlsSlots[WOW64_TLS_WOW64INFO] = wow64info;
807 #define GET_PTR(name) p ## name = RtlFindExportedRoutineByName( module, #name )
809 LdrGetDllHandle( NULL, 0, &str, &module );
810 GET_PTR( LdrSystemDllInitBlock );
812 module = load_64bit_module( get_cpu_dll_name() );
813 GET_PTR( BTCpuGetBopCode );
814 GET_PTR( BTCpuGetContext );
815 GET_PTR( BTCpuIsProcessorFeaturePresent );
816 GET_PTR( BTCpuProcessInit );
817 GET_PTR( BTCpuThreadInit );
818 GET_PTR( BTCpuResetToConsistentState );
819 GET_PTR( BTCpuSetContext );
820 GET_PTR( BTCpuSimulate );
821 GET_PTR( BTCpuNotifyFlushInstructionCache2 );
822 GET_PTR( BTCpuNotifyMapViewOfSection );
823 GET_PTR( BTCpuNotifyMemoryAlloc );
824 GET_PTR( BTCpuNotifyMemoryDirty );
825 GET_PTR( BTCpuNotifyMemoryFree );
826 GET_PTR( BTCpuNotifyMemoryProtect );
827 GET_PTR( BTCpuNotifyUnmapViewOfSection );
828 GET_PTR( BTCpuUpdateProcessorInformation );
829 GET_PTR( BTCpuThreadTerm );
830 GET_PTR( __wine_get_unix_opcode );
832 module = load_64bit_module( L"wow64win.dll" );
833 GET_PTR( sdwhwin32 );
834 syscall_tables[1] = *psdwhwin32;
836 pBTCpuProcessInit();
838 module = (HMODULE)(ULONG_PTR)pLdrSystemDllInitBlock->ntdll_handle;
839 init_image_mapping( module );
840 GET_PTR( KiRaiseUserExceptionDispatcher );
841 GET_PTR( __wine_syscall_dispatcher );
842 GET_PTR( __wine_unix_call_dispatcher );
844 *p__wine_syscall_dispatcher = PtrToUlong( pBTCpuGetBopCode() );
845 *p__wine_unix_call_dispatcher = PtrToUlong( p__wine_get_unix_opcode() );
847 if (wow64info->CpuFlags & WOW64_CPUFLAGS_SOFTWARE) create_cross_process_work_list( wow64info );
849 init_file_redirects();
850 return TRUE;
852 #undef GET_PTR
856 /**********************************************************************
857 * thread_init
859 static void thread_init(void)
861 TEB32 *teb32 = (TEB32 *)((char *)NtCurrentTeb() + NtCurrentTeb()->WowTebOffset);
862 void *cpu_area_ctx;
864 teb32->WOW32Reserved = PtrToUlong( pBTCpuGetBopCode() );
865 RtlWow64GetCurrentCpuArea( NULL, &cpu_area_ctx, NULL );
866 NtCurrentTeb()->TlsSlots[WOW64_TLS_WOW64INFO] = wow64info;
867 if (pBTCpuThreadInit) pBTCpuThreadInit();
869 /* update initial context to jump to 32-bit LdrInitializeThunk (cf. 32-bit call_init_thunk) */
870 switch (current_machine)
872 case IMAGE_FILE_MACHINE_I386:
874 I386_CONTEXT *ctx_ptr, *ctx = cpu_area_ctx;
875 ULONG *stack;
877 ctx_ptr = (I386_CONTEXT *)ULongToPtr( ctx->Esp ) - 1;
878 *ctx_ptr = *ctx;
880 stack = (ULONG *)ctx_ptr;
881 *(--stack) = 0;
882 *(--stack) = 0;
883 *(--stack) = 0;
884 *(--stack) = PtrToUlong( ctx_ptr );
885 *(--stack) = 0xdeadbabe;
886 ctx->Esp = PtrToUlong( stack );
887 ctx->Eip = pLdrSystemDllInitBlock->pLdrInitializeThunk;
888 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL, ctx );
890 break;
892 case IMAGE_FILE_MACHINE_ARMNT:
894 ARM_CONTEXT *ctx_ptr, *ctx = cpu_area_ctx;
896 ctx_ptr = (ARM_CONTEXT *)ULongToPtr( ctx->Sp & ~15 ) - 1;
897 *ctx_ptr = *ctx;
899 ctx->R0 = PtrToUlong( ctx_ptr );
900 ctx->Sp = PtrToUlong( ctx_ptr );
901 ctx->Pc = pLdrSystemDllInitBlock->pLdrInitializeThunk;
902 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL, ctx );
904 break;
906 default:
907 ERR( "not supported machine %x\n", current_machine );
908 NtTerminateProcess( GetCurrentProcess(), STATUS_INVALID_IMAGE_FORMAT );
913 /**********************************************************************
914 * free_temp_data
916 static void free_temp_data(void)
918 struct mem_header *next, *mem;
920 for (mem = NtCurrentTeb()->TlsSlots[WOW64_TLS_TEMPLIST]; mem; mem = next)
922 next = mem->next;
923 RtlFreeHeap( GetProcessHeap(), 0, mem );
925 NtCurrentTeb()->TlsSlots[WOW64_TLS_TEMPLIST] = NULL;
929 /**********************************************************************
930 * wow64_syscall
932 #ifdef __aarch64__
933 NTSTATUS wow64_syscall( UINT *args, ULONG_PTR thunk );
934 __ASM_GLOBAL_FUNC( wow64_syscall,
935 "stp x29, x30, [sp, #-16]!\n\t"
936 ".seh_save_fplr_x 16\n\t"
937 ".seh_endprologue\n\t"
938 ".seh_handler wow64_syscall_handler, @except\n"
939 "blr x1\n\t"
940 "b 1f\n"
941 "wow64_syscall_ret:\n\t"
942 "eor w1, w0, #0xc0000000\n\t"
943 "cmp w1, #8\n\t" /* STATUS_INVALID_HANDLE */
944 "b.ne 1f\n\t"
945 "bl call_raise_user_exception_dispatcher\n"
946 "1:\tldp x29, x30, [sp], #16\n\t"
947 "ret" )
948 __ASM_GLOBAL_FUNC( wow64_syscall_handler,
949 "stp x29, x30, [sp, #-16]!\n\t"
950 ".seh_save_fplr_x 16\n\t"
951 ".seh_endprologue\n\t"
952 "ldr w4, [x0, #4]\n\t" /* record->ExceptionFlags */
953 "tst w4, #6\n\t" /* EXCEPTION_UNWINDING | EXCEPTION_EXIT_UNWIND */
954 "b.ne 1f\n\t"
955 "mov x2, x0\n\t" /* record */
956 "mov x0, x1\n\t" /* frame */
957 "adr x1, wow64_syscall_ret\n\t" /* target */
958 "ldr w3, [x2]\n\t" /* retval = record->ExceptionCode */
959 "bl RtlUnwind\n\t"
960 "1:\tmov w0, #1\n\t" /* ExceptionContinueSearch */
961 "ldp x29, x30, [sp], #16\n\t"
962 "ret" )
963 #else
964 NTSTATUS wow64_syscall( UINT *args, ULONG_PTR thunk );
965 __ASM_GLOBAL_FUNC( wow64_syscall,
966 "subq $0x28, %rsp\n\t"
967 ".seh_stackalloc 0x28\n\t"
968 ".seh_endprologue\n\t"
969 ".seh_handler wow64_syscall_handler, @except\n\t"
970 "call *%rdx\n\t"
971 "jmp 1f\n"
972 "wow64_syscall_ret:\n\t"
973 "cmpl $0xc0000008,%eax\n\t" /* STATUS_INVALID_HANDLE */
974 "jne 1f\n\t"
975 "movl %eax,%ecx\n\t"
976 "call call_raise_user_exception_dispatcher\n"
977 "1:\taddq $0x28, %rsp\n\t"
978 "ret" )
979 __ASM_GLOBAL_FUNC( wow64_syscall_handler,
980 "subq $0x28,%rsp\n\t"
981 ".seh_stackalloc 0x28\n\t"
982 ".seh_endprologue\n\t"
983 "movl (%rcx),%r9d\n\t" /* retval = rec->ExceptionCode */
984 "movq %rcx,%r8\n\t" /* rec */
985 "movq %rdx,%rcx\n\t" /* frame */
986 "leaq wow64_syscall_ret(%rip),%rdx\n\t"
987 "call RtlUnwind\n\t"
988 "int3" )
989 #endif
992 /**********************************************************************
993 * Wow64SystemServiceEx (wow64.@)
995 NTSTATUS WINAPI Wow64SystemServiceEx( UINT num, UINT *args )
997 NTSTATUS status;
998 UINT id = num & 0xfff;
999 const SYSTEM_SERVICE_TABLE *table = &syscall_tables[(num >> 12) & 3];
1001 if (id >= table->ServiceLimit)
1003 ERR( "unsupported syscall %04x\n", num );
1004 return STATUS_INVALID_SYSTEM_SERVICE;
1006 status = wow64_syscall( args, table->ServiceTable[id] );
1007 free_temp_data();
1008 return status;
1012 /**********************************************************************
1013 * cpu_simulate
1015 #ifdef __aarch64__
1016 extern void DECLSPEC_NORETURN cpu_simulate(void);
1017 __ASM_GLOBAL_FUNC( cpu_simulate,
1018 "stp x29, x30, [sp, #-16]!\n\t"
1019 ".seh_save_fplr_x 16\n\t"
1020 ".seh_endprologue\n\t"
1021 ".seh_handler cpu_simulate_handler, @except\n"
1022 ".Lcpu_simulate_loop:\n\t"
1023 "adrp x16, pBTCpuSimulate\n\t"
1024 "ldr x16, [x16, :lo12:pBTCpuSimulate]\n\t"
1025 "blr x16\n\t"
1026 "b .Lcpu_simulate_loop" )
1027 __ASM_GLOBAL_FUNC( cpu_simulate_handler,
1028 "stp x29, x30, [sp, #-48]!\n\t"
1029 ".seh_save_fplr_x 48\n\t"
1030 "stp x19, x20, [sp, #16]\n\t"
1031 ".seh_save_regp x19, 16\n\t"
1032 ".seh_endprologue\n\t"
1033 "mov x19, x0\n\t" /* record */
1034 "mov x20, x1\n\t" /* frame */
1035 "ldr w4, [x0, #4]\n\t" /* record->ExceptionFlags */
1036 "tst w4, #6\n\t" /* EXCEPTION_UNWINDING | EXCEPTION_EXIT_UNWIND */
1037 "b.ne 1f\n\t"
1038 "stp x0, x2, [sp, #32]\n\t" /* record, context */
1039 "add x0, sp, #32\n\t"
1040 "bl Wow64PassExceptionToGuest\n\t"
1041 "mov x0, x20\n\t" /* frame */
1042 "adr x1, .Lcpu_simulate_loop\n\t" /* target */
1043 "mov x2, x19\n\t" /* record */
1044 "bl RtlUnwind\n\t"
1045 "1:\tmov w0, #1\n\t" /* ExceptionContinueSearch */
1046 "ldp x19, x20, [sp, #16]\n\t"
1047 "ldp x29, x30, [sp], #48\n\t"
1048 "ret" )
1049 #else
1050 extern void DECLSPEC_NORETURN cpu_simulate(void);
1051 __ASM_GLOBAL_FUNC( cpu_simulate,
1052 "subq $0x28, %rsp\n\t"
1053 ".seh_stackalloc 0x28\n\t"
1054 ".seh_endprologue\n\t"
1055 ".seh_handler cpu_simulate_handler, @except\n\t"
1056 ".Lcpu_simulate_loop:\n\t"
1057 "call *pBTCpuSimulate(%rip)\n\t"
1058 "jmp .Lcpu_simulate_loop" )
1059 __ASM_GLOBAL_FUNC( cpu_simulate_handler,
1060 "subq $0x38, %rsp\n\t"
1061 ".seh_stackalloc 0x38\n\t"
1062 ".seh_endprologue\n\t"
1063 "movq %rcx,%rsi\n\t" /* record */
1064 "movq %rcx,0x20(%rsp)\n\t"
1065 "movq %rdx,%rdi\n\t" /* frame */
1066 "movq %r8,0x28(%rsp)\n\t" /* context */
1067 "leaq 0x20(%rsp),%rcx\n\t"
1068 "call Wow64PassExceptionToGuest\n\t"
1069 "movq %rdi,%rcx\n\t" /* frame */
1070 "leaq .Lcpu_simulate_loop(%rip), %rdx\n\t" /* target */
1071 "movq %rsi,%r8\n\t" /* record */
1072 "call RtlUnwind\n\t"
1073 "int3" )
1074 #endif
1077 /**********************************************************************
1078 * Wow64AllocateTemp (wow64.@)
1080 * FIXME: probably not 100% compatible.
1082 void * WINAPI Wow64AllocateTemp( SIZE_T size )
1084 struct mem_header *mem;
1086 if (!(mem = RtlAllocateHeap( GetProcessHeap(), 0, offsetof( struct mem_header, data[size] ))))
1087 return NULL;
1088 mem->next = NtCurrentTeb()->TlsSlots[WOW64_TLS_TEMPLIST];
1089 NtCurrentTeb()->TlsSlots[WOW64_TLS_TEMPLIST] = mem;
1090 return mem->data;
1094 /**********************************************************************
1095 * Wow64ApcRoutine (wow64.@)
1097 void WINAPI Wow64ApcRoutine( ULONG_PTR arg1, ULONG_PTR arg2, ULONG_PTR arg3, CONTEXT *context )
1099 struct user_apc_frame frame;
1101 frame.prev_frame = NtCurrentTeb()->TlsSlots[WOW64_TLS_APCLIST];
1102 frame.context = context;
1103 NtCurrentTeb()->TlsSlots[WOW64_TLS_APCLIST] = &frame;
1105 /* cf. 32-bit call_user_apc_dispatcher */
1106 switch (current_machine)
1108 case IMAGE_FILE_MACHINE_I386:
1110 /* stack layout when calling 32-bit KiUserApcDispatcher */
1111 struct apc_stack_layout32
1113 ULONG func; /* 000 */
1114 UINT arg1; /* 004 */
1115 UINT arg2; /* 008 */
1116 UINT arg3; /* 00c */
1117 UINT alertable; /* 010 */
1118 I386_CONTEXT context; /* 014 */
1119 CONTEXT_EX32 xctx; /* 2e0 */
1120 UINT unk2[4]; /* 2f8 */
1121 } *stack;
1122 I386_CONTEXT ctx = { CONTEXT_I386_FULL };
1124 C_ASSERT( offsetof(struct apc_stack_layout32, context) == 0x14 );
1125 C_ASSERT( sizeof(struct apc_stack_layout32) == 0x308 );
1127 pBTCpuGetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx );
1129 stack = (struct apc_stack_layout32 *)ULongToPtr( ctx.Esp & ~3 ) - 1;
1130 stack->func = arg1 >> 32;
1131 stack->arg1 = arg1;
1132 stack->arg2 = arg2;
1133 stack->arg3 = arg3;
1134 stack->alertable = TRUE;
1135 stack->context = ctx;
1136 stack->xctx.Legacy.Offset = -(LONG)sizeof(stack->context);
1137 stack->xctx.Legacy.Length = sizeof(stack->context);
1138 stack->xctx.All.Offset = -(LONG)sizeof(stack->context);
1139 stack->xctx.All.Length = sizeof(stack->context) + sizeof(stack->xctx);
1140 stack->xctx.XState.Offset = 25;
1141 stack->xctx.XState.Length = 0;
1143 ctx.Esp = PtrToUlong( stack );
1144 ctx.Eip = pLdrSystemDllInitBlock->pKiUserApcDispatcher;
1145 frame.wow_context = &stack->context;
1146 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx );
1147 cpu_simulate();
1149 break;
1151 case IMAGE_FILE_MACHINE_ARMNT:
1153 struct apc_stack_layout
1155 ULONG func;
1156 ULONG align[3];
1157 ARM_CONTEXT context;
1158 } *stack;
1159 ARM_CONTEXT ctx = { CONTEXT_ARM_FULL };
1161 pBTCpuGetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx );
1162 stack = (struct apc_stack_layout *)ULongToPtr( ctx.Sp & ~15 ) - 1;
1163 stack->func = arg1 >> 32;
1164 stack->context = ctx;
1165 ctx.Sp = PtrToUlong( stack );
1166 ctx.Pc = pLdrSystemDllInitBlock->pKiUserApcDispatcher;
1167 ctx.R0 = PtrToUlong( &stack->context );
1168 ctx.R1 = arg1;
1169 ctx.R2 = arg2;
1170 ctx.R3 = arg3;
1171 frame.wow_context = &stack->context;
1172 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx );
1173 cpu_simulate();
1175 break;
1180 /**********************************************************************
1181 * Wow64KiUserCallbackDispatcher (wow64.@)
1183 NTSTATUS WINAPI Wow64KiUserCallbackDispatcher( ULONG id, void *args, ULONG len,
1184 void **ret_ptr, ULONG *ret_len )
1186 WOW64_CPURESERVED *cpu = NtCurrentTeb()->TlsSlots[WOW64_TLS_CPURESERVED];
1187 TEB32 *teb32 = (TEB32 *)((char *)NtCurrentTeb() + NtCurrentTeb()->WowTebOffset);
1188 ULONG teb_frame = teb32->Tib.ExceptionList;
1189 struct user_callback_frame frame;
1190 USHORT flags = cpu->Flags;
1192 frame.prev_frame = NtCurrentTeb()->TlsSlots[WOW64_TLS_USERCALLBACKDATA];
1193 frame.temp_list = NtCurrentTeb()->TlsSlots[WOW64_TLS_TEMPLIST];
1194 frame.ret_ptr = ret_ptr;
1195 frame.ret_len = ret_len;
1197 NtCurrentTeb()->TlsSlots[WOW64_TLS_USERCALLBACKDATA] = &frame;
1198 NtCurrentTeb()->TlsSlots[WOW64_TLS_TEMPLIST] = NULL;
1200 /* cf. 32-bit KeUserModeCallback */
1201 switch (current_machine)
1203 case IMAGE_FILE_MACHINE_I386:
1205 /* stack layout when calling 32-bit KiUserCallbackDispatcher */
1206 struct callback_stack_layout32
1208 ULONG eip; /* 000 */
1209 ULONG id; /* 004 */
1210 ULONG args; /* 008 */
1211 ULONG len; /* 00c */
1212 ULONG unk[2]; /* 010 */
1213 ULONG esp; /* 018 */
1214 BYTE args_data[0]; /* 01c */
1215 } *stack;
1216 I386_CONTEXT orig_ctx, ctx = { CONTEXT_I386_FULL };
1218 C_ASSERT( sizeof(struct callback_stack_layout32) == 0x1c );
1220 pBTCpuGetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx );
1221 orig_ctx = ctx;
1223 stack = ULongToPtr( (ctx.Esp - offsetof(struct callback_stack_layout32,args_data[len])) & ~15 );
1224 stack->eip = ctx.Eip;
1225 stack->id = id;
1226 stack->args = PtrToUlong( stack->args_data );
1227 stack->len = len;
1228 stack->esp = ctx.Esp;
1229 memcpy( stack->args_data, args, len );
1231 ctx.Esp = PtrToUlong( stack );
1232 ctx.Eip = pLdrSystemDllInitBlock->pKiUserCallbackDispatcher;
1233 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx );
1235 if (!setjmp( frame.jmpbuf ))
1236 cpu_simulate();
1237 else
1238 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &orig_ctx );
1240 break;
1242 case IMAGE_FILE_MACHINE_ARMNT:
1244 ARM_CONTEXT orig_ctx, ctx = { CONTEXT_ARM_FULL };
1245 void *args_data;
1247 pBTCpuGetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx );
1248 orig_ctx = ctx;
1250 args_data = ULongToPtr( (ctx.Sp - len) & ~15 );
1251 memcpy( args_data, args, len );
1253 ctx.R0 = id;
1254 ctx.R1 = PtrToUlong( args_data );
1255 ctx.R2 = len;
1256 ctx.Sp = PtrToUlong( args_data );
1257 ctx.Pc = pLdrSystemDllInitBlock->pKiUserCallbackDispatcher;
1258 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx );
1260 if (!setjmp( frame.jmpbuf ))
1261 cpu_simulate();
1262 else
1263 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &orig_ctx );
1265 break;
1268 teb32->Tib.ExceptionList = teb_frame;
1269 NtCurrentTeb()->TlsSlots[WOW64_TLS_USERCALLBACKDATA] = frame.prev_frame;
1270 NtCurrentTeb()->TlsSlots[WOW64_TLS_TEMPLIST] = frame.temp_list;
1271 cpu->Flags = flags;
1272 return frame.status;
1276 /**********************************************************************
1277 * Wow64LdrpInitialize (wow64.@)
1279 void WINAPI Wow64LdrpInitialize( CONTEXT *context )
1281 static RTL_RUN_ONCE init_done;
1283 RtlRunOnceExecuteOnce( &init_done, process_init, NULL, NULL );
1284 thread_init();
1285 cpu_simulate();
1289 /**********************************************************************
1290 * Wow64PrepareForException (wow64.@)
1292 #ifdef __x86_64__
1293 __ASM_GLOBAL_FUNC( Wow64PrepareForException,
1294 "sub $0x38,%rsp\n\t"
1295 "mov %rcx,%r10\n\t" /* rec */
1296 "movw %cs,%ax\n\t"
1297 "cmpw %ax,0x38(%rdx)\n\t" /* context->SegCs */
1298 "je 1f\n\t" /* already in 64-bit mode? */
1299 /* copy arguments to 64-bit stack */
1300 "mov %rsp,%rsi\n\t"
1301 "mov 0x98(%rdx),%rcx\n\t" /* context->Rsp */
1302 "sub %rsi,%rcx\n\t" /* stack size */
1303 "sub %rcx,%r14\n\t" /* reserve same size on 64-bit stack */
1304 "and $~0x0f,%r14\n\t"
1305 "mov %r14,%rdi\n\t"
1306 "shr $3,%rcx\n\t"
1307 "rep; movsq\n\t"
1308 /* update arguments to point to the new stack */
1309 "mov %r14,%rax\n\t"
1310 "sub %rsp,%rax\n\t"
1311 "add %rax,%r10\n\t" /* rec */
1312 "add %rax,%rdx\n\t" /* context */
1313 /* switch to 64-bit stack */
1314 "mov %r14,%rsp\n"
1315 /* build EXCEPTION_POINTERS structure and call BTCpuResetToConsistentState */
1316 "1:\tlea 0x20(%rsp),%rcx\n\t" /* pointers */
1317 "mov %r10,(%rcx)\n\t" /* rec */
1318 "mov %rdx,8(%rcx)\n\t" /* context */
1319 "mov " __ASM_NAME("pBTCpuResetToConsistentState") "(%rip),%rax\n\t"
1320 "call *%rax\n\t"
1321 "add $0x38,%rsp\n\t"
1322 "ret" )
1323 #else
1324 void WINAPI Wow64PrepareForException( EXCEPTION_RECORD *rec, CONTEXT *context )
1326 EXCEPTION_POINTERS ptrs = { rec, context };
1328 pBTCpuResetToConsistentState( &ptrs );
1330 #endif
1333 /**********************************************************************
1334 * Wow64PassExceptionToGuest (wow64.@)
1336 void WINAPI Wow64PassExceptionToGuest( EXCEPTION_POINTERS *ptrs )
1338 EXCEPTION_RECORD32 rec32;
1340 exception_record_64to32( &rec32, ptrs->ExceptionRecord );
1341 call_user_exception_dispatcher( &rec32, NULL, ptrs->ContextRecord );
1345 /**********************************************************************
1346 * Wow64ProcessPendingCrossProcessItems (wow64.@)
1348 void WINAPI Wow64ProcessPendingCrossProcessItems(void)
1350 CROSS_PROCESS_WORK_LIST *list = (void *)wow64info->CrossProcessWorkList;
1351 CROSS_PROCESS_WORK_ENTRY *entry;
1352 BOOLEAN flush = FALSE;
1353 UINT next;
1355 if (!list) return;
1356 entry = RtlWow64PopAllCrossProcessWorkFromWorkList( &list->work_list, &flush );
1358 if (flush)
1360 if (pBTCpuNotifyFlushInstructionCache2) pBTCpuNotifyFlushInstructionCache2( NULL, ~0ull );
1361 while (entry)
1363 next = entry->next;
1364 RtlWow64PushCrossProcessWorkOntoFreeList( &list->free_list, entry );
1365 entry = CROSS_PROCESS_LIST_ENTRY( &list->work_list, next );
1367 return;
1370 while (entry)
1372 switch (entry->id)
1374 case CrossProcessPreVirtualAlloc:
1375 /* FIXME */
1376 break;
1377 case CrossProcessPostVirtualAlloc:
1378 if (!pBTCpuNotifyMemoryAlloc) break;
1379 if (entry->args[2]) break;
1380 pBTCpuNotifyMemoryAlloc( (void *)entry->addr, entry->size, entry->args[0], entry->args[1] );
1381 break;
1382 case CrossProcessPreVirtualFree:
1383 if (!pBTCpuNotifyMemoryFree) break;
1384 pBTCpuNotifyMemoryFree( (void *)entry->addr, entry->size, entry->args[0] );
1385 break;
1386 case CrossProcessPostVirtualFree:
1387 /* FIXME */
1388 break;
1389 case CrossProcessPreVirtualProtect:
1390 if (!pBTCpuNotifyMemoryProtect) break;
1391 pBTCpuNotifyMemoryProtect( (void *)entry->addr, entry->size, entry->args[0] );
1392 break;
1393 case CrossProcessPostVirtualProtect:
1394 /* FIXME */
1395 break;
1396 case CrossProcessFlushCache:
1397 if (!pBTCpuNotifyFlushInstructionCache2) break;
1398 pBTCpuNotifyFlushInstructionCache2( (void *)entry->addr, entry->size );
1399 break;
1401 next = entry->next;
1402 RtlWow64PushCrossProcessWorkOntoFreeList( &list->free_list, entry );
1403 entry = CROSS_PROCESS_LIST_ENTRY( &list->work_list, next );
1408 /**********************************************************************
1409 * Wow64RaiseException (wow64.@)
1411 NTSTATUS WINAPI Wow64RaiseException( int code, EXCEPTION_RECORD *rec )
1413 EXCEPTION_RECORD32 rec32;
1414 BOOL first_chance = TRUE;
1415 union
1417 I386_CONTEXT i386;
1418 ARM_CONTEXT arm;
1419 } ctx32 = { 0 };
1421 switch (current_machine)
1423 case IMAGE_FILE_MACHINE_I386:
1425 EXCEPTION_RECORD int_rec = { 0 };
1427 ctx32.i386.ContextFlags = CONTEXT_I386_ALL;
1428 pBTCpuGetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx32.i386 );
1429 if (code == -1) break;
1430 int_rec.ExceptionAddress = (void *)(ULONG_PTR)ctx32.i386.Eip;
1431 switch (code)
1433 case 0x00: /* division by zero */
1434 int_rec.ExceptionCode = EXCEPTION_INT_DIVIDE_BY_ZERO;
1435 break;
1436 case 0x01: /* single-step */
1437 ctx32.i386.EFlags &= ~0x100;
1438 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx32.i386 );
1439 int_rec.ExceptionCode = EXCEPTION_SINGLE_STEP;
1440 break;
1441 case 0x03: /* breakpoint */
1442 int_rec.ExceptionCode = EXCEPTION_BREAKPOINT;
1443 int_rec.ExceptionAddress = (void *)(ULONG_PTR)(ctx32.i386.Eip - 1);
1444 int_rec.NumberParameters = 1;
1445 break;
1446 case 0x04: /* overflow */
1447 int_rec.ExceptionCode = EXCEPTION_INT_OVERFLOW;
1448 break;
1449 case 0x05: /* array bounds */
1450 int_rec.ExceptionCode = EXCEPTION_ARRAY_BOUNDS_EXCEEDED;
1451 break;
1452 case 0x06: /* invalid opcode */
1453 int_rec.ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION;
1454 break;
1455 case 0x09: /* coprocessor segment overrun */
1456 int_rec.ExceptionCode = EXCEPTION_FLT_INVALID_OPERATION;
1457 break;
1458 case 0x0c: /* stack fault */
1459 int_rec.ExceptionCode = EXCEPTION_STACK_OVERFLOW;
1460 break;
1461 case 0x0d: /* general protection fault */
1462 int_rec.ExceptionCode = EXCEPTION_PRIV_INSTRUCTION;
1463 break;
1464 case 0x29: /* __fastfail */
1465 int_rec.ExceptionCode = STATUS_STACK_BUFFER_OVERRUN;
1466 int_rec.ExceptionFlags = EXCEPTION_NONCONTINUABLE;
1467 int_rec.NumberParameters = 1;
1468 int_rec.ExceptionInformation[0] = ctx32.i386.Ecx;
1469 first_chance = FALSE;
1470 break;
1471 case 0x2d: /* debug service */
1472 ctx32.i386.Eip += 3;
1473 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx32.i386 );
1474 int_rec.ExceptionCode = EXCEPTION_BREAKPOINT;
1475 int_rec.ExceptionAddress = (void *)(ULONG_PTR)ctx32.i386.Eip;
1476 int_rec.NumberParameters = 1;
1477 int_rec.ExceptionInformation[0] = ctx32.i386.Eax;
1478 break;
1479 default:
1480 int_rec.ExceptionCode = EXCEPTION_ACCESS_VIOLATION;
1481 int_rec.ExceptionAddress = (void *)(ULONG_PTR)ctx32.i386.Eip;
1482 int_rec.NumberParameters = 2;
1483 int_rec.ExceptionInformation[1] = 0xffffffff;
1484 break;
1486 *rec = int_rec;
1487 break;
1490 case IMAGE_FILE_MACHINE_ARMNT:
1491 ctx32.arm.ContextFlags = CONTEXT_ARM_ALL;
1492 pBTCpuGetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx32.arm );
1493 break;
1496 exception_record_64to32( &rec32, rec );
1497 raise_exception( &rec32, &ctx32, first_chance, rec );
1499 return STATUS_SUCCESS;