diff options
| author | André Zwing <nerv@dawncrow.de> | 2025-05-22 21:19:16 +0200 |
|---|---|---|
| committer | André Zwing <nerv@dawncrow.de> | 2025-05-22 21:27:02 +0200 |
| commit | fa874ffcbca0908493aea5e45503d52df998b099 (patch) | |
| tree | 92153d2d823c013b6c66584786fac0dd6da4b85a | |
| parent | b729e3e37b37b5c14ab556d674aa71c24edcdffe (diff) | |
| download | box64-fa874ffcbca0908493aea5e45503d52df998b099.tar.gz box64-fa874ffcbca0908493aea5e45503d52df998b099.zip | |
[WOW64] Implement syscalls
| -rw-r--r-- | src/dynarec/arm64/dynarec_arm64_00.c | 19 | ||||
| -rw-r--r-- | src/include/os.h | 2 | ||||
| -rw-r--r-- | wow64/compiler.h | 3 | ||||
| -rw-r--r-- | wow64/wowbox64.c | 87 |
4 files changed, 111 insertions, 0 deletions
diff --git a/src/dynarec/arm64/dynarec_arm64_00.c b/src/dynarec/arm64/dynarec_arm64_00.c index 351e1e0a..3ab1e5c4 100644 --- a/src/dynarec/arm64/dynarec_arm64_00.c +++ b/src/dynarec/arm64/dynarec_arm64_00.c @@ -2646,6 +2646,25 @@ uintptr_t dynarec64_00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int nin break; case 0xCD: u8 = F8; +#ifdef _WIN32 + NOTEST(x1); + SMEND(); + GETIP(addr); + STORE_XEMU_CALL(xRIP); + MOV32w(x1, u8); + LDRx_U12(xR8, xEmu, offsetof(x64emu_t, win64_teb)); + CALL_S(x86Int, -1); + LOAD_XEMU_CALL(xRIP); + TABLE64(x3, addr); // expected return address + CMPSx_REG(xRIP, x3); + B_MARK(cNE); + LDRw_U12(w1, xEmu, offsetof(x64emu_t, quit)); + CBZw_NEXT(w1); + MARK; + LOAD_XEMU_REM(); + jump_to_epilog(dyn, 0, xRIP, ninst); + break; +#endif if(box64_wine && (u8==0x2D || u8==0x2C || u8==0x29)) { INST_NAME("INT 29/2c/2d"); // lets do nothing diff --git a/src/include/os.h b/src/include/os.h index 1257cc48..f141e99e 100644 --- a/src/include/os.h +++ b/src/include/os.h @@ -26,6 +26,8 @@ void* mmap(void* addr, size_t length, int prot, int flags, int fd, off_t offset) int munmap(void* addr, size_t length); int mprotect(void* addr, size_t len, int prot); +void x86Int(void* emu, int code); + void* WinMalloc(size_t size); void* WinRealloc(void* ptr, size_t size); void* WinCalloc(size_t nmemb, size_t size); diff --git a/wow64/compiler.h b/wow64/compiler.h index 9abafa74..e30691fd 100644 --- a/wow64/compiler.h +++ b/wow64/compiler.h @@ -7,6 +7,7 @@ #define ThreadWow64Context (29) #define WOW64_TLS_CPURESERVED (1) #define WOW64_TLS_MAX_NUMBER (19) +#define WOW64_CPURESERVED_FLAG_RESET_STATE (1) typedef struct _WOW64_CPURESERVED { @@ -15,8 +16,10 @@ typedef struct _WOW64_CPURESERVED } WOW64_CPURESERVED; NTSTATUS WINAPI RtlWow64GetCurrentCpuArea(USHORT *, void **, void **); +NTSTATUS WINAPI Wow64SystemServiceEx(UINT, UINT*); NTSYSAPI NTSTATUS WINAPI LdrGetDllHandle(LPCWSTR, ULONG, const UNICODE_STRING*, HMODULE*); NTSYSAPI void* WINAPI RtlFindExportedRoutineByName(HMODULE, const char*); +NTSYSAPI void DECLSPEC_NORETURN WINAPI RtlRaiseStatus(NTSTATUS); static inline uintptr_t calculate_fs(void) { diff --git a/wow64/wowbox64.c b/wow64/wowbox64.c index 4d6d7263..b3147404 100644 --- a/wow64/wowbox64.c +++ b/wow64/wowbox64.c @@ -18,6 +18,7 @@ #include "x64trace.h" #include "box64context.h" #include "box64cpu.h" +#include "box64cpu_util.h" #include "rbtree.h" #include "wine/debug.h" @@ -240,6 +241,92 @@ NTSTATUS WINAPI BTCpuTurboThunkControl(ULONG enable) return STATUS_SUCCESS; } +void x86IntImpl(x64emu_t *emu, int code) +{ + int inst_off = box64env.dynarec ? 2 : 0; + + if (code == 0x2e) /* NT syscall */ + { + WOW64_CPURESERVED *cpu = NtCurrentTeb()->TlsSlots[WOW64_TLS_CPURESERVED]; + WOW64_CONTEXT *ctx = (WOW64_CONTEXT *)(cpu + 1); + int id = R_EAX; + BOOL is_unix_call = FALSE; + + if (ULongToPtr(R_RIP-inst_off) == &unxcode) + is_unix_call = TRUE; + else if (ULongToPtr(R_RIP-inst_off) != &bopcode) + return; + + R_RIP = Pop32(emu); + ctx->Eip = R_RIP; + ctx->Esp = R_ESP; + ctx->Ebx = R_EBX; + ctx->Esi = R_ESI; + ctx->Edi = R_EDI; + ctx->Ebp = R_EBP; + ctx->EFlags = emu->eflags.x64; + cpu->Flags = 0; + + if (is_unix_call) + { + uintptr_t handle_low = Pop32(emu); + uintptr_t handle_high = Pop32(emu); + unsigned int code = Pop32(emu); + uintptr_t args = Pop32(emu); + + ctx->Esp = R_ESP; + R_EAX = __wine_unix_call_dispatcher( handle_low | (handle_high << 32), code, (void *)args ); + } + else + { + R_EAX = Wow64SystemServiceEx( id, ULongToPtr(ctx->Esp+4) ); + } + + R_EBX = ctx->Ebx; + R_ESI = ctx->Esi; + R_EDI = ctx->Edi; + R_EBP = ctx->Ebp; + R_ESP = ctx->Esp; + R_RIP = ctx->Eip; + if (cpu->Flags & WOW64_CPURESERVED_FLAG_RESET_STATE) + { + cpu->Flags &= ~WOW64_CPURESERVED_FLAG_RESET_STATE; + R_EAX = ctx->Eax; + R_ECX = ctx->Ecx; + R_EDX = ctx->Edx; + R_FS = ctx->SegFs & 0xffff; + emu->segs_offs[_FS] = calculate_fs(); + emu->eflags.x64 = ctx->EFlags; + } + } + else + { + RtlRaiseStatus( STATUS_ACCESS_VIOLATION ); + } +} + +/* Calls a 2-argument function `Func` setting the parent unwind frame information to the given SP and PC */ +static void __attribute__((naked)) SEHFrameTrampoline2Args(void* Arg0, int Arg1, void* Func, uint64_t Sp, uint64_t Pc) +{ + asm( ".seh_proc SEHFrameTrampoline2Args\n\t" + "stp x3, x4, [sp, #-0x10]!\n\t" + ".seh_pushframe\n\t" + "stp x29, x30, [sp, #-0x10]!\n\t" + ".seh_save_fplr_x 16\n\t" + ".seh_endprologue\n\t" + "blr x2\n\t" + "ldp x29, x30, [sp], 0x20\n\t" + "ret\n\t" + ".seh_endproc" ); +} + +void x86Int(void* emu, int code) +{ + CONTEXT *entry_context = NtCurrentTeb()->TlsSlots[WOW64_TLS_MAX_NUMBER]; + SEHFrameTrampoline2Args(emu, code, (void*)x86IntImpl, entry_context->Sp, entry_context->Pc); + NtCurrentTeb()->TlsSlots[WOW64_TLS_MAX_NUMBER] = entry_context; +} + NTSTATUS WINAPI LdrDisableThreadCalloutsForDll(HMODULE); BOOL WINAPI DllMainCRTStartup(HINSTANCE inst, DWORD reason, void* reserved) |