about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
authorYang Liu <liuyang22@iscas.ac.cn>2024-12-26 01:52:32 +0800
committerGitHub <noreply@github.com>2024-12-25 18:52:32 +0100
commit21a21b04e6b678cbdd88172c0d162e82f2190c9f (patch)
tree2ef432c3ab03e8a7bc44d5562a26fe030f6c98dc /src
parent87e19076ad6836cac80ea945a9f973279d91a5b9 (diff)
downloadbox64-21a21b04e6b678cbdd88172c0d162e82f2190c9f.tar.gz
box64-21a21b04e6b678cbdd88172c0d162e82f2190c9f.zip
[LA64_DYNAREC] Added IRET opcode (#2210)
Diffstat (limited to 'src')
-rw-r--r--src/dynarec/la64/dynarec_la64_00.c8
-rw-r--r--src/dynarec/la64/dynarec_la64_helper.c43
-rw-r--r--src/dynarec/la64/dynarec_la64_helper.h2
3 files changed, 53 insertions, 0 deletions
diff --git a/src/dynarec/la64/dynarec_la64_00.c b/src/dynarec/la64/dynarec_la64_00.c
index 8a863667..a5a8f459 100644
--- a/src/dynarec/la64/dynarec_la64_00.c
+++ b/src/dynarec/la64/dynarec_la64_00.c
@@ -1908,6 +1908,14 @@ uintptr_t dynarec64_00(dynarec_la64_t* dyn, uintptr_t addr, uintptr_t ip, int ni
                 }
             }
             break;
+        case 0xCF:
+            INST_NAME("IRET");
+            SETFLAGS(X_ALL, SF_SET_NODF, NAT_FLAGS_NOFUSION); // Not a hack, EFLAGS are restored
+            BARRIER(BARRIER_FLOAT);
+            iret_to_epilog(dyn, ninst, rex.w);
+            *need_epilog = 0;
+            *ok = 0;
+            break;
         case 0xD0:
         case 0xD2: // TODO: Jump if CL is 0
             nextop = F8;
diff --git a/src/dynarec/la64/dynarec_la64_helper.c b/src/dynarec/la64/dynarec_la64_helper.c
index e752ac96..48e5fc10 100644
--- a/src/dynarec/la64/dynarec_la64_helper.c
+++ b/src/dynarec/la64/dynarec_la64_helper.c
@@ -658,6 +658,49 @@ void retn_to_epilog(dynarec_la64_t* dyn, int ninst, rex_t rex, int n)
     CLEARIP();
 }
 
+void iret_to_epilog(dynarec_la64_t* dyn, int ninst, int is64bits)
+{
+    // #warning TODO: is64bits
+    MAYUSE(ninst);
+    MESSAGE(LOG_DUMP, "IRet to epilog\n");
+    NOTEST(x2);
+    if (is64bits) {
+        POP1(xRIP);
+        POP1(x2);
+        POP1(xFlags);
+    } else {
+        POP1_32(xRIP);
+        POP1_32(x2);
+        POP1_32(xFlags);
+    }
+
+    ST_H(x2, xEmu, offsetof(x64emu_t, segs[_CS]));
+    ST_W(xZR, xEmu, offsetof(x64emu_t, segs_serial[_CS]));
+    // clean EFLAGS
+    MOV32w(x1, 0x3F7FD7);
+    AND(xFlags, xFlags, x1);
+    ORI(xFlags, xFlags, 0x2);
+    SET_DFNONE();
+    // POP RSP
+    if (is64bits) {
+        POP1(x3); // rsp
+        POP1(x2); // ss
+    } else {
+        POP1_32(x3); // rsp
+        POP1_32(x2); // ss
+    }
+    // POP SS
+    ST_H(x2, xEmu, offsetof(x64emu_t, segs[_SS]));
+    ST_W(xZR, xEmu, offsetof(x64emu_t, segs_serial[_SS]));
+    // set new RSP
+    MV(xRSP, x3);
+    // Ret....
+    MOV64x(x2, (uintptr_t)la64_epilog); // epilog on purpose, CS might have changed!
+    SMEND();
+    BR(x2);
+    CLEARIP();
+}
+
 void call_c(dynarec_la64_t* dyn, int ninst, void* fnc, int reg, int ret, int saveflags, int savereg)
 {
     MAYUSE(fnc);
diff --git a/src/dynarec/la64/dynarec_la64_helper.h b/src/dynarec/la64/dynarec_la64_helper.h
index 15f9bb15..7eaaac30 100644
--- a/src/dynarec/la64/dynarec_la64_helper.h
+++ b/src/dynarec/la64/dynarec_la64_helper.h
@@ -838,6 +838,7 @@ void* la64_next(x64emu_t* emu, uintptr_t addr);
 #define jump_to_next        STEPNAME(jump_to_next)
 #define ret_to_epilog       STEPNAME(ret_to_epilog)
 #define retn_to_epilog      STEPNAME(retn_to_epilog)
+#define iret_to_epilog      STEPNAME(iret_to_epilog)
 #define call_c              STEPNAME(call_c)
 #define grab_segdata        STEPNAME(grab_segdata)
 #define emit_cmp16          STEPNAME(emit_cmp16)
@@ -946,6 +947,7 @@ void jump_to_epilog_fast(dynarec_la64_t* dyn, uintptr_t ip, int reg, int ninst);
 void jump_to_next(dynarec_la64_t* dyn, uintptr_t ip, int reg, int ninst, int is32bits);
 void ret_to_epilog(dynarec_la64_t* dyn, int ninst, rex_t rex);
 void retn_to_epilog(dynarec_la64_t* dyn, int ninst, rex_t rex, int n);
+void iret_to_epilog(dynarec_la64_t* dyn, int ninst, int is64bits);
 void call_c(dynarec_la64_t* dyn, int ninst, void* fnc, int reg, int ret, int saveflags, int save_reg);
 void grab_segdata(dynarec_la64_t* dyn, uintptr_t addr, int ninst, int reg, int segment);
 void emit_cmp8(dynarec_la64_t* dyn, int ninst, int s1, int s2, int s3, int s4, int s5, int s6);