wow64: Add thunks for a few simple syscalls.
[wine.git] / dlls / wow64 / syscall.c
blob10abe7a8b38eab6ca6a18902414a3c4cd0b81e45
1 /*
2 * WoW64 syscall wrapping
4 * Copyright 2021 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <stdarg.h>
23 #include "ntstatus.h"
24 #define WIN32_NO_STATUS
25 #include "windef.h"
26 #include "winbase.h"
27 #include "winnt.h"
28 #include "winternl.h"
29 #include "wine/exception.h"
30 #include "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,
43 ALL_SYSCALLS
44 #undef SYSCALL_ENTRY
47 static const char *syscall_names[] =
49 #define SYSCALL_ENTRY(func) #func,
50 ALL_SYSCALLS
51 #undef SYSCALL_ENTRY
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 );
63 return TRUE;
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 /**********************************************************************
107 * wow64_NtClose
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 /**********************************************************************
184 * get_syscall_num
186 static DWORD get_syscall_num( const BYTE *syscall )
188 DWORD id = ~0u;
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);
196 break;
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);
205 break;
207 return id;
211 /**********************************************************************
212 * init_syscall_table
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] );
229 int res = -1;
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 );
245 else if (res > 0)
247 FIXME( "no ntdll export for syscall %s\n", syscall_names[wrap_pos] );
248 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 /**********************************************************************
260 * load_cpu_dll
262 static HMODULE load_cpu_dll(void)
264 NTSTATUS status;
265 HMODULE module;
266 UNICODE_STRING str;
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");
274 break;
275 case IMAGE_FILE_MACHINE_ARM:
276 name = L"wowarmhw.dll";
277 break;
278 default:
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 );
292 return module;
296 /**********************************************************************
297 * process_init
299 static void process_init(void)
301 HMODULE module;
302 UNICODE_STRING str;
304 RtlWow64GetProcessMachines( GetCurrentProcess(), &current_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 );
316 load_cpu_dll();
318 #undef GET_PTR
322 /**********************************************************************
323 * Wow64SystemServiceEx (NTDLL.@)
325 NTSTATUS WINAPI Wow64SystemServiceEx( UINT num, UINT *args )
327 NTSTATUS status;
329 if (num >= ARRAY_SIZE( syscall_map ) || !syscall_map[num])
331 ERR( "unsupported syscall %04x\n", num );
332 return STATUS_INVALID_SYSTEM_SERVICE;
334 __TRY
336 syscall_thunk thunk = syscall_thunks[syscall_map[num]];
337 status = thunk( args );
339 __EXCEPT_ALL
341 status = GetExceptionCode();
343 __ENDTRY;
344 return status;
348 /**********************************************************************
349 * Wow64LdrpInitialize (NTDLL.@)
351 void WINAPI Wow64LdrpInitialize( CONTEXT *context )
353 static BOOL init_done;
355 if (!init_done)
357 init_done = TRUE;
358 process_init();