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
24 #define WIN32_NO_STATUS
29 #include "wine/exception.h"
30 #include "wow64_private.h"
31 #include "wine/debug.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(wow
);
35 USHORT native_machine
= 0;
36 USHORT current_machine
= 0;
38 typedef NTSTATUS (WINAPI
*syscall_thunk
)( UINT
*args
);
40 static const syscall_thunk syscall_thunks
[] =
42 #define SYSCALL_ENTRY(func) wow64_ ## func,
47 static const char *syscall_names
[] =
49 #define SYSCALL_ENTRY(func) #func,
54 static unsigned short syscall_map
[1024];
56 static SYSTEM_DLL_INIT_BLOCK
*pLdrSystemDllInitBlock
;
58 void *dummy
= RtlUnwind
;
60 BOOL WINAPI
DllMain( HINSTANCE inst
, DWORD reason
, void *reserved
)
62 if (reason
== DLL_PROCESS_ATTACH
) LdrDisableThreadCalloutsForDll( inst
);
66 void __cdecl
__wine_spec_unimplemented_stub( const char *module
, const char *function
)
68 EXCEPTION_RECORD record
;
70 record
.ExceptionCode
= EXCEPTION_WINE_STUB
;
71 record
.ExceptionFlags
= EH_NONCONTINUABLE
;
72 record
.ExceptionRecord
= NULL
;
73 record
.ExceptionAddress
= __wine_spec_unimplemented_stub
;
74 record
.NumberParameters
= 2;
75 record
.ExceptionInformation
[0] = (ULONG_PTR
)module
;
76 record
.ExceptionInformation
[1] = (ULONG_PTR
)function
;
77 for (;;) RtlRaiseException( &record
);
81 /**********************************************************************
82 * wow64_NtAllocateLocallyUniqueId
84 NTSTATUS WINAPI
wow64_NtAllocateLocallyUniqueId( UINT
*args
)
86 LUID
*luid
= get_ptr( &args
);
88 return NtAllocateLocallyUniqueId( luid
);
92 /**********************************************************************
93 * wow64_NtAllocateUuids
95 NTSTATUS WINAPI
wow64_NtAllocateUuids( UINT
*args
)
97 ULARGE_INTEGER
*time
= get_ptr( &args
);
98 ULONG
*delta
= get_ptr( &args
);
99 ULONG
*sequence
= get_ptr( &args
);
100 UCHAR
*seed
= get_ptr( &args
);
102 return NtAllocateUuids( time
, delta
, sequence
, seed
);
106 /**********************************************************************
109 NTSTATUS WINAPI
wow64_NtClose( UINT
*args
)
111 HANDLE handle
= get_handle( &args
);
113 return NtClose( handle
);
117 /**********************************************************************
118 * wow64_NtGetCurrentProcessorNumber
120 NTSTATUS WINAPI
wow64_NtGetCurrentProcessorNumber( UINT
*args
)
122 return NtGetCurrentProcessorNumber();
126 /**********************************************************************
127 * wow64_NtQueryDefaultLocale
129 NTSTATUS WINAPI
wow64_NtQueryDefaultLocale( UINT
*args
)
131 BOOLEAN user
= get_ulong( &args
);
132 LCID
*lcid
= get_ptr( &args
);
134 return NtQueryDefaultLocale( user
, lcid
);
138 /**********************************************************************
139 * wow64_NtQueryDefaultUILanguage
141 NTSTATUS WINAPI
wow64_NtQueryDefaultUILanguage( UINT
*args
)
143 LANGID
*lang
= get_ptr( &args
);
145 return NtQueryDefaultUILanguage( lang
);
149 /**********************************************************************
150 * wow64_NtQueryInstallUILanguage
152 NTSTATUS WINAPI
wow64_NtQueryInstallUILanguage( UINT
*args
)
154 LANGID
*lang
= get_ptr( &args
);
156 return NtQueryInstallUILanguage( lang
);
160 /**********************************************************************
161 * wow64_NtSetDefaultLocale
163 NTSTATUS WINAPI
wow64_NtSetDefaultLocale( UINT
*args
)
165 BOOLEAN user
= get_ulong( &args
);
166 LCID lcid
= get_ulong( &args
);
168 return NtSetDefaultLocale( user
, lcid
);
172 /**********************************************************************
173 * wow64_NtSetDefaultUILanguage
175 NTSTATUS WINAPI
wow64_NtSetDefaultUILanguage( UINT
*args
)
177 LANGID lang
= get_ulong( &args
);
179 return NtSetDefaultUILanguage( lang
);
183 /**********************************************************************
186 static DWORD
get_syscall_num( const BYTE
*syscall
)
190 if (!syscall
) return id
;
191 switch (current_machine
)
193 case IMAGE_FILE_MACHINE_I386
:
194 if (syscall
[0] == 0xb8 && syscall
[5] == 0xba && syscall
[10] == 0xff && syscall
[11] == 0xd2)
195 id
= *(DWORD
*)(syscall
+ 1);
198 case IMAGE_FILE_MACHINE_ARM
:
199 if (*(WORD
*)syscall
== 0xb40f)
201 DWORD inst
= *(DWORD
*)((WORD
*)syscall
+ 1);
202 id
= ((inst
<< 1) & 0x0800) + ((inst
<< 12) & 0xf000) +
203 ((inst
>> 20) & 0x0700) + ((inst
>> 16) & 0x00ff);
211 /**********************************************************************
214 static void init_syscall_table( HMODULE ntdll
)
216 const IMAGE_EXPORT_DIRECTORY
*exports
;
217 const ULONG
*functions
, *names
;
218 const USHORT
*ordinals
;
219 ULONG id
, exp_size
, exp_pos
, wrap_pos
;
221 exports
= RtlImageDirectoryEntryToData( ntdll
, TRUE
, IMAGE_DIRECTORY_ENTRY_EXPORT
, &exp_size
);
222 ordinals
= get_rva( ntdll
, exports
->AddressOfNameOrdinals
);
223 functions
= get_rva( ntdll
, exports
->AddressOfFunctions
);
224 names
= get_rva( ntdll
, exports
->AddressOfNames
);
226 for (exp_pos
= wrap_pos
= 0; exp_pos
< exports
->NumberOfNames
; exp_pos
++)
228 char *name
= get_rva( ntdll
, names
[exp_pos
] );
231 if (strncmp( name
, "Nt", 2 ) && strncmp( name
, "wine", 4 ) && strncmp( name
, "__wine", 6 ))
232 continue; /* not a syscall */
234 if ((id
= get_syscall_num( get_rva( ntdll
, functions
[ordinals
[exp_pos
]] ))) == ~0u)
235 continue; /* not a syscall */
237 if (wrap_pos
< ARRAY_SIZE(syscall_names
))
238 res
= strcmp( name
, syscall_names
[wrap_pos
] );
240 if (!res
) /* got a match */
242 if (id
< ARRAY_SIZE(syscall_map
)) syscall_map
[id
] = wrap_pos
++;
243 else ERR( "invalid syscall id %04x for %s\n", id
, name
);
247 FIXME( "no ntdll export for syscall %s\n", syscall_names
[wrap_pos
] );
249 exp_pos
--; /* try again */
251 else FIXME( "missing wrapper for syscall %04x %s\n", id
, name
);
254 for ( ; wrap_pos
< ARRAY_SIZE(syscall_thunks
); wrap_pos
++)
255 FIXME( "no ntdll export for syscall %s\n", syscall_names
[wrap_pos
] );
259 /**********************************************************************
262 static HMODULE
load_cpu_dll(void)
267 WCHAR path
[MAX_PATH
];
268 const WCHAR
*dir
, *name
;
270 switch (current_machine
)
272 case IMAGE_FILE_MACHINE_I386
:
273 name
= (native_machine
== IMAGE_FILE_MACHINE_ARM64
? L
"xtajit.dll" : L
"wow64cpu.dll");
275 case IMAGE_FILE_MACHINE_ARM
:
276 name
= L
"wowarmhw.dll";
279 ERR( "unsupported machine %04x\n", current_machine
);
280 RtlExitUserProcess( 1 );
283 dir
= get_machine_wow64_dir( IMAGE_FILE_MACHINE_TARGET_HOST
);
285 swprintf( path
, MAX_PATH
, L
"%s\\%s", dir
, name
);
286 RtlInitUnicodeString( &str
, path
);
287 if ((status
= LdrLoadDll( NULL
, 0, &str
, &module
)))
289 ERR( "failed to load CPU dll %x\n", status
);
290 NtTerminateProcess( GetCurrentProcess(), status
);
296 /**********************************************************************
299 static void process_init(void)
304 RtlWow64GetProcessMachines( GetCurrentProcess(), ¤t_machine
, &native_machine
);
305 if (!current_machine
) current_machine
= native_machine
;
307 #define GET_PTR(name) p ## name = RtlFindExportedRoutineByName( module, #name )
309 RtlInitUnicodeString( &str
, L
"ntdll.dll" );
310 LdrGetDllHandle( NULL
, 0, &str
, &module
);
311 GET_PTR( LdrSystemDllInitBlock
);
313 module
= (HMODULE
)(ULONG_PTR
)pLdrSystemDllInitBlock
->ntdll_handle
;
314 init_syscall_table( module
);
322 /**********************************************************************
323 * Wow64SystemServiceEx (NTDLL.@)
325 NTSTATUS WINAPI
Wow64SystemServiceEx( UINT num
, UINT
*args
)
329 if (num
>= ARRAY_SIZE( syscall_map
) || !syscall_map
[num
])
331 ERR( "unsupported syscall %04x\n", num
);
332 return STATUS_INVALID_SYSTEM_SERVICE
;
336 syscall_thunk thunk
= syscall_thunks
[syscall_map
[num
]];
337 status
= thunk( args
);
341 status
= GetExceptionCode();
348 /**********************************************************************
349 * Wow64LdrpInitialize (NTDLL.@)
351 void WINAPI
Wow64LdrpInitialize( CONTEXT
*context
)
353 static BOOL init_done
;