include: Add a private header for Unix libraries definitions.
[wine.git] / dlls / wow64 / syscall.c
blob495c10b121a34cb0606297af75661ff650ebe61f
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 "wine/unixlib.h"
31 #include "wow64_private.h"
32 #include "wine/debug.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(wow);
36 USHORT native_machine = 0;
37 USHORT current_machine = 0;
38 ULONG_PTR args_alignment = 0;
40 typedef NTSTATUS (WINAPI *syscall_thunk)( UINT *args );
42 static const syscall_thunk syscall_thunks[] =
44 #define SYSCALL_ENTRY(func) wow64_ ## func,
45 ALL_SYSCALLS
46 #undef SYSCALL_ENTRY
49 static const char *syscall_names[] =
51 #define SYSCALL_ENTRY(func) #func,
52 ALL_SYSCALLS
53 #undef SYSCALL_ENTRY
56 static unsigned short syscall_map[1024];
58 /* header for Wow64AllocTemp blocks; probably not the right layout */
59 struct mem_header
61 struct mem_header *next;
62 void *__pad;
63 BYTE data[1];
66 static void **pWow64Transition;
67 static void **p__wine_syscall_dispatcher;
68 static SYSTEM_DLL_INIT_BLOCK *pLdrSystemDllInitBlock;
70 /* cpu backend dll functions */
71 static void * (WINAPI *pBTCpuGetBopCode)(void);
72 static void (WINAPI *pBTCpuProcessInit)(void);
73 static void (WINAPI *pBTCpuSimulate)(void);
76 void *dummy = RtlUnwind;
78 BOOL WINAPI DllMain( HINSTANCE inst, DWORD reason, void *reserved )
80 if (reason == DLL_PROCESS_ATTACH) LdrDisableThreadCalloutsForDll( inst );
81 return TRUE;
84 void __cdecl __wine_spec_unimplemented_stub( const char *module, const char *function )
86 EXCEPTION_RECORD record;
88 record.ExceptionCode = EXCEPTION_WINE_STUB;
89 record.ExceptionFlags = EH_NONCONTINUABLE;
90 record.ExceptionRecord = NULL;
91 record.ExceptionAddress = __wine_spec_unimplemented_stub;
92 record.NumberParameters = 2;
93 record.ExceptionInformation[0] = (ULONG_PTR)module;
94 record.ExceptionInformation[1] = (ULONG_PTR)function;
95 for (;;) RtlRaiseException( &record );
99 /**********************************************************************
100 * wow64_NtAddAtom
102 NTSTATUS WINAPI wow64_NtAddAtom( UINT *args )
104 const WCHAR *name = get_ptr( &args );
105 ULONG len = get_ulong( &args );
106 RTL_ATOM *atom = get_ptr( &args );
108 return NtAddAtom( name, len, atom );
112 /**********************************************************************
113 * wow64_NtAllocateLocallyUniqueId
115 NTSTATUS WINAPI wow64_NtAllocateLocallyUniqueId( UINT *args )
117 LUID *luid = get_ptr( &args );
119 return NtAllocateLocallyUniqueId( luid );
123 /**********************************************************************
124 * wow64_NtAllocateUuids
126 NTSTATUS WINAPI wow64_NtAllocateUuids( UINT *args )
128 ULARGE_INTEGER *time = get_ptr( &args );
129 ULONG *delta = get_ptr( &args );
130 ULONG *sequence = get_ptr( &args );
131 UCHAR *seed = get_ptr( &args );
133 return NtAllocateUuids( time, delta, sequence, seed );
137 /**********************************************************************
138 * wow64_NtClose
140 NTSTATUS WINAPI wow64_NtClose( UINT *args )
142 HANDLE handle = get_handle( &args );
144 return NtClose( handle );
148 /**********************************************************************
149 * wow64_NtDeleteAtom
151 NTSTATUS WINAPI wow64_NtDeleteAtom( UINT *args )
153 RTL_ATOM atom = get_ulong( &args );
155 return NtDeleteAtom( atom );
159 /**********************************************************************
160 * wow64_NtFindAtom
162 NTSTATUS WINAPI wow64_NtFindAtom( UINT *args )
164 const WCHAR *name = get_ptr( &args );
165 ULONG len = get_ulong( &args );
166 RTL_ATOM *atom = get_ptr( &args );
168 return NtFindAtom( name, len, atom );
172 /**********************************************************************
173 * wow64_NtGetCurrentProcessorNumber
175 NTSTATUS WINAPI wow64_NtGetCurrentProcessorNumber( UINT *args )
177 return NtGetCurrentProcessorNumber();
181 /**********************************************************************
182 * wow64_NtQueryDefaultLocale
184 NTSTATUS WINAPI wow64_NtQueryDefaultLocale( UINT *args )
186 BOOLEAN user = get_ulong( &args );
187 LCID *lcid = get_ptr( &args );
189 return NtQueryDefaultLocale( user, lcid );
193 /**********************************************************************
194 * wow64_NtQueryDefaultUILanguage
196 NTSTATUS WINAPI wow64_NtQueryDefaultUILanguage( UINT *args )
198 LANGID *lang = get_ptr( &args );
200 return NtQueryDefaultUILanguage( lang );
204 /**********************************************************************
205 * wow64_NtQueryInformationAtom
207 NTSTATUS WINAPI wow64_NtQueryInformationAtom( UINT *args )
209 RTL_ATOM atom = get_ulong( &args );
210 ATOM_INFORMATION_CLASS class = get_ulong( &args );
211 void *info = get_ptr( &args );
212 ULONG len = get_ulong( &args );
213 ULONG *retlen = get_ptr( &args );
215 if (class != AtomBasicInformation) FIXME( "class %u not supported\n", class );
216 return NtQueryInformationAtom( atom, class, info, len, retlen );
220 /**********************************************************************
221 * wow64_NtQueryInstallUILanguage
223 NTSTATUS WINAPI wow64_NtQueryInstallUILanguage( UINT *args )
225 LANGID *lang = get_ptr( &args );
227 return NtQueryInstallUILanguage( lang );
231 /**********************************************************************
232 * wow64_NtSetDefaultLocale
234 NTSTATUS WINAPI wow64_NtSetDefaultLocale( UINT *args )
236 BOOLEAN user = get_ulong( &args );
237 LCID lcid = get_ulong( &args );
239 return NtSetDefaultLocale( user, lcid );
243 /**********************************************************************
244 * wow64_NtSetDefaultUILanguage
246 NTSTATUS WINAPI wow64_NtSetDefaultUILanguage( UINT *args )
248 LANGID lang = get_ulong( &args );
250 return NtSetDefaultUILanguage( lang );
254 /**********************************************************************
255 * wow64___wine_dbg_write
257 NTSTATUS WINAPI wow64___wine_dbg_write( UINT *args )
259 const char *str = get_ptr( &args );
260 ULONG len = get_ulong( &args );
262 return __wine_dbg_write( str, len );
266 /**********************************************************************
267 * wow64___wine_unix_call
269 NTSTATUS WINAPI wow64___wine_unix_call( UINT *args )
271 unixlib_handle_t handle = get_ulong64( &args );
272 unsigned int code = get_ulong( &args );
273 void *args_ptr = get_ptr( &args );
275 return __wine_unix_call( handle, code, args_ptr );
279 /**********************************************************************
280 * wow64_wine_server_call
282 NTSTATUS WINAPI wow64_wine_server_call( UINT *args )
284 struct __server_request_info32 *req32 = get_ptr( &args );
286 unsigned int i;
287 NTSTATUS status;
288 struct __server_request_info req;
290 req.u.req = req32->u.req;
291 req.data_count = req32->data_count;
292 for (i = 0; i < req.data_count; i++)
294 req.data[i].ptr = ULongToPtr( req32->data[i].ptr );
295 req.data[i].size = req32->data[i].size;
297 req.reply_data = ULongToPtr( req32->reply_data );
298 status = wine_server_call( &req );
299 req32->u.reply = req.u.reply;
300 return status;
304 /**********************************************************************
305 * get_syscall_num
307 static DWORD get_syscall_num( const BYTE *syscall )
309 DWORD id = ~0u;
311 if (!syscall) return id;
312 switch (current_machine)
314 case IMAGE_FILE_MACHINE_I386:
315 if (syscall[0] == 0xb8 && syscall[5] == 0xba && syscall[10] == 0xff && syscall[11] == 0xd2)
316 id = *(DWORD *)(syscall + 1);
317 break;
319 case IMAGE_FILE_MACHINE_ARM:
320 if (*(WORD *)syscall == 0xb40f)
322 DWORD inst = *(DWORD *)((WORD *)syscall + 1);
323 id = ((inst << 1) & 0x0800) + ((inst << 12) & 0xf000) +
324 ((inst >> 20) & 0x0700) + ((inst >> 16) & 0x00ff);
326 break;
328 return id;
332 /**********************************************************************
333 * init_syscall_table
335 static void init_syscall_table( HMODULE ntdll )
337 const IMAGE_EXPORT_DIRECTORY *exports;
338 const ULONG *functions, *names;
339 const USHORT *ordinals;
340 ULONG id, exp_size, exp_pos, wrap_pos;
342 args_alignment = (current_machine == IMAGE_FILE_MACHINE_I386) ? sizeof(ULONG) : sizeof(ULONG64);
344 exports = RtlImageDirectoryEntryToData( ntdll, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &exp_size );
345 ordinals = get_rva( ntdll, exports->AddressOfNameOrdinals );
346 functions = get_rva( ntdll, exports->AddressOfFunctions );
347 names = get_rva( ntdll, exports->AddressOfNames );
349 for (exp_pos = wrap_pos = 0; exp_pos < exports->NumberOfNames; exp_pos++)
351 char *name = get_rva( ntdll, names[exp_pos] );
352 int res = -1;
354 if (strncmp( name, "Nt", 2 ) && strncmp( name, "wine", 4 ) && strncmp( name, "__wine", 6 ))
355 continue; /* not a syscall */
357 if ((id = get_syscall_num( get_rva( ntdll, functions[ordinals[exp_pos]] ))) == ~0u)
358 continue; /* not a syscall */
360 if (wrap_pos < ARRAY_SIZE(syscall_names))
361 res = strcmp( name, syscall_names[wrap_pos] );
363 if (!res) /* got a match */
365 if (id < ARRAY_SIZE(syscall_map)) syscall_map[id] = wrap_pos++;
366 else ERR( "invalid syscall id %04x for %s\n", id, name );
368 else if (res > 0)
370 FIXME( "no ntdll export for syscall %s\n", syscall_names[wrap_pos] );
371 wrap_pos++;
372 exp_pos--; /* try again */
374 else FIXME( "missing wrapper for syscall %04x %s\n", id, name );
377 for ( ; wrap_pos < ARRAY_SIZE(syscall_thunks); wrap_pos++)
378 FIXME( "no ntdll export for syscall %s\n", syscall_names[wrap_pos] );
382 /**********************************************************************
383 * load_cpu_dll
385 static HMODULE load_cpu_dll(void)
387 NTSTATUS status;
388 HMODULE module;
389 UNICODE_STRING str;
390 WCHAR path[MAX_PATH];
391 const WCHAR *dir, *name;
393 switch (current_machine)
395 case IMAGE_FILE_MACHINE_I386:
396 name = (native_machine == IMAGE_FILE_MACHINE_ARM64 ? L"xtajit.dll" : L"wow64cpu.dll");
397 break;
398 case IMAGE_FILE_MACHINE_ARM:
399 name = L"wowarmhw.dll";
400 break;
401 default:
402 ERR( "unsupported machine %04x\n", current_machine );
403 RtlExitUserProcess( 1 );
406 dir = get_machine_wow64_dir( IMAGE_FILE_MACHINE_TARGET_HOST );
408 swprintf( path, MAX_PATH, L"%s\\%s", dir, name );
409 RtlInitUnicodeString( &str, path );
410 if ((status = LdrLoadDll( NULL, 0, &str, &module )))
412 ERR( "failed to load CPU dll %x\n", status );
413 NtTerminateProcess( GetCurrentProcess(), status );
415 return module;
419 /**********************************************************************
420 * process_init
422 static DWORD WINAPI process_init( RTL_RUN_ONCE *once, void *param, void **context )
424 HMODULE module;
425 UNICODE_STRING str;
427 RtlWow64GetProcessMachines( GetCurrentProcess(), &current_machine, &native_machine );
428 if (!current_machine) current_machine = native_machine;
430 #define GET_PTR(name) p ## name = RtlFindExportedRoutineByName( module, #name )
432 RtlInitUnicodeString( &str, L"ntdll.dll" );
433 LdrGetDllHandle( NULL, 0, &str, &module );
434 GET_PTR( LdrSystemDllInitBlock );
436 module = (HMODULE)(ULONG_PTR)pLdrSystemDllInitBlock->ntdll_handle;
437 GET_PTR( Wow64Transition );
438 GET_PTR( __wine_syscall_dispatcher );
439 init_syscall_table( module );
441 module = load_cpu_dll();
442 GET_PTR( BTCpuGetBopCode );
443 GET_PTR( BTCpuProcessInit );
444 GET_PTR( BTCpuSimulate );
446 pBTCpuProcessInit();
447 *pWow64Transition = *p__wine_syscall_dispatcher = pBTCpuGetBopCode();
449 init_file_redirects();
450 return TRUE;
452 #undef GET_PTR
456 /**********************************************************************
457 * thread_init
459 static void thread_init(void)
461 /* update initial context to jump to 32-bit LdrInitializeThunk (cf. 32-bit call_init_thunk) */
462 switch (current_machine)
464 case IMAGE_FILE_MACHINE_I386:
466 I386_CONTEXT *ctx_ptr, ctx = { CONTEXT_I386_ALL };
467 ULONG *stack;
469 NtQueryInformationThread( GetCurrentThread(), ThreadWow64Context, &ctx, sizeof(ctx), NULL );
470 ctx_ptr = (I386_CONTEXT *)ULongToPtr( ctx.Esp ) - 1;
471 *ctx_ptr = ctx;
473 stack = (ULONG *)ctx_ptr;
474 *(--stack) = 0;
475 *(--stack) = 0;
476 *(--stack) = 0;
477 *(--stack) = PtrToUlong( ctx_ptr );
478 *(--stack) = 0xdeadbabe;
479 ctx.Esp = PtrToUlong( stack );
480 ctx.Eip = pLdrSystemDllInitBlock->pLdrInitializeThunk;
481 NtSetInformationThread( GetCurrentThread(), ThreadWow64Context, &ctx, sizeof(ctx) );
483 break;
485 case IMAGE_FILE_MACHINE_ARMNT:
487 ARM_CONTEXT *ctx_ptr, ctx = { CONTEXT_ARM_ALL };
489 NtQueryInformationThread( GetCurrentThread(), ThreadWow64Context, &ctx, sizeof(ctx), NULL );
490 ctx_ptr = (ARM_CONTEXT *)ULongToPtr( ctx.Sp & ~15 ) - 1;
491 *ctx_ptr = ctx;
493 ctx.R0 = PtrToUlong( ctx_ptr );
494 ctx.Sp = PtrToUlong( ctx_ptr );
495 ctx.Pc = pLdrSystemDllInitBlock->pLdrInitializeThunk;
496 NtSetInformationThread( GetCurrentThread(), ThreadWow64Context, &ctx, sizeof(ctx) );
498 break;
500 default:
501 ERR( "not supported machine %x\n", current_machine );
502 NtTerminateProcess( GetCurrentProcess(), STATUS_INVALID_IMAGE_FORMAT );
507 /**********************************************************************
508 * free_temp_data
510 static void free_temp_data(void)
512 struct mem_header *next, *mem;
514 for (mem = NtCurrentTeb()->TlsSlots[WOW64_TLS_TEMPLIST]; mem; mem = next)
516 next = mem->next;
517 RtlFreeHeap( GetProcessHeap(), 0, mem );
519 NtCurrentTeb()->TlsSlots[WOW64_TLS_TEMPLIST] = NULL;
523 /**********************************************************************
524 * Wow64SystemServiceEx (NTDLL.@)
526 NTSTATUS WINAPI Wow64SystemServiceEx( UINT num, UINT *args )
528 NTSTATUS status;
530 if (num >= ARRAY_SIZE( syscall_map ) || !syscall_map[num])
532 ERR( "unsupported syscall %04x\n", num );
533 return STATUS_INVALID_SYSTEM_SERVICE;
535 __TRY
537 syscall_thunk thunk = syscall_thunks[syscall_map[num]];
538 status = thunk( args );
540 __EXCEPT_ALL
542 status = GetExceptionCode();
544 __ENDTRY;
545 free_temp_data();
546 return status;
550 /**********************************************************************
551 * Wow64AllocateTemp
553 * FIXME: probably not 100% compatible.
555 void * WINAPI Wow64AllocateTemp( SIZE_T size )
557 struct mem_header *mem;
559 if (!(mem = RtlAllocateHeap( GetProcessHeap(), 0, offsetof( struct mem_header, data[size] ))))
560 return NULL;
561 mem->next = NtCurrentTeb()->TlsSlots[WOW64_TLS_TEMPLIST];
562 NtCurrentTeb()->TlsSlots[WOW64_TLS_TEMPLIST] = mem;
563 return mem->data;
567 /**********************************************************************
568 * Wow64ApcRoutine (NTDLL.@)
570 void WINAPI Wow64ApcRoutine( ULONG_PTR arg1, ULONG_PTR arg2, ULONG_PTR arg3, CONTEXT *context )
572 NTSTATUS retval;
574 #ifdef __x86_64__
575 retval = context->Rax;
576 #elif defined(__aarch64__)
577 retval = context->X0;
578 #endif
580 /* cf. 32-bit call_user_apc_dispatcher */
581 switch (current_machine)
583 case IMAGE_FILE_MACHINE_I386:
585 struct apc_stack_layout
587 ULONG ret;
588 ULONG context_ptr;
589 ULONG arg1;
590 ULONG arg2;
591 ULONG arg3;
592 ULONG func;
593 I386_CONTEXT context;
594 } *stack;
595 I386_CONTEXT ctx = { CONTEXT_I386_FULL };
597 NtQueryInformationThread( GetCurrentThread(), ThreadWow64Context, &ctx, sizeof(ctx), NULL );
598 stack = (struct apc_stack_layout *)ULongToPtr( ctx.Esp & ~3 ) - 1;
599 stack->context_ptr = PtrToUlong( &stack->context );
600 stack->func = arg1 >> 32;
601 stack->arg1 = arg1;
602 stack->arg2 = arg2;
603 stack->arg3 = arg3;
604 stack->context = ctx;
605 stack->context.Eax = retval;
606 ctx.Esp = PtrToUlong( stack );
607 ctx.Eip = pLdrSystemDllInitBlock->pKiUserApcDispatcher;
608 NtSetInformationThread( GetCurrentThread(), ThreadWow64Context, &ctx, sizeof(ctx) );
610 break;
612 case IMAGE_FILE_MACHINE_ARMNT:
614 struct apc_stack_layout
616 ULONG func;
617 ULONG align[3];
618 ARM_CONTEXT context;
619 } *stack;
620 ARM_CONTEXT ctx = { CONTEXT_ARM_FULL };
622 NtQueryInformationThread( GetCurrentThread(), ThreadWow64Context, &ctx, sizeof(ctx), NULL );
623 stack = (struct apc_stack_layout *)ULongToPtr( ctx.Sp & ~15 ) - 1;
624 stack->func = arg1 >> 32;
625 stack->context = ctx;
626 stack->context.R0 = retval;
627 ctx.Sp = PtrToUlong( stack );
628 ctx.Pc = pLdrSystemDllInitBlock->pKiUserApcDispatcher;
629 ctx.R0 = PtrToUlong( &stack->context );
630 ctx.R1 = arg1;
631 ctx.R2 = arg2;
632 ctx.R3 = arg3;
633 NtSetInformationThread( GetCurrentThread(), ThreadWow64Context, &ctx, sizeof(ctx) );
635 break;
640 /**********************************************************************
641 * Wow64LdrpInitialize (NTDLL.@)
643 void WINAPI Wow64LdrpInitialize( CONTEXT *context )
645 static RTL_RUN_ONCE init_done;
647 RtlRunOnceExecuteOnce( &init_done, process_init, NULL, NULL );
648 thread_init();
649 pBTCpuSimulate();