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
25 #define WIN32_NO_STATUS
30 #include "rtlsupportapi.h"
31 #include "wine/unixlib.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,
53 static BYTE syscall_args
[ARRAY_SIZE(syscall_thunks
)] =
55 #define SYSCALL_ENTRY(id,name,args) args,
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 */
68 struct mem_header
*next
;
73 /* stack frame for user callbacks */
74 struct user_callback_frame
76 struct user_callback_frame
*prev_frame
;
77 struct mem_header
*temp_list
;
84 /* stack frame for user APCs */
87 struct user_apc_frame
*prev_frame
;
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
);
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
;
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
];
156 static void exception_record_64to32( EXCEPTION_RECORD32
*rec32
, const EXCEPTION_RECORD
*rec
)
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
;
183 /**********************************************************************
184 * call_user_exception_dispatcher
186 static void __attribute__((used
)) call_user_exception_dispatcher( EXCEPTION_RECORD32
*rec
, void *ctx32_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 */
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
);
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
);
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
);
253 case IMAGE_FILE_MACHINE_ARMNT
:
258 EXCEPTION_RECORD32 rec
;
260 ARM_CONTEXT ctx
= { CONTEXT_ARM_ALL
};
262 pBTCpuGetContext( GetCurrentThread(), GetCurrentProcess(), NULL
, &ctx
);
263 stack
= (struct stack_layout
*)(ULONG_PTR
)(ctx
.Sp
& ~3) - 1;
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
);
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
);
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
);
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
);
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"
344 "ldp x29, x30, [sp], #48\n\t"
345 "add sp, sp, #0x390\n\t"
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 */
354 "mov x2, x0\n\t" /* rec */
355 "mov x0, x1\n\t" /* frame */
356 "adr x1, raise_exception_ret\n\t"
358 "1:\tmov w0, #1\n\t" /* ExceptionContinueSearch */
359 "ldp x29, x30, [sp], #16\n\t"
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"
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"
385 "add $0x4d8,%rsp\n\t"
387 __ASM_GLOBAL_FUNC( raise_exception_handler
,
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"
399 /**********************************************************************
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 /**********************************************************************
461 NTSTATUS WINAPI
wow64_NtClose( UINT
*args
)
463 HANDLE handle
= get_handle( &args
);
465 return NtClose( handle
);
469 /**********************************************************************
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();
491 /**********************************************************************
494 NTSTATUS WINAPI
wow64_NtDeleteAtom( UINT
*args
)
496 RTL_ATOM atom
= get_ulong( &args
);
498 return NtDeleteAtom( atom
);
502 /**********************************************************************
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 /**********************************************************************
663 void init_image_mapping( HMODULE module
)
665 ULONG
*ptr
= RtlFindExportedRoutineByName( module
, "Wow64Transition" );
667 if (ptr
) *ptr
= PtrToUlong( pBTCpuGetBopCode() );
671 /**********************************************************************
674 static HMODULE
load_64bit_module( const WCHAR
*name
)
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
);
693 /**********************************************************************
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
;
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");
712 case IMAGE_FILE_MACHINE_ARMNT
:
713 RtlInitUnicodeString( &nameW
, L
"\\Registry\\Machine\\Software\\Microsoft\\Wow64\\arm" );
714 ret
= L
"wowarmhw.dll";
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
;
734 /**********************************************************************
735 * create_cross_process_work_list
737 static NTSTATUS
create_cross_process_work_list( WOW64INFO
*wow64info
)
739 SIZE_T map_size
= 0x4000;
743 CROSS_PROCESS_WORK_LIST
*list
= NULL
;
744 CROSS_PROCESS_WORK_ENTRY
*end
;
747 size
.QuadPart
= map_size
;
748 status
= NtCreateSection( §ion
, 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
);
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 /**********************************************************************
771 static DWORD WINAPI
process_init( RTL_RUN_ONCE
*once
, void *param
, void **context
)
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(), ¤t_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
;
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();
842 /**********************************************************************
845 static void thread_init(void)
847 TEB32
*teb32
= (TEB32
*)((char *)NtCurrentTeb() + NtCurrentTeb()->WowTebOffset
);
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
;
863 ctx_ptr
= (I386_CONTEXT
*)ULongToPtr( ctx
->Esp
) - 1;
866 stack
= (ULONG
*)ctx_ptr
;
870 *(--stack
) = PtrToUlong( ctx_ptr
);
871 *(--stack
) = 0xdeadbabe;
872 ctx
->Esp
= PtrToUlong( stack
);
873 ctx
->Eip
= pLdrSystemDllInitBlock
->pLdrInitializeThunk
;
874 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL
, ctx
);
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;
885 ctx
->R0
= PtrToUlong( ctx_ptr
);
886 ctx
->Sp
= PtrToUlong( ctx_ptr
);
887 ctx
->Pc
= pLdrSystemDllInitBlock
->pLdrInitializeThunk
;
888 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL
, ctx
);
893 ERR( "not supported machine %x\n", current_machine
);
894 NtTerminateProcess( GetCurrentProcess(), STATUS_INVALID_IMAGE_FORMAT
);
899 /**********************************************************************
902 static void free_temp_data(void)
904 struct mem_header
*next
, *mem
;
906 for (mem
= NtCurrentTeb()->TlsSlots
[WOW64_TLS_TEMPLIST
]; mem
; mem
= next
)
909 RtlFreeHeap( GetProcessHeap(), 0, mem
);
911 NtCurrentTeb()->TlsSlots
[WOW64_TLS_TEMPLIST
] = NULL
;
915 /**********************************************************************
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"
927 "wow64_syscall_ret:\n\t"
928 "eor w1, w0, #0xc0000000\n\t"
929 "cmp w1, #8\n\t" /* STATUS_INVALID_HANDLE */
931 "bl call_raise_user_exception_dispatcher\n"
932 "1:\tldp x29, x30, [sp], #16\n\t"
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 */
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 */
946 "1:\tmov w0, #1\n\t" /* ExceptionContinueSearch */
947 "ldp x29, x30, [sp], #16\n\t"
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"
958 "wow64_syscall_ret:\n\t"
959 "cmpl $0xc0000008,%eax\n\t" /* STATUS_INVALID_HANDLE */
962 "call call_raise_user_exception_dispatcher\n"
963 "1:\taddq $0x28, %rsp\n\t"
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"
978 /**********************************************************************
979 * Wow64SystemServiceEx (wow64.@)
981 NTSTATUS WINAPI
Wow64SystemServiceEx( UINT num
, UINT
*args
)
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
] );
998 /**********************************************************************
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"
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 */
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 */
1031 "1:\tmov w0, #1\n\t" /* ExceptionContinueSearch */
1032 "ldp x19, x20, [sp, #16]\n\t"
1033 "ldp x29, x30, [sp], #48\n\t"
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"
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
] ))))
1074 mem
->next
= NtCurrentTeb()->TlsSlots
[WOW64_TLS_TEMPLIST
];
1075 NtCurrentTeb()->TlsSlots
[WOW64_TLS_TEMPLIST
] = mem
;
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 */
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;
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
);
1137 case IMAGE_FILE_MACHINE_ARMNT
:
1139 struct apc_stack_layout
1143 ARM_CONTEXT context
;
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
);
1157 frame
.wow_context
= &stack
->context
;
1158 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL
, &ctx
);
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 */
1196 ULONG args
; /* 008 */
1197 ULONG len
; /* 00c */
1198 ULONG unk
[2]; /* 010 */
1199 ULONG esp
; /* 018 */
1200 BYTE args_data
[0]; /* 01c */
1202 I386_CONTEXT orig_ctx
, ctx
= { CONTEXT_I386_FULL
};
1204 C_ASSERT( sizeof(struct callback_stack_layout32
) == 0x1c );
1206 pBTCpuGetContext( GetCurrentThread(), GetCurrentProcess(), NULL
, &ctx
);
1209 stack
= ULongToPtr( (ctx
.Esp
- offsetof(struct callback_stack_layout32
,args_data
[len
])) & ~15 );
1210 stack
->eip
= ctx
.Eip
;
1212 stack
->args
= PtrToUlong( stack
->args_data
);
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
))
1224 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL
, &orig_ctx
);
1228 case IMAGE_FILE_MACHINE_ARMNT
:
1230 ARM_CONTEXT orig_ctx
, ctx
= { CONTEXT_ARM_FULL
};
1233 pBTCpuGetContext( GetCurrentThread(), GetCurrentProcess(), NULL
, &ctx
);
1236 args_data
= ULongToPtr( (ctx
.Sp
- len
) & ~15 );
1237 memcpy( args_data
, args
, len
);
1240 ctx
.R1
= PtrToUlong( args_data
);
1242 ctx
.Sp
= PtrToUlong( args_data
);
1243 ctx
.Pc
= pLdrSystemDllInitBlock
->pKiUserCallbackDispatcher
;
1244 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL
, &ctx
);
1246 if (!setjmp( frame
.jmpbuf
))
1249 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL
, &orig_ctx
);
1254 teb32
->Tib
.ExceptionList
= teb_frame
;
1255 NtCurrentTeb()->TlsSlots
[WOW64_TLS_USERCALLBACKDATA
] = frame
.prev_frame
;
1256 NtCurrentTeb()->TlsSlots
[WOW64_TLS_TEMPLIST
] = frame
.temp_list
;
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
);
1275 /**********************************************************************
1276 * Wow64PrepareForException (wow64.@)
1279 __ASM_GLOBAL_FUNC( Wow64PrepareForException
,
1280 "sub $0x38,%rsp\n\t"
1281 "mov %rcx,%r10\n\t" /* rec */
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 */
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"
1294 /* update arguments to point to the new stack */
1297 "add %rax,%r10\n\t" /* rec */
1298 "add %rax,%rdx\n\t" /* context */
1299 /* switch to 64-bit stack */
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"
1307 "add $0x38,%rsp\n\t"
1310 void WINAPI
Wow64PrepareForException( EXCEPTION_RECORD
*rec
, CONTEXT
*context
)
1312 EXCEPTION_POINTERS ptrs
= { rec
, context
};
1314 pBTCpuResetToConsistentState( &ptrs
);
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
;
1342 entry
= RtlWow64PopAllCrossProcessWorkFromWorkList( &list
->work_list
, &flush
);
1346 if (pBTCpuNotifyFlushInstructionCache2
) pBTCpuNotifyFlushInstructionCache2( NULL
, ~0ull );
1350 RtlWow64PushCrossProcessWorkOntoFreeList( &list
->free_list
, entry
);
1351 entry
= CROSS_PROCESS_LIST_ENTRY( &list
->work_list
, next
);
1360 case CrossProcessPreVirtualAlloc
:
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] );
1368 case CrossProcessPreVirtualFree
:
1369 if (!pBTCpuNotifyMemoryFree
) break;
1370 pBTCpuNotifyMemoryFree( (void *)entry
->addr
, entry
->size
, entry
->args
[0] );
1372 case CrossProcessPostVirtualFree
:
1375 case CrossProcessPreVirtualProtect
:
1376 if (!pBTCpuNotifyMemoryProtect
) break;
1377 pBTCpuNotifyMemoryProtect( (void *)entry
->addr
, entry
->size
, entry
->args
[0] );
1379 case CrossProcessPostVirtualProtect
:
1382 case CrossProcessFlushCache
:
1383 if (!pBTCpuNotifyFlushInstructionCache2
) break;
1384 pBTCpuNotifyFlushInstructionCache2( (void *)entry
->addr
, entry
->size
);
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
;
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
;
1419 case 0x00: /* division by zero */
1420 int_rec
.ExceptionCode
= EXCEPTION_INT_DIVIDE_BY_ZERO
;
1422 case 0x01: /* single-step */
1423 ctx32
.i386
.EFlags
&= ~0x100;
1424 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL
, &ctx32
.i386
);
1425 int_rec
.ExceptionCode
= EXCEPTION_SINGLE_STEP
;
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;
1432 case 0x04: /* overflow */
1433 int_rec
.ExceptionCode
= EXCEPTION_INT_OVERFLOW
;
1435 case 0x05: /* array bounds */
1436 int_rec
.ExceptionCode
= EXCEPTION_ARRAY_BOUNDS_EXCEEDED
;
1438 case 0x06: /* invalid opcode */
1439 int_rec
.ExceptionCode
= EXCEPTION_ILLEGAL_INSTRUCTION
;
1441 case 0x09: /* coprocessor segment overrun */
1442 int_rec
.ExceptionCode
= EXCEPTION_FLT_INVALID_OPERATION
;
1444 case 0x0c: /* stack fault */
1445 int_rec
.ExceptionCode
= EXCEPTION_STACK_OVERFLOW
;
1447 case 0x0d: /* general protection fault */
1448 int_rec
.ExceptionCode
= EXCEPTION_PRIV_INSTRUCTION
;
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
;
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
;
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;
1476 case IMAGE_FILE_MACHINE_ARMNT
:
1477 ctx32
.arm
.ContextFlags
= CONTEXT_ARM_ALL
;
1478 pBTCpuGetContext( GetCurrentThread(), GetCurrentProcess(), NULL
, &ctx32
.arm
);
1482 exception_record_64to32( &rec32
, rec
);
1483 raise_exception( &rec32
, &ctx32
, first_chance
, rec
);
1485 return STATUS_SUCCESS
;