cmd: DIR command outputs free space for the path.
[wine.git] / dlls / wow64 / syscall.c
blob6b1da0913a9b7647eb23abe3d31841607b5908ed
1 /*
2 * WoW64 syscall wrapping
4 * Copyright 2021 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <stdarg.h>
23 #include "ntstatus.h"
24 #define WIN32_NO_STATUS
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winnt.h"
28 #include "winternl.h"
29 #include "wine/exception.h"
30 #include "wine/unixlib.h"
31 #include "wine/asm.h"
32 #include "wow64_private.h"
33 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(wow);
37 USHORT native_machine = 0;
38 USHORT current_machine = 0;
39 ULONG_PTR args_alignment = 0;
40 ULONG_PTR highest_user_address = 0x7ffeffff;
41 ULONG_PTR default_zero_bits = 0x7fffffff;
43 typedef NTSTATUS (WINAPI *syscall_thunk)( UINT *args );
45 static const syscall_thunk syscall_thunks[] =
47 #define SYSCALL_ENTRY(func) wow64_ ## func,
48 ALL_SYSCALLS
49 #undef SYSCALL_ENTRY
52 static const char *syscall_names[] =
54 #define SYSCALL_ENTRY(func) #func,
55 ALL_SYSCALLS
56 #undef SYSCALL_ENTRY
59 static const SYSTEM_SERVICE_TABLE ntdll_syscall_table =
61 (ULONG_PTR *)syscall_thunks,
62 (ULONG_PTR *)syscall_names,
63 ARRAY_SIZE(syscall_thunks)
66 static SYSTEM_SERVICE_TABLE syscall_tables[4];
68 /* header for Wow64AllocTemp blocks; probably not the right layout */
69 struct mem_header
71 struct mem_header *next;
72 void *__pad;
73 BYTE data[1];
76 /* stack frame for user callbacks */
77 struct user_callback_frame
79 struct user_callback_frame *prev_frame;
80 struct mem_header *temp_list;
81 void **ret_ptr;
82 ULONG *ret_len;
83 NTSTATUS status;
84 __wine_jmp_buf jmpbuf;
87 /* stack frame for user APCs */
88 struct user_apc_frame
90 struct user_apc_frame *prev_frame;
91 CONTEXT *context;
92 void *wow_context;
95 SYSTEM_DLL_INIT_BLOCK *pLdrSystemDllInitBlock = NULL;
97 /* wow64win syscall table */
98 static const SYSTEM_SERVICE_TABLE *psdwhwin32;
99 static HMODULE win32u_module;
100 static WOW64INFO *wow64info;
102 /* cpu backend dll functions */
103 /* the function prototypes most likely differ from Windows */
104 static void * (WINAPI *pBTCpuGetBopCode)(void);
105 static NTSTATUS (WINAPI *pBTCpuGetContext)(HANDLE,HANDLE,void *,void *);
106 static BOOLEAN (WINAPI *pBTCpuIsProcessorFeaturePresent)(UINT);
107 static void (WINAPI *pBTCpuProcessInit)(void);
108 static NTSTATUS (WINAPI *pBTCpuSetContext)(HANDLE,HANDLE,void *,void *);
109 static void (WINAPI *pBTCpuThreadInit)(void);
110 static void (WINAPI *pBTCpuSimulate)(void);
111 static NTSTATUS (WINAPI *pBTCpuResetToConsistentState)( EXCEPTION_POINTERS * );
112 static void * (WINAPI *p__wine_get_unix_opcode)(void);
113 static void * (WINAPI *pKiRaiseUserExceptionDispatcher)(void);
114 void (WINAPI *pBTCpuNotifyFlushInstructionCache2)( const void *, SIZE_T ) = NULL;
115 void (WINAPI *pBTCpuNotifyMapViewOfSection)( void * ) = NULL;
116 void (WINAPI *pBTCpuNotifyMemoryAlloc)( void *, SIZE_T, ULONG, ULONG ) = NULL;
117 void (WINAPI *pBTCpuNotifyMemoryDirty)( void *, SIZE_T ) = NULL;
118 void (WINAPI *pBTCpuNotifyMemoryFree)( void *, SIZE_T ) = NULL;
119 void (WINAPI *pBTCpuNotifyMemoryProtect)( void *, SIZE_T, ULONG ) = NULL;
120 void (WINAPI *pBTCpuNotifyUnmapViewOfSection)( void * ) = NULL;
121 void (WINAPI *pBTCpuUpdateProcessorInformation)( SYSTEM_CPU_INFORMATION * ) = NULL;
122 void (WINAPI *pBTCpuThreadTerm)( HANDLE ) = NULL;
124 void *dummy = RtlUnwind;
126 BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, void *reserved )
128 if (reason == DLL_PROCESS_ATTACH) LdrDisableThreadCalloutsForDll( inst );
129 return TRUE;
132 void __cdecl __wine_spec_unimplemented_stub( const char *module, const char *function )
134 EXCEPTION_RECORD record;
136 record.ExceptionCode = EXCEPTION_WINE_STUB;
137 record.ExceptionFlags = EH_NONCONTINUABLE;
138 record.ExceptionRecord = NULL;
139 record.ExceptionAddress = __wine_spec_unimplemented_stub;
140 record.NumberParameters = 2;
141 record.ExceptionInformation[0] = (ULONG_PTR)module;
142 record.ExceptionInformation[1] = (ULONG_PTR)function;
143 for (;;) RtlRaiseException( &record );
147 static EXCEPTION_RECORD *exception_record_32to64( const EXCEPTION_RECORD32 *rec32 )
149 EXCEPTION_RECORD *rec;
150 unsigned int i;
152 rec = Wow64AllocateTemp( sizeof(*rec) );
153 rec->ExceptionCode = rec32->ExceptionCode;
154 rec->ExceptionFlags = rec32->ExceptionFlags;
155 rec->ExceptionRecord = rec32->ExceptionRecord ? exception_record_32to64( ULongToPtr(rec32->ExceptionRecord) ) : NULL;
156 rec->ExceptionAddress = ULongToPtr( rec32->ExceptionAddress );
157 rec->NumberParameters = rec32->NumberParameters;
158 for (i = 0; i < EXCEPTION_MAXIMUM_PARAMETERS; i++)
159 rec->ExceptionInformation[i] = rec32->ExceptionInformation[i];
160 return rec;
164 static void exception_record_64to32( EXCEPTION_RECORD32 *rec32, const EXCEPTION_RECORD *rec )
166 unsigned int i;
168 rec32->ExceptionCode = rec->ExceptionCode;
169 rec32->ExceptionFlags = rec->ExceptionFlags;
170 rec32->ExceptionRecord = PtrToUlong( rec->ExceptionRecord );
171 rec32->ExceptionAddress = PtrToUlong( rec->ExceptionAddress );
172 rec32->NumberParameters = rec->NumberParameters;
173 for (i = 0; i < rec->NumberParameters; i++)
174 rec32->ExceptionInformation[i] = rec->ExceptionInformation[i];
178 static NTSTATUS get_context_return_value( void *wow_context )
180 switch (current_machine)
182 case IMAGE_FILE_MACHINE_I386:
183 return ((I386_CONTEXT *)wow_context)->Eax;
184 case IMAGE_FILE_MACHINE_ARMNT:
185 return ((ARM_CONTEXT *)wow_context)->R0;
187 return 0;
191 /**********************************************************************
192 * call_user_exception_dispatcher
194 static void call_user_exception_dispatcher( EXCEPTION_RECORD32 *rec, void *ctx32_ptr, void *ctx64_ptr )
196 switch (current_machine)
198 case IMAGE_FILE_MACHINE_I386:
200 struct stack_layout
202 ULONG rec_ptr; /* first arg for KiUserExceptionDispatcher */
203 ULONG context_ptr; /* second arg for KiUserExceptionDispatcher */
204 EXCEPTION_RECORD32 rec;
205 I386_CONTEXT context;
206 } *stack;
207 I386_CONTEXT *context, ctx = { CONTEXT_I386_ALL };
208 CONTEXT_EX *context_ex, *src_ex = NULL;
209 ULONG size, flags;
211 pBTCpuGetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx );
213 if (ctx32_ptr)
215 I386_CONTEXT *ctx32 = ctx32_ptr;
217 if ((ctx32->ContextFlags & CONTEXT_I386_XSTATE) == CONTEXT_I386_XSTATE)
218 src_ex = (CONTEXT_EX *)(ctx32 + 1);
220 else if (native_machine == IMAGE_FILE_MACHINE_AMD64)
222 AMD64_CONTEXT *ctx64 = ctx64_ptr;
224 if ((ctx64->ContextFlags & CONTEXT_AMD64_FLOATING_POINT) == CONTEXT_AMD64_FLOATING_POINT)
225 memcpy( ctx.ExtendedRegisters, &ctx64->FltSave, sizeof(ctx.ExtendedRegisters) );
226 if ((ctx64->ContextFlags & CONTEXT_AMD64_XSTATE) == CONTEXT_AMD64_XSTATE)
227 src_ex = (CONTEXT_EX *)(ctx64 + 1);
230 flags = ctx.ContextFlags;
231 if (src_ex) flags |= CONTEXT_I386_XSTATE;
232 RtlGetExtendedContextLength( flags, &size );
233 size = ((size + 15) & ~15) + offsetof(struct stack_layout,context);
235 stack = (struct stack_layout *)(ULONG_PTR)(ctx.Esp - size);
236 stack->rec_ptr = PtrToUlong( &stack->rec );
237 stack->rec = *rec;
238 RtlInitializeExtendedContext( &stack->context, flags, &context_ex );
239 context = RtlLocateLegacyContext( context_ex, NULL );
240 *context = ctx;
241 context->ContextFlags = flags;
242 /* adjust Eip for breakpoints in software emulation (hardware exceptions already adjust Rip) */
243 if (rec->ExceptionCode == EXCEPTION_BREAKPOINT && (wow64info->CpuFlags & WOW64_CPUFLAGS_SOFTWARE))
244 context->Eip--;
245 stack->context_ptr = PtrToUlong( context );
247 if (src_ex)
249 XSTATE *src_xs = (XSTATE *)((char *)src_ex + src_ex->XState.Offset);
250 XSTATE *dst_xs = (XSTATE *)((char *)context_ex + context_ex->XState.Offset);
252 dst_xs->Mask = src_xs->Mask & ~(ULONG64)3;
253 dst_xs->CompactionMask = src_xs->CompactionMask;
254 if ((dst_xs->Mask & 4) &&
255 src_ex->XState.Length >= sizeof(XSTATE) &&
256 context_ex->XState.Length >= sizeof(XSTATE))
257 memcpy( &dst_xs->YmmContext, &src_xs->YmmContext, sizeof(dst_xs->YmmContext) );
260 ctx.Esp = PtrToUlong( stack );
261 ctx.Eip = pLdrSystemDllInitBlock->pKiUserExceptionDispatcher;
262 ctx.EFlags &= ~(0x100|0x400|0x40000);
263 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx );
265 TRACE( "exception %08lx dispatcher %08lx stack %08lx eip %08lx\n",
266 rec->ExceptionCode, ctx.Eip, ctx.Esp, stack->context.Eip );
268 break;
270 case IMAGE_FILE_MACHINE_ARMNT:
272 struct stack_layout
274 ARM_CONTEXT context;
275 EXCEPTION_RECORD32 rec;
276 } *stack;
277 ARM_CONTEXT ctx = { CONTEXT_ARM_ALL };
279 pBTCpuGetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx );
280 stack = (struct stack_layout *)(ULONG_PTR)(ctx.Sp & ~3) - 1;
281 stack->rec = *rec;
282 stack->context = ctx;
284 ctx.R0 = PtrToUlong( &stack->rec ); /* first arg for KiUserExceptionDispatcher */
285 ctx.R1 = PtrToUlong( &stack->context ); /* second arg for KiUserExceptionDispatcher */
286 ctx.Sp = PtrToUlong( stack );
287 ctx.Pc = pLdrSystemDllInitBlock->pKiUserExceptionDispatcher;
288 if (ctx.Pc & 1) ctx.Cpsr |= 0x20;
289 else ctx.Cpsr &= ~0x20;
290 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx );
292 TRACE( "exception %08lx dispatcher %08lx stack %08lx pc %08lx\n",
293 rec->ExceptionCode, ctx.Pc, ctx.Sp, stack->context.Sp );
295 break;
300 /**********************************************************************
301 * call_raise_user_exception_dispatcher
303 static void call_raise_user_exception_dispatcher( ULONG code )
305 TEB32 *teb32 = (TEB32 *)((char *)NtCurrentTeb() + NtCurrentTeb()->WowTebOffset);
307 teb32->ExceptionCode = code;
309 switch (current_machine)
311 case IMAGE_FILE_MACHINE_I386:
313 I386_CONTEXT ctx = { CONTEXT_I386_ALL };
315 pBTCpuGetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx );
316 ctx.Esp -= sizeof(ULONG);
317 *(ULONG *)ULongToPtr( ctx.Esp ) = ctx.Eip;
318 ctx.Eip = (ULONG_PTR)pKiRaiseUserExceptionDispatcher;
319 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx );
321 break;
323 case IMAGE_FILE_MACHINE_ARMNT:
325 ARM_CONTEXT ctx = { CONTEXT_ARM_ALL };
327 pBTCpuGetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx );
328 ctx.Pc = (ULONG_PTR)pKiRaiseUserExceptionDispatcher;
329 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx );
331 break;
336 /* based on RtlRaiseException: call NtRaiseException with context setup to return to caller */
337 void WINAPI raise_exception( EXCEPTION_RECORD *rec, CONTEXT *context, BOOL first_chance ) DECLSPEC_HIDDEN;
338 #ifdef __x86_64__
339 __ASM_GLOBAL_FUNC( raise_exception,
340 "sub $0x28,%rsp\n\t"
341 __ASM_SEH(".seh_stackalloc 0x28\n\t")
342 __ASM_SEH(".seh_endprologue\n\t")
343 __ASM_CFI(".cfi_adjust_cfa_offset 0x28\n\t")
344 "movq %rcx,(%rsp)\n\t"
345 "movq %rdx,%rcx\n\t"
346 "call " __ASM_NAME("RtlCaptureContext") "\n\t"
347 "leaq 0x30(%rsp),%rax\n\t" /* orig stack pointer */
348 "movq %rax,0x98(%rdx)\n\t" /* context->Rsp */
349 "movq (%rsp),%rcx\n\t" /* original first parameter */
350 "movq 0x28(%rsp),%rax\n\t" /* return address */
351 "movq %rax,0xf8(%rdx)\n\t" /* context->Rip */
352 "call " __ASM_NAME("NtRaiseException") )
353 #elif defined(__aarch64__)
354 __ASM_GLOBAL_FUNC( raise_exception,
355 "stp x29, x30, [sp, #-32]!\n\t"
356 __ASM_SEH(".seh_save_fplr_x 32\n\t")
357 __ASM_SEH(".seh_endprologue\n\t")
358 __ASM_CFI(".cfi_def_cfa x29, 32\n\t")
359 __ASM_CFI(".cfi_offset x30, -24\n\t")
360 __ASM_CFI(".cfi_offset x29, -32\n\t")
361 "mov x29, sp\n\t"
362 "stp x0, x1, [sp, #16]\n\t"
363 "mov x0, x1\n\t"
364 "bl " __ASM_NAME("RtlCaptureContext") "\n\t"
365 "ldp x0, x1, [sp, #16]\n\t" /* orig parameters */
366 "ldp x4, x5, [sp]\n\t" /* frame pointer, return address */
367 "stp x4, x5, [x1, #0xf0]\n\t" /* context->Fp, Lr */
368 "add x4, sp, #32\n\t" /* orig stack pointer */
369 "stp x4, x5, [x1, #0x100]\n\t" /* context->Sp, Pc */
370 "bl " __ASM_NAME("NtRaiseException") )
371 #endif
374 /**********************************************************************
375 * wow64_NtAddAtom
377 NTSTATUS WINAPI wow64_NtAddAtom( UINT *args )
379 const WCHAR *name = get_ptr( &args );
380 ULONG len = get_ulong( &args );
381 RTL_ATOM *atom = get_ptr( &args );
383 return NtAddAtom( name, len, atom );
387 /**********************************************************************
388 * wow64_NtAllocateLocallyUniqueId
390 NTSTATUS WINAPI wow64_NtAllocateLocallyUniqueId( UINT *args )
392 LUID *luid = get_ptr( &args );
394 return NtAllocateLocallyUniqueId( luid );
398 /**********************************************************************
399 * wow64_NtAllocateUuids
401 NTSTATUS WINAPI wow64_NtAllocateUuids( UINT *args )
403 ULARGE_INTEGER *time = get_ptr( &args );
404 ULONG *delta = get_ptr( &args );
405 ULONG *sequence = get_ptr( &args );
406 UCHAR *seed = get_ptr( &args );
408 return NtAllocateUuids( time, delta, sequence, seed );
412 /***********************************************************************
413 * wow64_NtCallbackReturn
415 NTSTATUS WINAPI wow64_NtCallbackReturn( UINT *args )
417 void *ret_ptr = get_ptr( &args );
418 ULONG ret_len = get_ulong( &args );
419 NTSTATUS status = get_ulong( &args );
421 struct user_callback_frame *frame = NtCurrentTeb()->TlsSlots[WOW64_TLS_USERCALLBACKDATA];
423 if (!frame) return STATUS_NO_CALLBACK_ACTIVE;
425 *frame->ret_ptr = ret_ptr;
426 *frame->ret_len = ret_len;
427 frame->status = status;
428 __wine_longjmp( &frame->jmpbuf, 1 );
432 /**********************************************************************
433 * wow64_NtClose
435 NTSTATUS WINAPI wow64_NtClose( UINT *args )
437 HANDLE handle = get_handle( &args );
439 return NtClose( handle );
443 /**********************************************************************
444 * wow64_NtContinue
446 NTSTATUS WINAPI wow64_NtContinue( UINT *args )
448 void *context = get_ptr( &args );
449 BOOLEAN alertable = get_ulong( &args );
451 NTSTATUS status = get_context_return_value( context );
452 struct user_apc_frame *frame = NtCurrentTeb()->TlsSlots[WOW64_TLS_APCLIST];
454 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL, context );
456 while (frame && frame->wow_context != context) frame = frame->prev_frame;
457 NtCurrentTeb()->TlsSlots[WOW64_TLS_APCLIST] = frame ? frame->prev_frame : NULL;
458 if (frame) NtContinue( frame->context, alertable );
460 if (alertable) NtTestAlert();
461 return status;
465 /**********************************************************************
466 * wow64_NtDeleteAtom
468 NTSTATUS WINAPI wow64_NtDeleteAtom( UINT *args )
470 RTL_ATOM atom = get_ulong( &args );
472 return NtDeleteAtom( atom );
476 /**********************************************************************
477 * wow64_NtFindAtom
479 NTSTATUS WINAPI wow64_NtFindAtom( UINT *args )
481 const WCHAR *name = get_ptr( &args );
482 ULONG len = get_ulong( &args );
483 RTL_ATOM *atom = get_ptr( &args );
485 return NtFindAtom( name, len, atom );
489 /**********************************************************************
490 * wow64_NtGetContextThread
492 NTSTATUS WINAPI wow64_NtGetContextThread( UINT *args )
494 HANDLE handle = get_handle( &args );
495 WOW64_CONTEXT *context = get_ptr( &args );
497 return RtlWow64GetThreadContext( handle, context );
501 /**********************************************************************
502 * wow64_NtGetCurrentProcessorNumber
504 NTSTATUS WINAPI wow64_NtGetCurrentProcessorNumber( UINT *args )
506 return NtGetCurrentProcessorNumber();
510 /**********************************************************************
511 * wow64_NtQueryDefaultLocale
513 NTSTATUS WINAPI wow64_NtQueryDefaultLocale( UINT *args )
515 BOOLEAN user = get_ulong( &args );
516 LCID *lcid = get_ptr( &args );
518 return NtQueryDefaultLocale( user, lcid );
522 /**********************************************************************
523 * wow64_NtQueryDefaultUILanguage
525 NTSTATUS WINAPI wow64_NtQueryDefaultUILanguage( UINT *args )
527 LANGID *lang = get_ptr( &args );
529 return NtQueryDefaultUILanguage( lang );
533 /**********************************************************************
534 * wow64_NtQueryInformationAtom
536 NTSTATUS WINAPI wow64_NtQueryInformationAtom( UINT *args )
538 RTL_ATOM atom = get_ulong( &args );
539 ATOM_INFORMATION_CLASS class = get_ulong( &args );
540 void *info = get_ptr( &args );
541 ULONG len = get_ulong( &args );
542 ULONG *retlen = get_ptr( &args );
544 if (class != AtomBasicInformation) FIXME( "class %u not supported\n", class );
545 return NtQueryInformationAtom( atom, class, info, len, retlen );
549 /**********************************************************************
550 * wow64_NtQueryInstallUILanguage
552 NTSTATUS WINAPI wow64_NtQueryInstallUILanguage( UINT *args )
554 LANGID *lang = get_ptr( &args );
556 return NtQueryInstallUILanguage( lang );
560 /**********************************************************************
561 * wow64_NtRaiseException
563 NTSTATUS WINAPI wow64_NtRaiseException( UINT *args )
565 EXCEPTION_RECORD32 *rec32 = get_ptr( &args );
566 void *context32 = get_ptr( &args );
567 BOOL first_chance = get_ulong( &args );
569 EXCEPTION_RECORD *rec = exception_record_32to64( rec32 );
570 CONTEXT context;
572 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL, context32 );
574 __TRY
576 raise_exception( rec, &context, first_chance );
578 __EXCEPT_ALL
580 call_user_exception_dispatcher( rec32, context32, &context );
582 __ENDTRY
583 return STATUS_SUCCESS;
587 /**********************************************************************
588 * wow64_NtSetContextThread
590 NTSTATUS WINAPI wow64_NtSetContextThread( UINT *args )
592 HANDLE handle = get_handle( &args );
593 WOW64_CONTEXT *context = get_ptr( &args );
595 return RtlWow64SetThreadContext( handle, context );
599 /**********************************************************************
600 * wow64_NtSetDebugFilterState
602 NTSTATUS WINAPI wow64_NtSetDebugFilterState( UINT *args )
604 ULONG component_id = get_ulong( &args );
605 ULONG level = get_ulong( &args );
606 BOOLEAN state = get_ulong( &args );
608 return NtSetDebugFilterState( component_id, level, state );
612 /**********************************************************************
613 * wow64_NtSetDefaultLocale
615 NTSTATUS WINAPI wow64_NtSetDefaultLocale( UINT *args )
617 BOOLEAN user = get_ulong( &args );
618 LCID lcid = get_ulong( &args );
620 return NtSetDefaultLocale( user, lcid );
624 /**********************************************************************
625 * wow64_NtSetDefaultUILanguage
627 NTSTATUS WINAPI wow64_NtSetDefaultUILanguage( UINT *args )
629 LANGID lang = get_ulong( &args );
631 return NtSetDefaultUILanguage( lang );
635 /**********************************************************************
636 * wow64_NtWow64IsProcessorFeaturePresent
638 NTSTATUS WINAPI wow64_NtWow64IsProcessorFeaturePresent( UINT *args )
640 UINT feature = get_ulong( &args );
642 return pBTCpuIsProcessorFeaturePresent && pBTCpuIsProcessorFeaturePresent( feature );
646 /**********************************************************************
647 * get_syscall_num
649 static DWORD get_syscall_num( const BYTE *syscall )
651 WORD *arm_syscall = (WORD *)((ULONG_PTR)syscall & ~1);
652 DWORD id = ~0u;
654 if (!syscall) return id;
655 switch (current_machine)
657 case IMAGE_FILE_MACHINE_I386:
658 if (syscall[0] == 0xb8 && syscall[5] == 0xba && syscall[10] == 0xff && syscall[11] == 0xd2)
659 id = *(DWORD *)(syscall + 1);
660 break;
662 case IMAGE_FILE_MACHINE_ARMNT:
663 if (*arm_syscall == 0xb40f)
665 DWORD inst = *(DWORD *)(arm_syscall + 1);
666 id = ((inst << 1) & 0x0800) + ((inst << 12) & 0xf000) +
667 ((inst >> 20) & 0x0700) + ((inst >> 16) & 0x00ff);
669 break;
671 return id;
675 /**********************************************************************
676 * get_rva
678 static void *get_rva( const IMAGE_NT_HEADERS *nt, HMODULE module, DWORD rva,
679 IMAGE_SECTION_HEADER **section, BOOL image )
681 if (image) return (void *)((char *)module + rva);
682 return RtlImageRvaToVa( nt, module, rva, section );
686 /**********************************************************************
687 * init_syscall_table
689 static void init_syscall_table( HMODULE module, ULONG idx, const SYSTEM_SERVICE_TABLE *orig_table, BOOL image )
691 static syscall_thunk thunks[2048];
692 static ULONG start_pos;
694 const IMAGE_NT_HEADERS *nt = RtlImageNtHeader( module );
695 IMAGE_SECTION_HEADER *section = NULL;
696 const IMAGE_EXPORT_DIRECTORY *exports;
697 const ULONG *functions, *names;
698 const USHORT *ordinals;
699 ULONG id, exp_size, exp_pos, wrap_pos, max_pos = 0;
700 const char **syscall_names = (const char **)orig_table->CounterTable;
702 exports = RtlImageDirectoryEntryToData( module, image, IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size );
703 ordinals = get_rva( nt, module, exports->AddressOfNameOrdinals, &section, image );
704 functions = get_rva( nt, module, exports->AddressOfFunctions, &section, image );
705 names = get_rva( nt, module, exports->AddressOfNames, &section, image );
707 for (exp_pos = wrap_pos = 0; exp_pos < exports->NumberOfNames; exp_pos++)
709 char *name = get_rva( nt, module, names[exp_pos], &section, image );
710 int res = -1;
712 if (strncmp( name, "Nt", 2 ) && strncmp( name, "wine", 4 ) && strncmp( name, "__wine", 6 ))
713 continue; /* not a syscall */
715 id = get_syscall_num( get_rva( nt, module, functions[ordinals[exp_pos]], &section, image ));
716 if (id == ~0u) continue; /* not a syscall */
718 if (wrap_pos < orig_table->ServiceLimit) res = strcmp( name, syscall_names[wrap_pos] );
720 if (!res) /* got a match */
722 ULONG table_idx = (id >> 12) & 3, table_pos = id & 0xfff;
723 if (table_idx == idx)
725 if (start_pos + table_pos < ARRAY_SIZE(thunks))
727 thunks[start_pos + table_pos] = (syscall_thunk)orig_table->ServiceTable[wrap_pos++];
728 max_pos = max( table_pos, max_pos );
730 else ERR( "invalid syscall id %04lx for %s\n", id, name );
732 else ERR( "wrong syscall table id %04lx for %s\n", id, name );
734 else if (res > 0)
736 FIXME( "no export for syscall %s\n", syscall_names[wrap_pos] );
737 wrap_pos++;
738 exp_pos--; /* try again */
740 else FIXME( "missing wrapper for syscall %04lx %s\n", id, name );
743 for ( ; wrap_pos < orig_table->ServiceLimit; wrap_pos++)
744 FIXME( "no export for syscall %s\n", syscall_names[wrap_pos] );
746 syscall_tables[idx].ServiceTable = (ULONG_PTR *)(thunks + start_pos);
747 syscall_tables[idx].ServiceLimit = max_pos + 1;
748 start_pos += max_pos + 1;
752 /**********************************************************************
753 * init_image_mapping
755 void init_image_mapping( HMODULE module )
757 void **ptr = RtlFindExportedRoutineByName( module, "Wow64Transition" );
759 if (!ptr) return;
760 *ptr = pBTCpuGetBopCode();
761 if (!win32u_module && RtlFindExportedRoutineByName( module, "NtUserInitializeClientPfnArrays" ))
763 win32u_module = module;
764 init_syscall_table( win32u_module, 1, psdwhwin32, TRUE );
769 /**********************************************************************
770 * load_32bit_module
772 static HMODULE load_32bit_module( const WCHAR *name, WORD machine, BOOL image )
774 NTSTATUS status;
775 OBJECT_ATTRIBUTES attr;
776 IO_STATUS_BLOCK io;
777 LARGE_INTEGER size;
778 UNICODE_STRING str;
779 SIZE_T len = 0;
780 void *ptr = NULL;
781 HANDLE handle, mapping;
782 WCHAR path[MAX_PATH];
783 const WCHAR *dir = get_machine_wow64_dir( machine );
785 swprintf( path, MAX_PATH, L"%s\\%s", dir, name );
786 RtlInitUnicodeString( &str, path );
787 InitializeObjectAttributes( &attr, &str, OBJ_CASE_INSENSITIVE, 0, NULL );
789 status = NtOpenFile( &handle, GENERIC_READ | SYNCHRONIZE, &attr, &io,
790 FILE_SHARE_READ | FILE_SHARE_DELETE,
791 FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE );
792 if (status) return NULL;
794 size.QuadPart = 0;
795 status = NtCreateSection( &mapping, STANDARD_RIGHTS_REQUIRED | SECTION_QUERY |
796 SECTION_MAP_READ | SECTION_MAP_EXECUTE, NULL,
797 &size, PAGE_EXECUTE_READ, image ? SEC_IMAGE : SEC_COMMIT, handle );
798 NtClose( handle );
799 if (status) return NULL;
801 status = NtMapViewOfSection( mapping, NtCurrentProcess(), &ptr, 0, 0, NULL, &len,
802 ViewShare, 0, PAGE_EXECUTE_READ );
803 NtClose( mapping );
804 if (!NT_SUCCESS( status )) ptr = NULL;
805 return ptr;
809 /**********************************************************************
810 * load_64bit_module
812 static HMODULE load_64bit_module( const WCHAR *name )
814 NTSTATUS status;
815 HMODULE module;
816 UNICODE_STRING str;
817 WCHAR path[MAX_PATH];
818 const WCHAR *dir = get_machine_wow64_dir( IMAGE_FILE_MACHINE_TARGET_HOST );
820 swprintf( path, MAX_PATH, L"%s\\%s", dir, name );
821 RtlInitUnicodeString( &str, path );
822 if ((status = LdrLoadDll( dir, 0, &str, &module )))
824 ERR( "failed to load dll %lx\n", status );
825 NtTerminateProcess( GetCurrentProcess(), status );
827 return module;
831 /**********************************************************************
832 * get_cpu_dll_name
834 static const WCHAR *get_cpu_dll_name(void)
836 static ULONG buffer[32];
837 KEY_VALUE_PARTIAL_INFORMATION *info = (KEY_VALUE_PARTIAL_INFORMATION *)buffer;
838 OBJECT_ATTRIBUTES attr;
839 UNICODE_STRING nameW;
840 const WCHAR *ret;
841 HANDLE key;
842 ULONG size;
844 switch (current_machine)
846 case IMAGE_FILE_MACHINE_I386:
847 RtlInitUnicodeString( &nameW, L"\\Registry\\Machine\\Software\\Microsoft\\Wow64\\x86" );
848 ret = (native_machine == IMAGE_FILE_MACHINE_ARM64 ? L"xtajit.dll" : L"wow64cpu.dll");
849 break;
850 case IMAGE_FILE_MACHINE_ARMNT:
851 RtlInitUnicodeString( &nameW, L"\\Registry\\Machine\\Software\\Microsoft\\Wow64\\arm" );
852 ret = L"wowarmhw.dll";
853 break;
854 default:
855 ERR( "unsupported machine %04x\n", current_machine );
856 RtlExitUserProcess( 1 );
858 InitializeObjectAttributes( &attr, &nameW, OBJ_CASE_INSENSITIVE, 0, NULL );
859 if (NtOpenKey( &key, KEY_READ | KEY_WOW64_64KEY, &attr )) return ret;
860 RtlInitUnicodeString( &nameW, L"" );
861 size = sizeof(buffer) - sizeof(WCHAR);
862 if (!NtQueryValueKey( key, &nameW, KeyValuePartialInformation, buffer, size, &size ) && info->Type == REG_SZ)
864 ((WCHAR *)info->Data)[info->DataLength / sizeof(WCHAR)] = 0;
865 ret = (WCHAR *)info->Data;
867 NtClose( key );
868 return ret;
872 /**********************************************************************
873 * process_init
875 static DWORD WINAPI process_init( RTL_RUN_ONCE *once, void *param, void **context )
877 PEB32 *peb32;
878 HMODULE module, ntdll;
879 UNICODE_STRING str = RTL_CONSTANT_STRING( L"ntdll.dll" );
880 SYSTEM_BASIC_INFORMATION info;
882 RtlWow64GetProcessMachines( GetCurrentProcess(), &current_machine, &native_machine );
883 if (!current_machine) current_machine = native_machine;
884 args_alignment = (current_machine == IMAGE_FILE_MACHINE_I386) ? sizeof(ULONG) : sizeof(ULONG64);
885 NtQuerySystemInformation( SystemEmulationBasicInformation, &info, sizeof(info), NULL );
886 highest_user_address = (ULONG_PTR)info.HighestUserAddress;
887 default_zero_bits = (ULONG_PTR)info.HighestUserAddress | 0x7fffffff;
888 NtQueryInformationProcess( GetCurrentProcess(), ProcessWow64Information, &peb32, sizeof(peb32), NULL );
889 wow64info = (WOW64INFO *)(peb32 + 1);
890 wow64info->NativeSystemPageSize = 0x1000;
891 wow64info->NativeMachineType = native_machine;
892 wow64info->EmulatedMachineType = current_machine;
893 NtCurrentTeb()->TlsSlots[WOW64_TLS_WOW64INFO] = wow64info;
895 #define GET_PTR(name) p ## name = RtlFindExportedRoutineByName( module, #name )
897 LdrGetDllHandle( NULL, 0, &str, &module );
898 GET_PTR( LdrSystemDllInitBlock );
900 module = load_64bit_module( get_cpu_dll_name() );
901 GET_PTR( BTCpuGetBopCode );
902 GET_PTR( BTCpuGetContext );
903 GET_PTR( BTCpuIsProcessorFeaturePresent );
904 GET_PTR( BTCpuProcessInit );
905 GET_PTR( BTCpuThreadInit );
906 GET_PTR( BTCpuResetToConsistentState );
907 GET_PTR( BTCpuSetContext );
908 GET_PTR( BTCpuSimulate );
909 GET_PTR( BTCpuNotifyFlushInstructionCache2 );
910 GET_PTR( BTCpuNotifyMapViewOfSection );
911 GET_PTR( BTCpuNotifyMemoryAlloc );
912 GET_PTR( BTCpuNotifyMemoryDirty );
913 GET_PTR( BTCpuNotifyMemoryFree );
914 GET_PTR( BTCpuNotifyMemoryProtect );
915 GET_PTR( BTCpuNotifyUnmapViewOfSection );
916 GET_PTR( BTCpuUpdateProcessorInformation );
917 GET_PTR( BTCpuThreadTerm );
918 GET_PTR( __wine_get_unix_opcode );
920 module = load_64bit_module( L"wow64win.dll" );
921 GET_PTR( sdwhwin32 );
923 pBTCpuProcessInit();
925 module = (HMODULE)(ULONG_PTR)pLdrSystemDllInitBlock->ntdll_handle;
926 init_image_mapping( module );
927 *(void **)RtlFindExportedRoutineByName( module, "__wine_syscall_dispatcher" ) = pBTCpuGetBopCode();
928 *(void **)RtlFindExportedRoutineByName( module, "__wine_unix_call_dispatcher" ) = p__wine_get_unix_opcode();
929 GET_PTR( KiRaiseUserExceptionDispatcher );
931 if ((ntdll = load_32bit_module( L"ntdll.dll", current_machine, FALSE )))
933 init_syscall_table( ntdll, 0, &ntdll_syscall_table, FALSE );
934 NtUnmapViewOfSection( NtCurrentProcess(), ntdll );
936 else init_syscall_table( module, 0, &ntdll_syscall_table, TRUE );
938 init_file_redirects();
939 return TRUE;
941 #undef GET_PTR
945 /**********************************************************************
946 * thread_init
948 static void thread_init(void)
950 void *cpu_area_ctx;
952 RtlWow64GetCurrentCpuArea( NULL, &cpu_area_ctx, NULL );
953 NtCurrentTeb()->TlsSlots[WOW64_TLS_WOW64INFO] = wow64info;
954 if (pBTCpuThreadInit) pBTCpuThreadInit();
956 /* update initial context to jump to 32-bit LdrInitializeThunk (cf. 32-bit call_init_thunk) */
957 switch (current_machine)
959 case IMAGE_FILE_MACHINE_I386:
961 I386_CONTEXT *ctx_ptr, *ctx = cpu_area_ctx;
962 ULONG *stack;
964 ctx_ptr = (I386_CONTEXT *)ULongToPtr( ctx->Esp ) - 1;
965 *ctx_ptr = *ctx;
967 stack = (ULONG *)ctx_ptr;
968 *(--stack) = 0;
969 *(--stack) = 0;
970 *(--stack) = 0;
971 *(--stack) = PtrToUlong( ctx_ptr );
972 *(--stack) = 0xdeadbabe;
973 ctx->Esp = PtrToUlong( stack );
974 ctx->Eip = pLdrSystemDllInitBlock->pLdrInitializeThunk;
975 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL, ctx );
977 break;
979 case IMAGE_FILE_MACHINE_ARMNT:
981 ARM_CONTEXT *ctx_ptr, *ctx = cpu_area_ctx;
983 ctx_ptr = (ARM_CONTEXT *)ULongToPtr( ctx->Sp & ~15 ) - 1;
984 *ctx_ptr = *ctx;
986 ctx->R0 = PtrToUlong( ctx_ptr );
987 ctx->Sp = PtrToUlong( ctx_ptr );
988 ctx->Pc = pLdrSystemDllInitBlock->pLdrInitializeThunk;
989 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL, ctx );
991 break;
993 default:
994 ERR( "not supported machine %x\n", current_machine );
995 NtTerminateProcess( GetCurrentProcess(), STATUS_INVALID_IMAGE_FORMAT );
1000 /**********************************************************************
1001 * free_temp_data
1003 static void free_temp_data(void)
1005 struct mem_header *next, *mem;
1007 for (mem = NtCurrentTeb()->TlsSlots[WOW64_TLS_TEMPLIST]; mem; mem = next)
1009 next = mem->next;
1010 RtlFreeHeap( GetProcessHeap(), 0, mem );
1012 NtCurrentTeb()->TlsSlots[WOW64_TLS_TEMPLIST] = NULL;
1016 /**********************************************************************
1017 * syscall_filter
1019 static LONG CALLBACK syscall_filter( EXCEPTION_POINTERS *ptrs )
1021 switch (ptrs->ExceptionRecord->ExceptionCode)
1023 case STATUS_INVALID_HANDLE:
1024 call_raise_user_exception_dispatcher( ptrs->ExceptionRecord->ExceptionCode );
1025 break;
1027 return EXCEPTION_EXECUTE_HANDLER;
1031 /**********************************************************************
1032 * Wow64SystemServiceEx (wow64.@)
1034 NTSTATUS WINAPI Wow64SystemServiceEx( UINT num, UINT *args )
1036 NTSTATUS status;
1037 UINT id = num & 0xfff;
1038 const SYSTEM_SERVICE_TABLE *table = &syscall_tables[(num >> 12) & 3];
1040 if (id >= table->ServiceLimit || !table->ServiceTable[id])
1042 ERR( "unsupported syscall %04x\n", num );
1043 return STATUS_INVALID_SYSTEM_SERVICE;
1045 __TRY
1047 syscall_thunk thunk = (syscall_thunk)table->ServiceTable[id];
1048 status = thunk( args );
1050 __EXCEPT( syscall_filter )
1052 status = GetExceptionCode();
1054 __ENDTRY
1055 free_temp_data();
1056 return status;
1060 /**********************************************************************
1061 * simulate_filter
1063 static LONG CALLBACK simulate_filter( EXCEPTION_POINTERS *ptrs )
1065 Wow64PassExceptionToGuest( ptrs );
1066 return EXCEPTION_EXECUTE_HANDLER;
1070 /**********************************************************************
1071 * cpu_simulate
1073 static void cpu_simulate(void)
1075 for (;;)
1077 __TRY
1079 pBTCpuSimulate();
1081 __EXCEPT( simulate_filter )
1083 /* restart simulation loop */
1085 __ENDTRY
1090 /**********************************************************************
1091 * Wow64AllocateTemp (wow64.@)
1093 * FIXME: probably not 100% compatible.
1095 void * WINAPI Wow64AllocateTemp( SIZE_T size )
1097 struct mem_header *mem;
1099 if (!(mem = RtlAllocateHeap( GetProcessHeap(), 0, offsetof( struct mem_header, data[size] ))))
1100 return NULL;
1101 mem->next = NtCurrentTeb()->TlsSlots[WOW64_TLS_TEMPLIST];
1102 NtCurrentTeb()->TlsSlots[WOW64_TLS_TEMPLIST] = mem;
1103 return mem->data;
1107 /**********************************************************************
1108 * Wow64ApcRoutine (wow64.@)
1110 void WINAPI Wow64ApcRoutine( ULONG_PTR arg1, ULONG_PTR arg2, ULONG_PTR arg3, CONTEXT *context )
1112 struct user_apc_frame frame;
1114 frame.prev_frame = NtCurrentTeb()->TlsSlots[WOW64_TLS_APCLIST];
1115 frame.context = context;
1116 NtCurrentTeb()->TlsSlots[WOW64_TLS_APCLIST] = &frame;
1118 /* cf. 32-bit call_user_apc_dispatcher */
1119 switch (current_machine)
1121 case IMAGE_FILE_MACHINE_I386:
1123 struct apc_stack_layout
1125 ULONG ret;
1126 ULONG context_ptr;
1127 ULONG arg1;
1128 ULONG arg2;
1129 ULONG arg3;
1130 ULONG func;
1131 I386_CONTEXT context;
1132 } *stack;
1133 I386_CONTEXT ctx = { CONTEXT_I386_FULL };
1135 pBTCpuGetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx );
1136 stack = (struct apc_stack_layout *)ULongToPtr( ctx.Esp & ~3 ) - 1;
1137 stack->context_ptr = PtrToUlong( &stack->context );
1138 stack->func = arg1 >> 32;
1139 stack->arg1 = arg1;
1140 stack->arg2 = arg2;
1141 stack->arg3 = arg3;
1142 stack->context = ctx;
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 I386_CONTEXT orig_ctx, ctx = { CONTEXT_I386_FULL };
1206 void *args_data;
1207 ULONG *stack;
1209 pBTCpuGetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx );
1210 orig_ctx = ctx;
1212 stack = args_data = ULongToPtr( (ctx.Esp - len) & ~15 );
1213 memcpy( args_data, args, len );
1214 *(--stack) = 0;
1215 *(--stack) = len;
1216 *(--stack) = PtrToUlong( args_data );
1217 *(--stack) = id;
1218 *(--stack) = 0xdeadbabe;
1220 ctx.Esp = PtrToUlong( stack );
1221 ctx.Eip = pLdrSystemDllInitBlock->pKiUserCallbackDispatcher;
1222 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx );
1224 if (!__wine_setjmpex( &frame.jmpbuf, NULL ))
1225 cpu_simulate();
1226 else
1227 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &orig_ctx );
1229 break;
1231 case IMAGE_FILE_MACHINE_ARMNT:
1233 ARM_CONTEXT orig_ctx, ctx = { CONTEXT_ARM_FULL };
1234 void *args_data;
1236 pBTCpuGetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx );
1237 orig_ctx = ctx;
1239 args_data = ULongToPtr( (ctx.Sp - len) & ~15 );
1240 memcpy( args_data, args, len );
1242 ctx.R0 = id;
1243 ctx.R1 = PtrToUlong( args_data );
1244 ctx.R2 = len;
1245 ctx.Sp = PtrToUlong( args_data );
1246 ctx.Pc = pLdrSystemDllInitBlock->pKiUserCallbackDispatcher;
1247 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx );
1249 if (!__wine_setjmpex( &frame.jmpbuf, NULL ))
1250 cpu_simulate();
1251 else
1252 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &orig_ctx );
1254 break;
1257 teb32->Tib.ExceptionList = teb_frame;
1258 NtCurrentTeb()->TlsSlots[WOW64_TLS_USERCALLBACKDATA] = frame.prev_frame;
1259 NtCurrentTeb()->TlsSlots[WOW64_TLS_TEMPLIST] = frame.temp_list;
1260 cpu->Flags = flags;
1261 return frame.status;
1265 /**********************************************************************
1266 * Wow64LdrpInitialize (wow64.@)
1268 void WINAPI Wow64LdrpInitialize( CONTEXT *context )
1270 static RTL_RUN_ONCE init_done;
1272 RtlRunOnceExecuteOnce( &init_done, process_init, NULL, NULL );
1273 thread_init();
1274 cpu_simulate();
1278 /**********************************************************************
1279 * Wow64PrepareForException (wow64.@)
1281 void WINAPI Wow64PrepareForException( EXCEPTION_RECORD *rec, CONTEXT *context )
1283 EXCEPTION_POINTERS ptrs = { rec, context };
1285 pBTCpuResetToConsistentState( &ptrs );
1289 /**********************************************************************
1290 * Wow64PassExceptionToGuest (wow64.@)
1292 void WINAPI Wow64PassExceptionToGuest( EXCEPTION_POINTERS *ptrs )
1294 EXCEPTION_RECORD32 rec32;
1296 exception_record_64to32( &rec32, ptrs->ExceptionRecord );
1297 call_user_exception_dispatcher( &rec32, NULL, ptrs->ContextRecord );
1301 /**********************************************************************
1302 * Wow64RaiseException (wow64.@)
1304 NTSTATUS WINAPI Wow64RaiseException( int code, EXCEPTION_RECORD *rec )
1306 EXCEPTION_RECORD32 rec32;
1307 CONTEXT context;
1308 BOOL first_chance = TRUE;
1309 union
1311 I386_CONTEXT i386;
1312 ARM_CONTEXT arm;
1313 } ctx32 = { 0 };
1315 switch (current_machine)
1317 case IMAGE_FILE_MACHINE_I386:
1319 EXCEPTION_RECORD int_rec = { 0 };
1321 ctx32.i386.ContextFlags = CONTEXT_I386_ALL;
1322 pBTCpuGetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx32.i386 );
1323 if (code == -1) break;
1324 int_rec.ExceptionAddress = (void *)(ULONG_PTR)ctx32.i386.Eip;
1325 switch (code)
1327 case 0x00: /* division by zero */
1328 int_rec.ExceptionCode = EXCEPTION_INT_DIVIDE_BY_ZERO;
1329 break;
1330 case 0x01: /* single-step */
1331 int_rec.ExceptionCode = EXCEPTION_SINGLE_STEP;
1332 break;
1333 case 0x03: /* breakpoint */
1334 int_rec.ExceptionCode = EXCEPTION_BREAKPOINT;
1335 int_rec.ExceptionAddress = (void *)(ULONG_PTR)(ctx32.i386.Eip + 1);
1336 int_rec.NumberParameters = 1;
1337 break;
1338 case 0x04: /* overflow */
1339 int_rec.ExceptionCode = EXCEPTION_INT_OVERFLOW;
1340 break;
1341 case 0x05: /* array bounds */
1342 int_rec.ExceptionCode = EXCEPTION_ARRAY_BOUNDS_EXCEEDED;
1343 break;
1344 case 0x06: /* invalid opcode */
1345 int_rec.ExceptionCode = EXCEPTION_ILLEGAL_INSTRUCTION;
1346 break;
1347 case 0x09: /* coprocessor segment overrun */
1348 int_rec.ExceptionCode = EXCEPTION_FLT_INVALID_OPERATION;
1349 break;
1350 case 0x0c: /* stack fault */
1351 int_rec.ExceptionCode = EXCEPTION_STACK_OVERFLOW;
1352 break;
1353 case 0x29: /* __fastfail */
1354 int_rec.ExceptionCode = STATUS_STACK_BUFFER_OVERRUN;
1355 int_rec.ExceptionFlags = EH_NONCONTINUABLE;
1356 int_rec.NumberParameters = 1;
1357 int_rec.ExceptionInformation[0] = ctx32.i386.Ecx;
1358 first_chance = FALSE;
1359 break;
1360 case 0x2d: /* debug service */
1361 ctx32.i386.Eip++;
1362 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx32.i386 );
1363 int_rec.ExceptionCode = EXCEPTION_BREAKPOINT;
1364 int_rec.ExceptionAddress = (void *)(ULONG_PTR)ctx32.i386.Eip;
1365 int_rec.NumberParameters = 1;
1366 int_rec.ExceptionInformation[0] = ctx32.i386.Eax;
1367 break;
1368 default:
1369 ctx32.i386.Eip -= 2;
1370 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx32.i386 );
1371 int_rec.ExceptionCode = EXCEPTION_ACCESS_VIOLATION;
1372 int_rec.ExceptionAddress = (void *)(ULONG_PTR)ctx32.i386.Eip;
1373 int_rec.NumberParameters = 2;
1374 int_rec.ExceptionInformation[1] = 0xffffffff;
1375 break;
1377 *rec = int_rec;
1378 break;
1381 case IMAGE_FILE_MACHINE_ARMNT:
1382 ctx32.arm.ContextFlags = CONTEXT_ARM_ALL;
1383 pBTCpuGetContext( GetCurrentThread(), GetCurrentProcess(), NULL, &ctx32.arm );
1384 break;
1387 exception_record_64to32( &rec32, rec );
1388 __TRY
1390 raise_exception( rec, &context, first_chance );
1392 __EXCEPT_ALL
1394 call_user_exception_dispatcher( &rec32, &ctx32, NULL );
1396 __ENDTRY
1397 return STATUS_SUCCESS;