about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorAndré Zwing <nerv@dawncrow.de>2025-05-22 21:19:16 +0200
committerAndré Zwing <nerv@dawncrow.de>2025-05-22 21:27:02 +0200
commitfa874ffcbca0908493aea5e45503d52df998b099 (patch)
tree92153d2d823c013b6c66584786fac0dd6da4b85a
parentb729e3e37b37b5c14ab556d674aa71c24edcdffe (diff)
downloadbox64-fa874ffcbca0908493aea5e45503d52df998b099.tar.gz
box64-fa874ffcbca0908493aea5e45503d52df998b099.zip
[WOW64] Implement syscalls
-rw-r--r--src/dynarec/arm64/dynarec_arm64_00.c19
-rw-r--r--src/include/os.h2
-rw-r--r--wow64/compiler.h3
-rw-r--r--wow64/wowbox64.c87
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)