mirror of
git://source.winehq.org/git/wine.git
synced 2024-09-01 19:43:37 +00:00
753 lines
22 KiB
C
753 lines
22 KiB
C
/*
|
|
* WoW64 syscall wrapping
|
|
*
|
|
* Copyright 2021 Alexandre Julliard
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Lesser General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
|
|
*/
|
|
|
|
#include <stdarg.h>
|
|
|
|
#include "ntstatus.h"
|
|
#define WIN32_NO_STATUS
|
|
#include "windef.h"
|
|
#include "winbase.h"
|
|
#include "winnt.h"
|
|
#include "winternl.h"
|
|
#include "wine/exception.h"
|
|
#include "wine/unixlib.h"
|
|
#include "wow64_private.h"
|
|
#include "wine/debug.h"
|
|
|
|
WINE_DEFAULT_DEBUG_CHANNEL(wow);
|
|
|
|
USHORT native_machine = 0;
|
|
USHORT current_machine = 0;
|
|
ULONG_PTR args_alignment = 0;
|
|
|
|
typedef NTSTATUS (WINAPI *syscall_thunk)( UINT *args );
|
|
|
|
static const syscall_thunk syscall_thunks[] =
|
|
{
|
|
#define SYSCALL_ENTRY(func) wow64_ ## func,
|
|
ALL_SYSCALLS
|
|
#undef SYSCALL_ENTRY
|
|
};
|
|
|
|
static const char *syscall_names[] =
|
|
{
|
|
#define SYSCALL_ENTRY(func) #func,
|
|
ALL_SYSCALLS
|
|
#undef SYSCALL_ENTRY
|
|
};
|
|
|
|
static const SYSTEM_SERVICE_TABLE ntdll_syscall_table =
|
|
{
|
|
(ULONG_PTR *)syscall_thunks,
|
|
(ULONG_PTR *)syscall_names,
|
|
ARRAY_SIZE(syscall_thunks)
|
|
};
|
|
|
|
static SYSTEM_SERVICE_TABLE syscall_tables[4];
|
|
|
|
/* header for Wow64AllocTemp blocks; probably not the right layout */
|
|
struct mem_header
|
|
{
|
|
struct mem_header *next;
|
|
void *__pad;
|
|
BYTE data[1];
|
|
};
|
|
|
|
SYSTEM_DLL_INIT_BLOCK *pLdrSystemDllInitBlock = NULL;
|
|
|
|
/* wow64win syscall table */
|
|
static const SYSTEM_SERVICE_TABLE *psdwhwin32;
|
|
|
|
/* cpu backend dll functions */
|
|
static void * (WINAPI *pBTCpuGetBopCode)(void);
|
|
static void (WINAPI *pBTCpuProcessInit)(void);
|
|
static void (WINAPI *pBTCpuSimulate)(void);
|
|
|
|
|
|
void *dummy = RtlUnwind;
|
|
|
|
BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, void *reserved )
|
|
{
|
|
if (reason == DLL_PROCESS_ATTACH) LdrDisableThreadCalloutsForDll( inst );
|
|
return TRUE;
|
|
}
|
|
|
|
void __cdecl __wine_spec_unimplemented_stub( const char *module, const char *function )
|
|
{
|
|
EXCEPTION_RECORD record;
|
|
|
|
record.ExceptionCode = EXCEPTION_WINE_STUB;
|
|
record.ExceptionFlags = EH_NONCONTINUABLE;
|
|
record.ExceptionRecord = NULL;
|
|
record.ExceptionAddress = __wine_spec_unimplemented_stub;
|
|
record.NumberParameters = 2;
|
|
record.ExceptionInformation[0] = (ULONG_PTR)module;
|
|
record.ExceptionInformation[1] = (ULONG_PTR)function;
|
|
for (;;) RtlRaiseException( &record );
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* wow64_NtAddAtom
|
|
*/
|
|
NTSTATUS WINAPI wow64_NtAddAtom( UINT *args )
|
|
{
|
|
const WCHAR *name = get_ptr( &args );
|
|
ULONG len = get_ulong( &args );
|
|
RTL_ATOM *atom = get_ptr( &args );
|
|
|
|
return NtAddAtom( name, len, atom );
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* wow64_NtAllocateLocallyUniqueId
|
|
*/
|
|
NTSTATUS WINAPI wow64_NtAllocateLocallyUniqueId( UINT *args )
|
|
{
|
|
LUID *luid = get_ptr( &args );
|
|
|
|
return NtAllocateLocallyUniqueId( luid );
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* wow64_NtAllocateUuids
|
|
*/
|
|
NTSTATUS WINAPI wow64_NtAllocateUuids( UINT *args )
|
|
{
|
|
ULARGE_INTEGER *time = get_ptr( &args );
|
|
ULONG *delta = get_ptr( &args );
|
|
ULONG *sequence = get_ptr( &args );
|
|
UCHAR *seed = get_ptr( &args );
|
|
|
|
return NtAllocateUuids( time, delta, sequence, seed );
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* wow64_NtClose
|
|
*/
|
|
NTSTATUS WINAPI wow64_NtClose( UINT *args )
|
|
{
|
|
HANDLE handle = get_handle( &args );
|
|
|
|
return NtClose( handle );
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* wow64_NtDeleteAtom
|
|
*/
|
|
NTSTATUS WINAPI wow64_NtDeleteAtom( UINT *args )
|
|
{
|
|
RTL_ATOM atom = get_ulong( &args );
|
|
|
|
return NtDeleteAtom( atom );
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* wow64_NtFindAtom
|
|
*/
|
|
NTSTATUS WINAPI wow64_NtFindAtom( UINT *args )
|
|
{
|
|
const WCHAR *name = get_ptr( &args );
|
|
ULONG len = get_ulong( &args );
|
|
RTL_ATOM *atom = get_ptr( &args );
|
|
|
|
return NtFindAtom( name, len, atom );
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* wow64_NtGetCurrentProcessorNumber
|
|
*/
|
|
NTSTATUS WINAPI wow64_NtGetCurrentProcessorNumber( UINT *args )
|
|
{
|
|
return NtGetCurrentProcessorNumber();
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* wow64_NtQueryDefaultLocale
|
|
*/
|
|
NTSTATUS WINAPI wow64_NtQueryDefaultLocale( UINT *args )
|
|
{
|
|
BOOLEAN user = get_ulong( &args );
|
|
LCID *lcid = get_ptr( &args );
|
|
|
|
return NtQueryDefaultLocale( user, lcid );
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* wow64_NtQueryDefaultUILanguage
|
|
*/
|
|
NTSTATUS WINAPI wow64_NtQueryDefaultUILanguage( UINT *args )
|
|
{
|
|
LANGID *lang = get_ptr( &args );
|
|
|
|
return NtQueryDefaultUILanguage( lang );
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* wow64_NtQueryInformationAtom
|
|
*/
|
|
NTSTATUS WINAPI wow64_NtQueryInformationAtom( UINT *args )
|
|
{
|
|
RTL_ATOM atom = get_ulong( &args );
|
|
ATOM_INFORMATION_CLASS class = get_ulong( &args );
|
|
void *info = get_ptr( &args );
|
|
ULONG len = get_ulong( &args );
|
|
ULONG *retlen = get_ptr( &args );
|
|
|
|
if (class != AtomBasicInformation) FIXME( "class %u not supported\n", class );
|
|
return NtQueryInformationAtom( atom, class, info, len, retlen );
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* wow64_NtQueryInstallUILanguage
|
|
*/
|
|
NTSTATUS WINAPI wow64_NtQueryInstallUILanguage( UINT *args )
|
|
{
|
|
LANGID *lang = get_ptr( &args );
|
|
|
|
return NtQueryInstallUILanguage( lang );
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* wow64_NtSetDefaultLocale
|
|
*/
|
|
NTSTATUS WINAPI wow64_NtSetDefaultLocale( UINT *args )
|
|
{
|
|
BOOLEAN user = get_ulong( &args );
|
|
LCID lcid = get_ulong( &args );
|
|
|
|
return NtSetDefaultLocale( user, lcid );
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* wow64_NtSetDefaultUILanguage
|
|
*/
|
|
NTSTATUS WINAPI wow64_NtSetDefaultUILanguage( UINT *args )
|
|
{
|
|
LANGID lang = get_ulong( &args );
|
|
|
|
return NtSetDefaultUILanguage( lang );
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* wow64___wine_dbg_write
|
|
*/
|
|
NTSTATUS WINAPI wow64___wine_dbg_write( UINT *args )
|
|
{
|
|
const char *str = get_ptr( &args );
|
|
ULONG len = get_ulong( &args );
|
|
|
|
return __wine_dbg_write( str, len );
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* wow64___wine_unix_call
|
|
*/
|
|
NTSTATUS WINAPI wow64___wine_unix_call( UINT *args )
|
|
{
|
|
unixlib_handle_t handle = get_ulong64( &args );
|
|
unsigned int code = get_ulong( &args );
|
|
void *args_ptr = get_ptr( &args );
|
|
|
|
return __wine_unix_call( handle, code, args_ptr );
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* wow64_wine_server_call
|
|
*/
|
|
NTSTATUS WINAPI wow64_wine_server_call( UINT *args )
|
|
{
|
|
struct __server_request_info32 *req32 = get_ptr( &args );
|
|
|
|
unsigned int i;
|
|
NTSTATUS status;
|
|
struct __server_request_info req;
|
|
|
|
req.u.req = req32->u.req;
|
|
req.data_count = req32->data_count;
|
|
for (i = 0; i < req.data_count; i++)
|
|
{
|
|
req.data[i].ptr = ULongToPtr( req32->data[i].ptr );
|
|
req.data[i].size = req32->data[i].size;
|
|
}
|
|
req.reply_data = ULongToPtr( req32->reply_data );
|
|
status = wine_server_call( &req );
|
|
req32->u.reply = req.u.reply;
|
|
return status;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* get_syscall_num
|
|
*/
|
|
static DWORD get_syscall_num( const BYTE *syscall )
|
|
{
|
|
DWORD id = ~0u;
|
|
|
|
if (!syscall) return id;
|
|
switch (current_machine)
|
|
{
|
|
case IMAGE_FILE_MACHINE_I386:
|
|
if (syscall[0] == 0xb8 && syscall[5] == 0xba && syscall[10] == 0xff && syscall[11] == 0xd2)
|
|
id = *(DWORD *)(syscall + 1);
|
|
break;
|
|
|
|
case IMAGE_FILE_MACHINE_ARM:
|
|
if (*(WORD *)syscall == 0xb40f)
|
|
{
|
|
DWORD inst = *(DWORD *)((WORD *)syscall + 1);
|
|
id = ((inst << 1) & 0x0800) + ((inst << 12) & 0xf000) +
|
|
((inst >> 20) & 0x0700) + ((inst >> 16) & 0x00ff);
|
|
}
|
|
break;
|
|
}
|
|
return id;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* init_image_mapping
|
|
*/
|
|
void init_image_mapping( HMODULE module )
|
|
{
|
|
void **ptr = RtlFindExportedRoutineByName( module, "Wow64Transition" );
|
|
|
|
if (ptr) *ptr = pBTCpuGetBopCode();
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* init_syscall_table
|
|
*/
|
|
static void init_syscall_table( HMODULE module, ULONG idx, const SYSTEM_SERVICE_TABLE *orig_table )
|
|
{
|
|
static syscall_thunk thunks[2048];
|
|
static ULONG start_pos;
|
|
|
|
const IMAGE_EXPORT_DIRECTORY *exports;
|
|
const ULONG *functions, *names;
|
|
const USHORT *ordinals;
|
|
ULONG id, exp_size, exp_pos, wrap_pos, max_pos = 0;
|
|
const char **syscall_names = (const char **)orig_table->CounterTable;
|
|
|
|
exports = RtlImageDirectoryEntryToData( module, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size );
|
|
ordinals = get_rva( module, exports->AddressOfNameOrdinals );
|
|
functions = get_rva( module, exports->AddressOfFunctions );
|
|
names = get_rva( module, exports->AddressOfNames );
|
|
|
|
for (exp_pos = wrap_pos = 0; exp_pos < exports->NumberOfNames; exp_pos++)
|
|
{
|
|
char *name = get_rva( module, names[exp_pos] );
|
|
int res = -1;
|
|
|
|
if (strncmp( name, "Nt", 2 ) && strncmp( name, "wine", 4 ) && strncmp( name, "__wine", 6 ))
|
|
continue; /* not a syscall */
|
|
|
|
if ((id = get_syscall_num( get_rva( module, functions[ordinals[exp_pos]] ))) == ~0u)
|
|
continue; /* not a syscall */
|
|
|
|
if (wrap_pos < orig_table->ServiceLimit) res = strcmp( name, syscall_names[wrap_pos] );
|
|
|
|
if (!res) /* got a match */
|
|
{
|
|
ULONG table_idx = (id >> 12) & 3, table_pos = id & 0xfff;
|
|
if (table_idx == idx)
|
|
{
|
|
if (start_pos + table_pos < ARRAY_SIZE(thunks))
|
|
{
|
|
thunks[start_pos + table_pos] = (syscall_thunk)orig_table->ServiceTable[wrap_pos++];
|
|
max_pos = max( table_pos, max_pos );
|
|
}
|
|
else ERR( "invalid syscall id %04x for %s\n", id, name );
|
|
}
|
|
else ERR( "wrong syscall table id %04x for %s\n", id, name );
|
|
}
|
|
else if (res > 0)
|
|
{
|
|
FIXME( "no export for syscall %s\n", syscall_names[wrap_pos] );
|
|
wrap_pos++;
|
|
exp_pos--; /* try again */
|
|
}
|
|
else FIXME( "missing wrapper for syscall %04x %s\n", id, name );
|
|
}
|
|
|
|
for ( ; wrap_pos < orig_table->ServiceLimit; wrap_pos++)
|
|
FIXME( "no export for syscall %s\n", syscall_names[wrap_pos] );
|
|
|
|
syscall_tables[idx].ServiceTable = (ULONG_PTR *)(thunks + start_pos);
|
|
syscall_tables[idx].ServiceLimit = max_pos + 1;
|
|
start_pos += max_pos + 1;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* load_64bit_module
|
|
*/
|
|
static HMODULE load_64bit_module( const WCHAR *name )
|
|
{
|
|
NTSTATUS status;
|
|
HMODULE module;
|
|
UNICODE_STRING str;
|
|
WCHAR path[MAX_PATH];
|
|
const WCHAR *dir = get_machine_wow64_dir( IMAGE_FILE_MACHINE_TARGET_HOST );
|
|
|
|
swprintf( path, MAX_PATH, L"%s\\%s", dir, name );
|
|
RtlInitUnicodeString( &str, path );
|
|
if ((status = LdrLoadDll( NULL, 0, &str, &module )))
|
|
{
|
|
ERR( "failed to load dll %x\n", status );
|
|
NtTerminateProcess( GetCurrentProcess(), status );
|
|
}
|
|
return module;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* load_32bit_module
|
|
*/
|
|
static HMODULE load_32bit_module( const WCHAR *name )
|
|
{
|
|
NTSTATUS status;
|
|
UNICODE_STRING str;
|
|
WCHAR path[MAX_PATH];
|
|
HANDLE file, mapping;
|
|
LARGE_INTEGER size;
|
|
IO_STATUS_BLOCK io;
|
|
OBJECT_ATTRIBUTES attr;
|
|
SIZE_T len = 0;
|
|
void *module = NULL;
|
|
const WCHAR *dir = get_machine_wow64_dir( current_machine );
|
|
|
|
swprintf( path, MAX_PATH, L"%s\\%s", dir, name );
|
|
RtlInitUnicodeString( &str, path );
|
|
InitializeObjectAttributes( &attr, &str, OBJ_CASE_INSENSITIVE, 0, NULL );
|
|
if ((status = NtOpenFile( &file, GENERIC_READ | SYNCHRONIZE, &attr, &io,
|
|
FILE_SHARE_READ | FILE_SHARE_DELETE,
|
|
FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE ))) goto failed;
|
|
|
|
size.QuadPart = 0;
|
|
status = NtCreateSection( &mapping, STANDARD_RIGHTS_REQUIRED | SECTION_QUERY |
|
|
SECTION_MAP_READ | SECTION_MAP_EXECUTE,
|
|
NULL, &size, PAGE_EXECUTE_READ, SEC_IMAGE, file );
|
|
NtClose( file );
|
|
if (status) goto failed;
|
|
|
|
status = NtMapViewOfSection( mapping, GetCurrentProcess(), &module, 0, 0, NULL, &len,
|
|
ViewShare, 0, PAGE_EXECUTE_READ );
|
|
NtClose( mapping );
|
|
if (!status) return module;
|
|
|
|
failed:
|
|
ERR( "failed to load dll %x\n", status );
|
|
NtTerminateProcess( GetCurrentProcess(), status );
|
|
return NULL;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* get_cpu_dll_name
|
|
*/
|
|
static const WCHAR *get_cpu_dll_name(void)
|
|
{
|
|
switch (current_machine)
|
|
{
|
|
case IMAGE_FILE_MACHINE_I386:
|
|
return (native_machine == IMAGE_FILE_MACHINE_ARM64 ? L"xtajit.dll" : L"wow64cpu.dll");
|
|
case IMAGE_FILE_MACHINE_ARM:
|
|
return L"wowarmhw.dll";
|
|
default:
|
|
ERR( "unsupported machine %04x\n", current_machine );
|
|
RtlExitUserProcess( 1 );
|
|
}
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* process_init
|
|
*/
|
|
static DWORD WINAPI process_init( RTL_RUN_ONCE *once, void *param, void **context )
|
|
{
|
|
HMODULE module;
|
|
UNICODE_STRING str;
|
|
|
|
RtlWow64GetProcessMachines( GetCurrentProcess(), ¤t_machine, &native_machine );
|
|
if (!current_machine) current_machine = native_machine;
|
|
args_alignment = (current_machine == IMAGE_FILE_MACHINE_I386) ? sizeof(ULONG) : sizeof(ULONG64);
|
|
|
|
#define GET_PTR(name) p ## name = RtlFindExportedRoutineByName( module, #name )
|
|
|
|
RtlInitUnicodeString( &str, L"ntdll.dll" );
|
|
LdrGetDllHandle( NULL, 0, &str, &module );
|
|
GET_PTR( LdrSystemDllInitBlock );
|
|
|
|
module = load_64bit_module( get_cpu_dll_name() );
|
|
GET_PTR( BTCpuGetBopCode );
|
|
GET_PTR( BTCpuProcessInit );
|
|
GET_PTR( BTCpuSimulate );
|
|
|
|
module = load_64bit_module( L"wow64win.dll" );
|
|
GET_PTR( sdwhwin32 );
|
|
|
|
pBTCpuProcessInit();
|
|
|
|
module = (HMODULE)(ULONG_PTR)pLdrSystemDllInitBlock->ntdll_handle;
|
|
init_image_mapping( module );
|
|
init_syscall_table( module, 0, &ntdll_syscall_table );
|
|
*(void **)RtlFindExportedRoutineByName( module, "__wine_syscall_dispatcher" ) = pBTCpuGetBopCode();
|
|
|
|
module = load_32bit_module( L"win32u.dll" );
|
|
init_syscall_table( module, 1, psdwhwin32 );
|
|
NtUnmapViewOfSection( GetCurrentProcess(), module );
|
|
|
|
init_file_redirects();
|
|
return TRUE;
|
|
|
|
#undef GET_PTR
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* thread_init
|
|
*/
|
|
static void thread_init(void)
|
|
{
|
|
/* update initial context to jump to 32-bit LdrInitializeThunk (cf. 32-bit call_init_thunk) */
|
|
switch (current_machine)
|
|
{
|
|
case IMAGE_FILE_MACHINE_I386:
|
|
{
|
|
I386_CONTEXT *ctx_ptr, ctx = { CONTEXT_I386_ALL };
|
|
ULONG *stack;
|
|
|
|
NtQueryInformationThread( GetCurrentThread(), ThreadWow64Context, &ctx, sizeof(ctx), NULL );
|
|
ctx_ptr = (I386_CONTEXT *)ULongToPtr( ctx.Esp ) - 1;
|
|
*ctx_ptr = ctx;
|
|
|
|
stack = (ULONG *)ctx_ptr;
|
|
*(--stack) = 0;
|
|
*(--stack) = 0;
|
|
*(--stack) = 0;
|
|
*(--stack) = PtrToUlong( ctx_ptr );
|
|
*(--stack) = 0xdeadbabe;
|
|
ctx.Esp = PtrToUlong( stack );
|
|
ctx.Eip = pLdrSystemDllInitBlock->pLdrInitializeThunk;
|
|
NtSetInformationThread( GetCurrentThread(), ThreadWow64Context, &ctx, sizeof(ctx) );
|
|
}
|
|
break;
|
|
|
|
case IMAGE_FILE_MACHINE_ARMNT:
|
|
{
|
|
ARM_CONTEXT *ctx_ptr, ctx = { CONTEXT_ARM_ALL };
|
|
|
|
NtQueryInformationThread( GetCurrentThread(), ThreadWow64Context, &ctx, sizeof(ctx), NULL );
|
|
ctx_ptr = (ARM_CONTEXT *)ULongToPtr( ctx.Sp & ~15 ) - 1;
|
|
*ctx_ptr = ctx;
|
|
|
|
ctx.R0 = PtrToUlong( ctx_ptr );
|
|
ctx.Sp = PtrToUlong( ctx_ptr );
|
|
ctx.Pc = pLdrSystemDllInitBlock->pLdrInitializeThunk;
|
|
NtSetInformationThread( GetCurrentThread(), ThreadWow64Context, &ctx, sizeof(ctx) );
|
|
}
|
|
break;
|
|
|
|
default:
|
|
ERR( "not supported machine %x\n", current_machine );
|
|
NtTerminateProcess( GetCurrentProcess(), STATUS_INVALID_IMAGE_FORMAT );
|
|
}
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* free_temp_data
|
|
*/
|
|
static void free_temp_data(void)
|
|
{
|
|
struct mem_header *next, *mem;
|
|
|
|
for (mem = NtCurrentTeb()->TlsSlots[WOW64_TLS_TEMPLIST]; mem; mem = next)
|
|
{
|
|
next = mem->next;
|
|
RtlFreeHeap( GetProcessHeap(), 0, mem );
|
|
}
|
|
NtCurrentTeb()->TlsSlots[WOW64_TLS_TEMPLIST] = NULL;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* syscall_filter
|
|
*/
|
|
static LONG CALLBACK syscall_filter( EXCEPTION_POINTERS *ptrs )
|
|
{
|
|
switch (ptrs->ExceptionRecord->ExceptionCode)
|
|
{
|
|
case STATUS_INVALID_HANDLE:
|
|
Wow64PassExceptionToGuest( ptrs );
|
|
break;
|
|
}
|
|
return EXCEPTION_EXECUTE_HANDLER;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* Wow64SystemServiceEx (wow64.@)
|
|
*/
|
|
NTSTATUS WINAPI Wow64SystemServiceEx( UINT num, UINT *args )
|
|
{
|
|
NTSTATUS status;
|
|
UINT id = num & 0xfff;
|
|
const SYSTEM_SERVICE_TABLE *table = &syscall_tables[(num >> 12) & 3];
|
|
|
|
if (id >= table->ServiceLimit || !table->ServiceTable[id])
|
|
{
|
|
ERR( "unsupported syscall %04x\n", num );
|
|
return STATUS_INVALID_SYSTEM_SERVICE;
|
|
}
|
|
__TRY
|
|
{
|
|
syscall_thunk thunk = (syscall_thunk)table->ServiceTable[id];
|
|
status = thunk( args );
|
|
}
|
|
__EXCEPT( syscall_filter )
|
|
{
|
|
status = GetExceptionCode();
|
|
}
|
|
__ENDTRY;
|
|
free_temp_data();
|
|
return status;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* Wow64AllocateTemp (wow64.@)
|
|
*
|
|
* FIXME: probably not 100% compatible.
|
|
*/
|
|
void * WINAPI Wow64AllocateTemp( SIZE_T size )
|
|
{
|
|
struct mem_header *mem;
|
|
|
|
if (!(mem = RtlAllocateHeap( GetProcessHeap(), 0, offsetof( struct mem_header, data[size] ))))
|
|
return NULL;
|
|
mem->next = NtCurrentTeb()->TlsSlots[WOW64_TLS_TEMPLIST];
|
|
NtCurrentTeb()->TlsSlots[WOW64_TLS_TEMPLIST] = mem;
|
|
return mem->data;
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* Wow64ApcRoutine (wow64.@)
|
|
*/
|
|
void WINAPI Wow64ApcRoutine( ULONG_PTR arg1, ULONG_PTR arg2, ULONG_PTR arg3, CONTEXT *context )
|
|
{
|
|
NTSTATUS retval;
|
|
|
|
#ifdef __x86_64__
|
|
retval = context->Rax;
|
|
#elif defined(__aarch64__)
|
|
retval = context->X0;
|
|
#endif
|
|
|
|
/* cf. 32-bit call_user_apc_dispatcher */
|
|
switch (current_machine)
|
|
{
|
|
case IMAGE_FILE_MACHINE_I386:
|
|
{
|
|
struct apc_stack_layout
|
|
{
|
|
ULONG ret;
|
|
ULONG context_ptr;
|
|
ULONG arg1;
|
|
ULONG arg2;
|
|
ULONG arg3;
|
|
ULONG func;
|
|
I386_CONTEXT context;
|
|
} *stack;
|
|
I386_CONTEXT ctx = { CONTEXT_I386_FULL };
|
|
|
|
NtQueryInformationThread( GetCurrentThread(), ThreadWow64Context, &ctx, sizeof(ctx), NULL );
|
|
stack = (struct apc_stack_layout *)ULongToPtr( ctx.Esp & ~3 ) - 1;
|
|
stack->context_ptr = PtrToUlong( &stack->context );
|
|
stack->func = arg1 >> 32;
|
|
stack->arg1 = arg1;
|
|
stack->arg2 = arg2;
|
|
stack->arg3 = arg3;
|
|
stack->context = ctx;
|
|
stack->context.Eax = retval;
|
|
ctx.Esp = PtrToUlong( stack );
|
|
ctx.Eip = pLdrSystemDllInitBlock->pKiUserApcDispatcher;
|
|
NtSetInformationThread( GetCurrentThread(), ThreadWow64Context, &ctx, sizeof(ctx) );
|
|
}
|
|
break;
|
|
|
|
case IMAGE_FILE_MACHINE_ARMNT:
|
|
{
|
|
struct apc_stack_layout
|
|
{
|
|
ULONG func;
|
|
ULONG align[3];
|
|
ARM_CONTEXT context;
|
|
} *stack;
|
|
ARM_CONTEXT ctx = { CONTEXT_ARM_FULL };
|
|
|
|
NtQueryInformationThread( GetCurrentThread(), ThreadWow64Context, &ctx, sizeof(ctx), NULL );
|
|
stack = (struct apc_stack_layout *)ULongToPtr( ctx.Sp & ~15 ) - 1;
|
|
stack->func = arg1 >> 32;
|
|
stack->context = ctx;
|
|
stack->context.R0 = retval;
|
|
ctx.Sp = PtrToUlong( stack );
|
|
ctx.Pc = pLdrSystemDllInitBlock->pKiUserApcDispatcher;
|
|
ctx.R0 = PtrToUlong( &stack->context );
|
|
ctx.R1 = arg1;
|
|
ctx.R2 = arg2;
|
|
ctx.R3 = arg3;
|
|
NtSetInformationThread( GetCurrentThread(), ThreadWow64Context, &ctx, sizeof(ctx) );
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
/**********************************************************************
|
|
* Wow64LdrpInitialize (wow64.@)
|
|
*/
|
|
void WINAPI Wow64LdrpInitialize( CONTEXT *context )
|
|
{
|
|
static RTL_RUN_ONCE init_done;
|
|
|
|
RtlRunOnceExecuteOnce( &init_done, process_init, NULL, NULL );
|
|
thread_init();
|
|
pBTCpuSimulate();
|
|
}
|