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 */
200 CONTEXT_EX32 context_ex
; /* 324 */
201 BYTE xstate
[sizeof(XSTATE
)+64]; /* 33c */
202 DWORD align
; /* 4bc */
204 I386_CONTEXT ctx
= { CONTEXT_I386_ALL
};
205 CONTEXT_EX
*context_ex
, *src_ex
= NULL
;
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
);
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
);
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
--;
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
);
267 case IMAGE_FILE_MACHINE_ARMNT
:
272 EXCEPTION_RECORD32 rec
;
274 ARM_CONTEXT ctx
= { CONTEXT_ARM_ALL
};
276 pBTCpuGetContext( GetCurrentThread(), GetCurrentProcess(), NULL
, &ctx
);
277 stack
= (struct stack_layout
*)(ULONG_PTR
)(ctx
.Sp
& ~3) - 1;
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
);
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
);
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
);
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
);
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"
358 "ldp x29, x30, [sp], #48\n\t"
359 "add sp, sp, #0x390\n\t"
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 */
368 "mov x2, x0\n\t" /* rec */
369 "mov x0, x1\n\t" /* frame */
370 "adr x1, raise_exception_ret\n\t"
372 "1:\tmov w0, #1\n\t" /* ExceptionContinueSearch */
373 "ldp x29, x30, [sp], #16\n\t"
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"
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"
399 "add $0x4d8,%rsp\n\t"
401 __ASM_GLOBAL_FUNC( raise_exception_handler
,
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"
413 /**********************************************************************
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 /**********************************************************************
475 NTSTATUS WINAPI
wow64_NtClose( UINT
*args
)
477 HANDLE handle
= get_handle( &args
);
479 return NtClose( handle
);
483 /**********************************************************************
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();
505 /**********************************************************************
508 NTSTATUS WINAPI
wow64_NtDeleteAtom( UINT
*args
)
510 RTL_ATOM atom
= get_ulong( &args
);
512 return NtDeleteAtom( atom
);
516 /**********************************************************************
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 /**********************************************************************
677 void init_image_mapping( HMODULE module
)
679 ULONG
*ptr
= RtlFindExportedRoutineByName( module
, "Wow64Transition" );
681 if (ptr
) *ptr
= PtrToUlong( pBTCpuGetBopCode() );
685 /**********************************************************************
688 static HMODULE
load_64bit_module( const WCHAR
*name
)
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
);
707 /**********************************************************************
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
;
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");
726 case IMAGE_FILE_MACHINE_ARMNT
:
727 RtlInitUnicodeString( &nameW
, L
"\\Registry\\Machine\\Software\\Microsoft\\Wow64\\arm" );
728 ret
= L
"wowarmhw.dll";
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
;
748 /**********************************************************************
749 * create_cross_process_work_list
751 static NTSTATUS
create_cross_process_work_list( WOW64INFO
*wow64info
)
753 SIZE_T map_size
= 0x4000;
757 CROSS_PROCESS_WORK_LIST
*list
= NULL
;
758 CROSS_PROCESS_WORK_ENTRY
*end
;
761 size
.QuadPart
= map_size
;
762 status
= NtCreateSection( §ion
, 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
);
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 /**********************************************************************
785 static DWORD WINAPI
process_init( RTL_RUN_ONCE
*once
, void *param
, void **context
)
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(), ¤t_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
;
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();
856 /**********************************************************************
859 static void thread_init(void)
861 TEB32
*teb32
= (TEB32
*)((char *)NtCurrentTeb() + NtCurrentTeb()->WowTebOffset
);
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
;
877 ctx_ptr
= (I386_CONTEXT
*)ULongToPtr( ctx
->Esp
) - 1;
880 stack
= (ULONG
*)ctx_ptr
;
884 *(--stack
) = PtrToUlong( ctx_ptr
);
885 *(--stack
) = 0xdeadbabe;
886 ctx
->Esp
= PtrToUlong( stack
);
887 ctx
->Eip
= pLdrSystemDllInitBlock
->pLdrInitializeThunk
;
888 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL
, ctx
);
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;
899 ctx
->R0
= PtrToUlong( ctx_ptr
);
900 ctx
->Sp
= PtrToUlong( ctx_ptr
);
901 ctx
->Pc
= pLdrSystemDllInitBlock
->pLdrInitializeThunk
;
902 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL
, ctx
);
907 ERR( "not supported machine %x\n", current_machine
);
908 NtTerminateProcess( GetCurrentProcess(), STATUS_INVALID_IMAGE_FORMAT
);
913 /**********************************************************************
916 static void free_temp_data(void)
918 struct mem_header
*next
, *mem
;
920 for (mem
= NtCurrentTeb()->TlsSlots
[WOW64_TLS_TEMPLIST
]; mem
; mem
= next
)
923 RtlFreeHeap( GetProcessHeap(), 0, mem
);
925 NtCurrentTeb()->TlsSlots
[WOW64_TLS_TEMPLIST
] = NULL
;
929 /**********************************************************************
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"
941 "wow64_syscall_ret:\n\t"
942 "eor w1, w0, #0xc0000000\n\t"
943 "cmp w1, #8\n\t" /* STATUS_INVALID_HANDLE */
945 "bl call_raise_user_exception_dispatcher\n"
946 "1:\tldp x29, x30, [sp], #16\n\t"
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 */
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 */
960 "1:\tmov w0, #1\n\t" /* ExceptionContinueSearch */
961 "ldp x29, x30, [sp], #16\n\t"
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"
972 "wow64_syscall_ret:\n\t"
973 "cmpl $0xc0000008,%eax\n\t" /* STATUS_INVALID_HANDLE */
976 "call call_raise_user_exception_dispatcher\n"
977 "1:\taddq $0x28, %rsp\n\t"
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"
992 /**********************************************************************
993 * Wow64SystemServiceEx (wow64.@)
995 NTSTATUS WINAPI
Wow64SystemServiceEx( UINT num
, UINT
*args
)
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
] );
1012 /**********************************************************************
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"
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 */
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 */
1045 "1:\tmov w0, #1\n\t" /* ExceptionContinueSearch */
1046 "ldp x19, x20, [sp, #16]\n\t"
1047 "ldp x29, x30, [sp], #48\n\t"
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"
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
] ))))
1088 mem
->next
= NtCurrentTeb()->TlsSlots
[WOW64_TLS_TEMPLIST
];
1089 NtCurrentTeb()->TlsSlots
[WOW64_TLS_TEMPLIST
] = mem
;
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 */
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;
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
);
1151 case IMAGE_FILE_MACHINE_ARMNT
:
1153 struct apc_stack_layout
1157 ARM_CONTEXT context
;
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
);
1171 frame
.wow_context
= &stack
->context
;
1172 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL
, &ctx
);
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 */
1210 ULONG args
; /* 008 */
1211 ULONG len
; /* 00c */
1212 ULONG unk
[2]; /* 010 */
1213 ULONG esp
; /* 018 */
1214 BYTE args_data
[0]; /* 01c */
1216 I386_CONTEXT orig_ctx
, ctx
= { CONTEXT_I386_FULL
};
1218 C_ASSERT( sizeof(struct callback_stack_layout32
) == 0x1c );
1220 pBTCpuGetContext( GetCurrentThread(), GetCurrentProcess(), NULL
, &ctx
);
1223 stack
= ULongToPtr( (ctx
.Esp
- offsetof(struct callback_stack_layout32
,args_data
[len
])) & ~15 );
1224 stack
->eip
= ctx
.Eip
;
1226 stack
->args
= PtrToUlong( stack
->args_data
);
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
))
1238 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL
, &orig_ctx
);
1242 case IMAGE_FILE_MACHINE_ARMNT
:
1244 ARM_CONTEXT orig_ctx
, ctx
= { CONTEXT_ARM_FULL
};
1247 pBTCpuGetContext( GetCurrentThread(), GetCurrentProcess(), NULL
, &ctx
);
1250 args_data
= ULongToPtr( (ctx
.Sp
- len
) & ~15 );
1251 memcpy( args_data
, args
, len
);
1254 ctx
.R1
= PtrToUlong( args_data
);
1256 ctx
.Sp
= PtrToUlong( args_data
);
1257 ctx
.Pc
= pLdrSystemDllInitBlock
->pKiUserCallbackDispatcher
;
1258 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL
, &ctx
);
1260 if (!setjmp( frame
.jmpbuf
))
1263 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL
, &orig_ctx
);
1268 teb32
->Tib
.ExceptionList
= teb_frame
;
1269 NtCurrentTeb()->TlsSlots
[WOW64_TLS_USERCALLBACKDATA
] = frame
.prev_frame
;
1270 NtCurrentTeb()->TlsSlots
[WOW64_TLS_TEMPLIST
] = frame
.temp_list
;
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
);
1289 /**********************************************************************
1290 * Wow64PrepareForException (wow64.@)
1293 __ASM_GLOBAL_FUNC( Wow64PrepareForException
,
1294 "sub $0x38,%rsp\n\t"
1295 "mov %rcx,%r10\n\t" /* rec */
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 */
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"
1308 /* update arguments to point to the new stack */
1311 "add %rax,%r10\n\t" /* rec */
1312 "add %rax,%rdx\n\t" /* context */
1313 /* switch to 64-bit stack */
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"
1321 "add $0x38,%rsp\n\t"
1324 void WINAPI
Wow64PrepareForException( EXCEPTION_RECORD
*rec
, CONTEXT
*context
)
1326 EXCEPTION_POINTERS ptrs
= { rec
, context
};
1328 pBTCpuResetToConsistentState( &ptrs
);
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
;
1356 entry
= RtlWow64PopAllCrossProcessWorkFromWorkList( &list
->work_list
, &flush
);
1360 if (pBTCpuNotifyFlushInstructionCache2
) pBTCpuNotifyFlushInstructionCache2( NULL
, ~0ull );
1364 RtlWow64PushCrossProcessWorkOntoFreeList( &list
->free_list
, entry
);
1365 entry
= CROSS_PROCESS_LIST_ENTRY( &list
->work_list
, next
);
1374 case CrossProcessPreVirtualAlloc
:
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] );
1382 case CrossProcessPreVirtualFree
:
1383 if (!pBTCpuNotifyMemoryFree
) break;
1384 pBTCpuNotifyMemoryFree( (void *)entry
->addr
, entry
->size
, entry
->args
[0] );
1386 case CrossProcessPostVirtualFree
:
1389 case CrossProcessPreVirtualProtect
:
1390 if (!pBTCpuNotifyMemoryProtect
) break;
1391 pBTCpuNotifyMemoryProtect( (void *)entry
->addr
, entry
->size
, entry
->args
[0] );
1393 case CrossProcessPostVirtualProtect
:
1396 case CrossProcessFlushCache
:
1397 if (!pBTCpuNotifyFlushInstructionCache2
) break;
1398 pBTCpuNotifyFlushInstructionCache2( (void *)entry
->addr
, entry
->size
);
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
;
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
;
1433 case 0x00: /* division by zero */
1434 int_rec
.ExceptionCode
= EXCEPTION_INT_DIVIDE_BY_ZERO
;
1436 case 0x01: /* single-step */
1437 ctx32
.i386
.EFlags
&= ~0x100;
1438 pBTCpuSetContext( GetCurrentThread(), GetCurrentProcess(), NULL
, &ctx32
.i386
);
1439 int_rec
.ExceptionCode
= EXCEPTION_SINGLE_STEP
;
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;
1446 case 0x04: /* overflow */
1447 int_rec
.ExceptionCode
= EXCEPTION_INT_OVERFLOW
;
1449 case 0x05: /* array bounds */
1450 int_rec
.ExceptionCode
= EXCEPTION_ARRAY_BOUNDS_EXCEEDED
;
1452 case 0x06: /* invalid opcode */
1453 int_rec
.ExceptionCode
= EXCEPTION_ILLEGAL_INSTRUCTION
;
1455 case 0x09: /* coprocessor segment overrun */
1456 int_rec
.ExceptionCode
= EXCEPTION_FLT_INVALID_OPERATION
;
1458 case 0x0c: /* stack fault */
1459 int_rec
.ExceptionCode
= EXCEPTION_STACK_OVERFLOW
;
1461 case 0x0d: /* general protection fault */
1462 int_rec
.ExceptionCode
= EXCEPTION_PRIV_INSTRUCTION
;
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
;
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
;
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;
1490 case IMAGE_FILE_MACHINE_ARMNT
:
1491 ctx32
.arm
.ContextFlags
= CONTEXT_ARM_ALL
;
1492 pBTCpuGetContext( GetCurrentThread(), GetCurrentProcess(), NULL
, &ctx32
.arm
);
1496 exception_record_64to32( &rec32
, rec
);
1497 raise_exception( &rec32
, &ctx32
, first_chance
, rec
);
1499 return STATUS_SUCCESS
;