about summary refs log tree commit diff stats
path: root/src/dynarec
diff options
context:
space:
mode:
authorptitSeb <sebastien.chev@gmail.com>2024-12-31 22:27:55 +0100
committerptitSeb <sebastien.chev@gmail.com>2024-12-31 22:27:55 +0100
commit1d20968f822018ccbe1afd7c4d35c4f7b4774341 (patch)
tree2c34d0a73b4a3cf9adedebd1962f2e2b1a039188 /src/dynarec
parentca8d569e63dd53183dcb9b1e6446027774083782 (diff)
downloadbox64-1d20968f822018ccbe1afd7c4d35c4f7b4774341.tar.gz
box64-1d20968f822018ccbe1afd7c4d35c4f7b4774341.zip
[ARM64_DYNAREC] Improved signal handling and flags handling (tbd on other archs)
Diffstat (limited to 'src/dynarec')
-rw-r--r--src/dynarec/arm64/dynarec_arm64_arch.c81
-rw-r--r--src/dynarec/arm64/dynarec_arm64_arch.h28
-rw-r--r--src/dynarec/dynablock_private.h2
-rw-r--r--src/dynarec/dynarec_arch.h12
-rw-r--r--src/dynarec/dynarec_native.c15
5 files changed, 136 insertions, 2 deletions
diff --git a/src/dynarec/arm64/dynarec_arm64_arch.c b/src/dynarec/arm64/dynarec_arm64_arch.c
new file mode 100644
index 00000000..af84565c
--- /dev/null
+++ b/src/dynarec/arm64/dynarec_arm64_arch.c
@@ -0,0 +1,81 @@
+#include <stddef.h>
+#include <stdio.h>
+#include <ucontext.h>
+
+#include "debug.h"
+#include "dynablock.h"
+#include "x64emu.h"
+#include "emu/x64emu_private.h"
+#include "x64run.h"
+#include "emu/x64run_private.h"
+#include "dynarec/dynablock_private.h"
+#include "dynarec_arm64_arch.h"
+
+size_t get_size_arch(dynarec_arm_t* dyn)
+{
+    if(!box64_dynarec_nativeflags)
+        return 0;
+    return dyn->isize*sizeof(arch_flags_t);
+}
+
+void populate_arch(dynarec_arm_t* dyn, void* p)
+{
+    if(!box64_dynarec_nativeflags)
+        return;
+
+    arch_flags_t* flags = p;
+    for(int i=0; i<dyn->size; ++i) {
+        flags[i].defered = dyn->insts[i].f_entry.dfnone==0;
+        flags[i].vf = dyn->insts[i].need_nat_flags&NF_VF;
+        flags[i].nf = dyn->insts[i].need_nat_flags&NF_SF;
+        flags[i].eq = dyn->insts[i].need_nat_flags&NF_EQ;
+        flags[i].cf = dyn->insts[i].need_nat_flags&NF_CF;
+        flags[i].inv_cf = !dyn->insts[i].normal_carry;
+    }
+}
+
+int getX64AddressInst(dynablock_t* db, uintptr_t native_addr); // define is signal.c
+
+// NZCV N
+#define NZCV_N      31
+// NZCV Z
+#define NZCV_Z      30
+// NZCV C
+#define NZCV_C      29
+// NZCV V
+#define NZCV_V      28
+
+void adjust_arch(dynablock_t* db, x64emu_t* emu, ucontext_t* p, uintptr_t x64pc)
+{
+    if(!db->arch_size || !db->arch)
+        return;
+    arch_flags_t* flags = db->arch;
+    int ninst = getX64AddressInst(db, x64pc);
+printf_log(LOG_INFO, "adjust_arch(...), db=%p, x64pc=%p, nints=%d, flags:%s %c%c%c%c%s\n", db, (void*)x64pc, ninst, flags[ninst-1].defered?"defered":"", flags[ninst-1].vf?'V':' ', flags[ninst-1].nf?'S':' ', flags[ninst-1].eq?'Z':' ', flags[ninst-1].cf?'C':' ', (flags[ninst-1].cf && flags[ninst-1].inv_cf)?"inverted":"");
+    if(ninst<0)
+        return;
+    if(ninst==0) {
+        CHECK_FLAGS(emu);
+        return;
+    }
+    if(flags[ninst-1].defered) {
+        CHECK_FLAGS(emu);
+        //return;
+    }
+    if(flags[ninst-1].nf) {
+        CONDITIONAL_SET_FLAG(p->uc_mcontext.pstate&(1<<NZCV_N), F_SF);
+    }
+    if(flags[ninst-1].vf) {
+        CONDITIONAL_SET_FLAG(p->uc_mcontext.pstate&(1<<NZCV_V), F_OF);
+    }
+    if(flags[ninst-1].eq) {
+        CONDITIONAL_SET_FLAG(p->uc_mcontext.pstate&(1<<NZCV_Z), F_ZF);
+    }
+    if(flags[ninst-1].cf) {
+        if(flags[ninst-1].inv_cf) {
+            CONDITIONAL_SET_FLAG((p->uc_mcontext.pstate&(1<<NZCV_C))==0, F_CF);
+        } else {
+            CONDITIONAL_SET_FLAG(p->uc_mcontext.pstate&(1<<NZCV_C), F_CF);
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/dynarec/arm64/dynarec_arm64_arch.h b/src/dynarec/arm64/dynarec_arm64_arch.h
new file mode 100644
index 00000000..a430cf74
--- /dev/null
+++ b/src/dynarec/arm64/dynarec_arm64_arch.h
@@ -0,0 +1,28 @@
+#ifndef __DYNAREC_ARM_ARCH_H__
+#define __DYNAREC_ARM_ARCH_H__
+
+#include <stddef.h>
+#include <ucontext.h>
+
+#include "x64emu.h"
+#include "box64context.h"
+#include "dynarec.h"
+#include "dynarec_arm64_private.h"
+
+typedef struct arch_flags_s
+{
+    uint8_t defered:1;
+    uint8_t nf:1;
+    uint8_t eq:1;
+    uint8_t vf:1;
+    uint8_t cf:1;
+    uint8_t inv_cf:1;
+} arch_flags_t;
+
+// get size of arch specific info (can be 0)
+size_t get_size_arch(dynarec_arm_t* dyn);
+//populate the array
+void populate_arch(dynarec_arm_t* dyn, void* p);
+//adjust flags and more
+void adjust_arch(dynablock_t* db, x64emu_t* emu, ucontext_t* p, uintptr_t native_addr);
+#endif // __DYNAREC_ARM_ARCH_H__
diff --git a/src/dynarec/dynablock_private.h b/src/dynarec/dynablock_private.h
index a152bd4e..b9e5f55d 100644
--- a/src/dynarec/dynablock_private.h
+++ b/src/dynarec/dynablock_private.h
@@ -21,6 +21,8 @@ typedef struct dynablock_s {
     uint8_t         is32bits:1;
     int             isize;
     instsize_t*     instsize;
+    void*           arch;       // arch dependant per inst info (can be NULL)
+    size_t          arch_size;  // size of of arch dependant infos
     void*           jmpnext;    // a branch jmpnext code when block is marked
 } dynablock_t;
 
diff --git a/src/dynarec/dynarec_arch.h b/src/dynarec/dynarec_arch.h
index 3dd07d5f..edc09650 100644
--- a/src/dynarec/dynarec_arch.h
+++ b/src/dynarec/dynarec_arch.h
@@ -17,6 +17,7 @@
 #include "arm64/arm64_printer.h"

 #include "arm64/dynarec_arm64_private.h"

 #include "arm64/dynarec_arm64_functions.h"

+#include "arm64/dynarec_arm64_arch.h"

 // Limit here is defined by LD litteral, that is 19bits

 #define MAXBLOCK_SIZE ((1<<19)-200)

 

@@ -24,6 +25,9 @@
 #define UPDATE_SPECIFICS(A)     updateNativeFlags(A)

 #define PREUPDATE_SPECIFICS(A)

 

+#define ARCH_SIZE(A)    get_size_arch(A)

+#define ARCH_FILL(A, B) populate_arch(A, B)

+#define ARCH_ADJUST(A, B, C, D) adjust_arch(A, B, C, D)

 #elif defined(LA64)

 

 #define instruction_native_t        instruction_la64_t

@@ -45,6 +49,10 @@
 #define RAZ_SPECIFIC(A, N)

 #define UPDATE_SPECIFICS(A)

 #define PREUPDATE_SPECIFICS(A) updateNativeFlags(A)

+

+#define ARCH_SIZE(A)    0

+#define ARCH_FILL(A, B)  {}

+#define ARCH_ADJUST(A, B, C, D) {}

 #elif defined(RV64)

 

 #define instruction_native_t        instruction_rv64_t

@@ -68,6 +76,10 @@
 #define RAZ_SPECIFIC(A, N)

 #define UPDATE_SPECIFICS(A)

 #define PREUPDATE_SPECIFICS(A) updateNativeFlags(A)

+

+#define ARCH_SIZE(A)    0

+#define ARCH_FILL(A, B)  {}

+#define ARCH_ADJUST(A, B, C, D) {}

 #else

 #error Unsupported platform

 #endif

diff --git a/src/dynarec/dynarec_native.c b/src/dynarec/dynarec_native.c
index 47c1c99e..42b557ed 100644
--- a/src/dynarec/dynarec_native.c
+++ b/src/dynarec/dynarec_native.c
@@ -562,6 +562,7 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
         B+16 .. B+23    : jmpnext (or jmp_epilog) address. jumpnext is used when the block needs testing
         B+24 .. B+31    : empty (in case an architecture needs more than 2 opcodes)
         B+32 .. B+32+sz : instsize (compressed array with each instruction length on x64 and native side)
+        C ..    C+sz    : arch: arch specific info (likes flags info) per inst (can be absent)
 
     */
     if(addr>=box64_nodynarec_start && addr<box64_nodynarec_end) {
@@ -725,14 +726,16 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
     size_t insts_rsize = (helper.insts_size+2)*sizeof(instsize_t);
     insts_rsize = (insts_rsize+7)&~7;   // round the size...
     size_t native_size = (helper.native_size+7)&~7;   // round the size...
+    size_t arch_size = ARCH_SIZE(&helper);
     // ok, now allocate mapped memory, with executable flag on
-    size_t sz = sizeof(void*) + native_size + helper.table64size*sizeof(uint64_t) + 4*sizeof(void*) + insts_rsize;
-    //           dynablock_t*     block (arm insts)            table64               jmpnext code       instsize
+    size_t sz = sizeof(void*) + native_size + helper.table64size*sizeof(uint64_t) + 4*sizeof(void*) + insts_rsize + arch_size;
+    //           dynablock_t*     block (arm insts)            table64               jmpnext code       instsize     arch
     void* actual_p = (void*)AllocDynarecMap(sz);
     void* p = (void*)(((uintptr_t)actual_p) + sizeof(void*));
     void* tablestart = p + native_size;
     void* next = tablestart + helper.table64size*sizeof(uint64_t);
     void* instsize = next + 4*sizeof(void*);
+    void* arch = instsize + insts_rsize;
     if(actual_p==NULL) {
         dynarec_log(LOG_INFO, "AllocDynarecMap(%p, %zu) failed, canceling block\n", block, sz);
         CancelBlock64(0);
@@ -784,6 +787,14 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr, int alternate, int is32bit
     block->always_test = helper.always_test;
     block->dirty = block->always_test;
     block->is32bits = is32bits;
+    if(arch_size) {
+        block->arch = arch;
+        block->arch_size = arch_size;
+        ARCH_FILL(&helper, arch);
+    } else {
+        block->arch = NULL;
+        block->arch_size = arch_size;
+    }
     *(dynablock_t**)next = block;
     *(void**)(next+3*sizeof(void*)) = native_next;
     CreateJmpNext(block->jmpnext, next+3*sizeof(void*));