about summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--src/dynarec/arm64/dynarec_arm64_consts.c1
-rw-r--r--src/dynarec/arm64/dynarec_arm64_consts.h1
-rw-r--r--src/dynarec/arm64/dynarec_arm64_helper.c53
-rw-r--r--src/dynarec/dynarec_native_functions.c6
-rw-r--r--src/dynarec/dynarec_native_functions.h1
-rw-r--r--src/tools/env.c2
6 files changed, 45 insertions, 19 deletions
diff --git a/src/dynarec/arm64/dynarec_arm64_consts.c b/src/dynarec/arm64/dynarec_arm64_consts.c
index 5a6e6d78..e208f990 100644
--- a/src/dynarec/arm64/dynarec_arm64_consts.c
+++ b/src/dynarec/arm64/dynarec_arm64_consts.c
@@ -49,6 +49,7 @@ uintptr_t getConst(arm64_consts_t which)
         case const_native_br: return (uintptr_t)native_br;
         case const_native_ud: return (uintptr_t)native_ud;
         case const_native_priv: return (uintptr_t)native_priv;
+        case const_native_gpf: return (uintptr_t)native_gpf;
         case const_native_int3: return (uintptr_t)native_int3;
         case const_native_int: return (uintptr_t)native_int;
         case const_native_div0: return (uintptr_t)native_div0;
diff --git a/src/dynarec/arm64/dynarec_arm64_consts.h b/src/dynarec/arm64/dynarec_arm64_consts.h
index 2543699e..e6620388 100644
--- a/src/dynarec/arm64/dynarec_arm64_consts.h
+++ b/src/dynarec/arm64/dynarec_arm64_consts.h
@@ -13,6 +13,7 @@ typedef enum arm64_consts_s {
     const_native_br,
     const_native_ud,
     const_native_priv,
+    const_native_gpf,
     const_native_int3,
     const_native_int,
     const_native_div0,
diff --git a/src/dynarec/arm64/dynarec_arm64_helper.c b/src/dynarec/arm64/dynarec_arm64_helper.c
index a1d9a93b..4e6b4c02 100644
--- a/src/dynarec/arm64/dynarec_arm64_helper.c
+++ b/src/dynarec/arm64/dynarec_arm64_helper.c
@@ -718,42 +718,48 @@ void iret_to_epilog(dynarec_arm_t* dyn, uintptr_t ip, int ninst, int is32bits, i
     // POP IP
     NOTEST(x2);
     if(is64bits) {
-        POP1(xRIP);
+        POP1(x1);
         POP1(x2);
-        POP1(xFlags);
+        POP1(x3);
     } else {
-        POP1_32(xRIP);
+        POP1_32(x1);
         POP1_32(x2);
-        POP1_32(xFlags);
+        POP1_32(x3);
     }
-    // x2 is CS
-    STRH_U12(x2, xEmu, offsetof(x64emu_t, segs[_CS]));
-    STRw_U12(xZR, xEmu, offsetof(x64emu_t, segs_serial[_CS]));
+    // check CS is NULL, sgfault if it is
+    CBZw_MARK3(x1);
     // clean EFLAGS
-    MOV32w(x1, 0x3F7FD7);
-    ANDx_REG(xFlags, xFlags, x1);
-    ORRx_mask(xFlags, xFlags, 1, 0b111111, 0); // xFlags | 0b10
+    MOV32w(x4, 0x3F7FD7);
+    ANDx_REG(x3, x3, x4);
+    ORRx_mask(x3, x3, 1, 0b111111, 0); // xFlags | 0b10
     SET_DFNONE();
     if(is32bits) {
-        ANDw_mask(x2, x2, 0, 7);   // mask 0xff
+        ANDw_mask(x4, x2, 0, 7);   // mask 0xff
         // check if return segment is 64bits, then restore rsp too
-        CMPSw_U12(x2, 0x23);
+        CMPSw_U12(x4, 0x23);
         B_MARKSEG(cEQ);
     }
     // POP RSP
     if(is64bits) {
-        POP1(x3);   //rsp
-        POP1(x2);   //ss
+        POP1(x4);   //rsp
+        POP1(x5);   //ss
     } else {
-        POP1_32(x3);   //rsp
-        POP1_32(x2);   //ss
+        POP1_32(x4);   //rsp
+        POP1_32(x5);   //ss
     }
+    // check if SS is NULL
+    CBZw(x5, MARK);
     // POP SS
-    STRH_U12(x2, xEmu, offsetof(x64emu_t, segs[_SS]));
+    STRH_U12(x5, xEmu, offsetof(x64emu_t, segs[_SS]));
     STRw_U12(xZR, xEmu, offsetof(x64emu_t, segs_serial[_SS]));
     // set new RSP
-    MOVx_REG(xRSP, x3);
+    MOVx_REG(xRSP, x4);
     MARKSEG;
+    // x2 is CS, x1 is IP, x3 is eFlags
+    STRH_U12(x2, xEmu, offsetof(x64emu_t, segs[_CS]));
+    STRw_U12(xZR, xEmu, offsetof(x64emu_t, segs_serial[_CS]));
+    MOVx_REG(xRIP, x1);
+    MOVw_REG(xFlags, x3);
     // Ret....
     // epilog on purpose, CS might have changed!
     if(dyn->need_reloc)
@@ -762,6 +768,17 @@ void iret_to_epilog(dynarec_arm_t* dyn, uintptr_t ip, int ninst, int is32bits, i
         MOV64x(x2, getConst(const_epilog));
     BR(x2);
     CLEARIP();
+    MARK;
+    if(is64bits)
+        ADDx_U12(xRSP, xRSP, 8*2);
+    else
+        ADDx_U12(xRSP, xRSP, 4*2);
+    MARK3;
+    if(is64bits)
+        ADDx_U12(xRSP, xRSP, 8*3);
+    else
+        ADDx_U12(xRSP, xRSP, 4*3);
+    CALL_S(const_native_priv, -1);
 }
 
 void call_c(dynarec_arm_t* dyn, int ninst, arm64_consts_t fnc, int reg, int ret, int saveflags, int savereg)
diff --git a/src/dynarec/dynarec_native_functions.c b/src/dynarec/dynarec_native_functions.c
index 49ea4a40..0f8f5a39 100644
--- a/src/dynarec/dynarec_native_functions.c
+++ b/src/dynarec/dynarec_native_functions.c
@@ -203,6 +203,12 @@ void native_priv(x64emu_t* emu)
     EmitSignal(emu, X64_SIGSEGV, (void*)R_RIP, 0xbad0);
 }
 
+void native_gpf(x64emu_t* emu)
+{
+    emu->test.test = 0;
+    EmitSignal(emu, X64_SIGSEGV, (void*)R_RIP, 0xbad0); // same effect has private opcode?
+}
+
 void native_int(x64emu_t* emu, int num)
 {
     emu->test.test = 0;
diff --git a/src/dynarec/dynarec_native_functions.h b/src/dynarec/dynarec_native_functions.h
index 9601fc18..be3b80d5 100644
--- a/src/dynarec/dynarec_native_functions.h
+++ b/src/dynarec/dynarec_native_functions.h
@@ -55,6 +55,7 @@ void native_clflush(x64emu_t* emu, void* p);
 void native_ud(x64emu_t* emu);
 void native_br(x64emu_t* emu);
 void native_priv(x64emu_t* emu);
+void native_gpf(x64emu_t* emu);
 void native_int3(x64emu_t* emu);
 void native_int(x64emu_t* emu, int num);
 void native_wineint(x64emu_t* emu, int num);
diff --git a/src/tools/env.c b/src/tools/env.c
index 22ed7511..58e312fc 100644
--- a/src/tools/env.c
+++ b/src/tools/env.c
@@ -804,7 +804,7 @@ done:
 #define HEADER_SIGN "DynaCache"
 #define SET_VERSION(MAJ, MIN, REV) (((MAJ)<<24)|((MIN)<<16)|(REV))
 #ifdef ARM64
-#define ARCH_VERSION SET_VERSION(0, 0, 5)
+#define ARCH_VERSION SET_VERSION(0, 0, 6)
 #elif defined(RV64)
 #define ARCH_VERSION SET_VERSION(0, 0, 3)
 #elif defined(LA64)