about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
authorptitSeb <sebastien.chev@gmail.com>2021-03-28 15:08:55 +0200
committerptitSeb <sebastien.chev@gmail.com>2021-03-28 15:08:55 +0200
commitba1493857f16f8d8e9eec8f3d421e49784761e8d (patch)
tree5a26df7bf3ab0bc6dd6505a0dc21890f5deddf25 /src
parentfb7a0318a0e93b099cf781ea5bb285b97092d277 (diff)
downloadbox64-ba1493857f16f8d8e9eec8f3d421e49784761e8d.tar.gz
box64-ba1493857f16f8d8e9eec8f3d421e49784761e8d.zip
[DYNAREC] Improved Dynablock construction, stopping when overlaping block is detected
Diffstat (limited to 'src')
-rw-r--r--src/custommem.c19
-rwxr-xr-xsrc/dynarec/dynablock.c1
-rwxr-xr-xsrc/dynarec/dynarec_arm64.c27
-rwxr-xr-xsrc/dynarec/dynarec_arm64_pass.c20
-rw-r--r--src/include/custommem.h1
-rwxr-xr-xsrc/tools/bridge.c7
6 files changed, 61 insertions, 14 deletions
diff --git a/src/custommem.c b/src/custommem.c
index 6b245112..eeba5f97 100644
--- a/src/custommem.c
+++ b/src/custommem.c
@@ -470,6 +470,8 @@ uintptr_t AllocDynarecMap(dynablock_t* db, int size)
 
 void FreeDynarecMap(dynablock_t* db, uintptr_t addr, uint32_t size)
 {
+    if(!addr || !size)
+        return;
     if(size>MMAPSIZE-2*sizeof(blockmark_t)) {
         #ifndef USE_MMAP
         free((void*)addr);
@@ -594,6 +596,23 @@ void setJumpTableDefault64(void* addr)
         return;
     box64_jmptbl3[idx3][idx2][idx1][idx0] = (uintptr_t)arm64_next;
 }
+int isJumpTableDefault64(void* addr)
+{
+    uintptr_t idx3, idx2, idx1, idx0;
+    idx3 = (((uintptr_t)addr)>>48)&0xffff;
+    idx2 = (((uintptr_t)addr)>>32)&0xffff;
+    idx1 = (((uintptr_t)addr)>>16)&0xffff;
+    idx0 = (((uintptr_t)addr)    )&0xffff;
+    if(box64_jmptbl3[idx3] == box64_jmptbldefault2)
+        return 1;
+    if(box64_jmptbl3[idx3][idx2] == box64_jmptbldefault1)
+        return 1;
+    if(box64_jmptbl3[idx3][idx2][idx1] == box64_jmptbldefault0)
+        return 1;
+    if(box64_jmptbl3[idx3][idx2][idx1][idx0]==(uintptr_t)arm64_next)
+        return 1;
+    return (box64_jmptbl3[idx3][idx2][idx1][idx0]==(uintptr_t)arm64_next)?1:0;
+}
 uintptr_t getJumpTable64()
 {
     return (uintptr_t)box64_jmptbl3;
diff --git a/src/dynarec/dynablock.c b/src/dynarec/dynablock.c
index 836d7eb0..c5e2d24b 100755
--- a/src/dynarec/dynablock.c
+++ b/src/dynarec/dynablock.c
@@ -330,6 +330,7 @@ static dynablock_t* internalDBGetBlock(x64emu_t* emu, uintptr_t addr, uintptr_t
     // fill the block
     block->x64_addr = (void*)addr;
     if(!FillBlock64(block, filladdr)) {
+        dynarec_log(LOG_DEBUG, "Fillblock of block %p for %p returned an error\n", block, (void*)addr);
         void* old = (void*)arm64_lock_xchg(&dynablocks->direct[addr-dynablocks->text], 0);
         if(old!=block && old) {// put it back in place, strange things are happening here!
             dynarec_log(LOG_INFO, "Warning, a wild block appeared at %p: %p\n", (void*)addr, old);
diff --git a/src/dynarec/dynarec_arm64.c b/src/dynarec/dynarec_arm64.c
index 679bc1e1..7641a573 100755
--- a/src/dynarec/dynarec_arm64.c
+++ b/src/dynarec/dynarec_arm64.c
@@ -325,10 +325,10 @@ int Table64(dynarec_arm_t *dyn, uint64_t val)
 }
 
 
-void arm_pass0(dynarec_arm_t* dyn, uintptr_t addr);
-void arm_pass1(dynarec_arm_t* dyn, uintptr_t addr);
-void arm_pass2(dynarec_arm_t* dyn, uintptr_t addr);
-void arm_pass3(dynarec_arm_t* dyn, uintptr_t addr);
+uintptr_t arm_pass0(dynarec_arm_t* dyn, uintptr_t addr);
+uintptr_t arm_pass1(dynarec_arm_t* dyn, uintptr_t addr);
+uintptr_t arm_pass2(dynarec_arm_t* dyn, uintptr_t addr);
+uintptr_t arm_pass3(dynarec_arm_t* dyn, uintptr_t addr);
 
 void* FillBlock64(dynablock_t* block, uintptr_t addr) {
     if(addr>=box64_nodynarec_start && addr<box64_nodynarec_end)
@@ -336,7 +336,8 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr) {
     // init the helper
     dynarec_arm_t helper = {0};
     helper.start = addr;
-    arm_pass0(&helper, addr);
+    uintptr_t start = addr;
+    uintptr_t end = arm_pass0(&helper, addr);
     if(!helper.size) {
         dynarec_log(LOG_DEBUG, "Warning, null-sized dynarec block (%p)\n", (void*)addr);
         block->done = 1;
@@ -344,11 +345,12 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr) {
     }
     helper.cap = helper.size+3; // needs epilog handling
     helper.insts = (instruction_arm64_t*)calloc(helper.cap, sizeof(instruction_arm64_t));
+    // already protect the block and compute hash signature
+    protectDB(addr, end-addr+1);
+    uint32_t hash = X31_hash_code((void*)addr, end-addr+1);
     // pass 1, addresses, x64 jump addresses, flags
     arm_pass1(&helper, addr);
     // calculate barriers
-    uintptr_t start = helper.insts[0].x64.addr;
-    uintptr_t end = helper.insts[helper.size].x64.addr+helper.insts[helper.size].x64.size;
     for(int i=0; i<helper.size; ++i)
         if(helper.insts[i].x64.jmp) {
             uintptr_t j = helper.insts[i].x64.jmp;
@@ -440,11 +442,18 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr) {
     block->block = p;
     block->need_test = 0;
     //block->x64_addr = (void*)start;
-    block->x64_size = end-start;
+    block->x64_size = end-start+1;
     if(box64_dynarec_largest<block->x64_size)
         box64_dynarec_largest = block->x64_size;
     block->hash = X31_hash_code(block->x64_addr, block->x64_size);
-    // fill sons if any
+    // Check if something changed, to abbort if it as
+    if(block->hash != hash) {
+        dynarec_log(LOG_INFO, "Warning, a block changed while beeing processed hash(%p:%d)=%x/%x\n", block->x64_addr, block->x64_size, block->hash, hash);
+        free(helper.sons_x64);
+        free(helper.sons_arm);
+        FreeDynarecMap(block, (uintptr_t)p, sz);
+        return NULL;
+    }    // fill sons if any
     dynablock_t** sons = NULL;
     int sons_size = 0;
     if(helper.sons_size) {
diff --git a/src/dynarec/dynarec_arm64_pass.c b/src/dynarec/dynarec_arm64_pass.c
index 97404224..9abeaf6a 100755
--- a/src/dynarec/dynarec_arm64_pass.c
+++ b/src/dynarec/dynarec_arm64_pass.c
@@ -25,11 +25,12 @@
 #error No STEP defined
 #endif
 
-void arm_pass(dynarec_arm_t* dyn, uintptr_t addr)
+uintptr_t arm_pass(dynarec_arm_t* dyn, uintptr_t addr)
 {
     int ok = 1;
     int ninst = 0;
     uintptr_t ip = addr;
+    uintptr_t init_addr = addr;
     rex_t rex;
     int rep;    // 0 none, 1=F2 prefix, 2=F3 prefix
     int need_epilog = 1;
@@ -38,11 +39,11 @@ void arm_pass(dynarec_arm_t* dyn, uintptr_t addr)
     dyn->state_flags = 0;
     dyn->dfnone = 0;
     dyn->last_ip = ip;  // RIP is always set at start of block!
+    MAYUSE(init_addr);
     fpu_reset(dyn, ninst);
     // ok, go now
     INIT;
     while(ok) {
-        if(dyn->insts && (ninst>dyn->size)) {dynarec_log(LOG_NONE, "Warning, too many inst treated (%d / %d)\n",ninst, dyn->size);}
         ip = addr;
         if(dyn->insts && (dyn->insts[ninst].x64.barrier==1)) {
             dyn->last_ip = 0;
@@ -110,6 +111,20 @@ void arm_pass(dynarec_arm_t* dyn, uintptr_t addr)
             }
         if(ok<0)  {ok = 0; need_epilog=1;}
         ++ninst;
+        #if STEP == 0
+        if(ok && !isJumpTableDefault64((void*)addr))
+        #else
+        if(ok && dyn->insts && (ninst==dyn->size))
+        #endif
+        {
+            #if STEP == 3
+            dynarec_log(LOG_DEBUG, "Stopping block %p (%d / %d)\n",(void*)init_addr, ninst, dyn->size); 
+            #endif
+            BARRIER(2);
+            fpu_purgecache(dyn, ninst, x1, x2, x3);
+            jump_to_next(dyn, addr, 0, ninst);
+            ok=0; need_epilog=0;
+        }
     }
     if(need_epilog) {
         fpu_purgecache(dyn, ninst, x1, x2, x3);
@@ -117,4 +132,5 @@ void arm_pass(dynarec_arm_t* dyn, uintptr_t addr)
     }
     FINI;
     MESSAGE(LOG_DUMP, "---- END OF BLOCK ---- (%d, %d sons)\n", dyn->size, dyn->sons_size);
+    return addr;
 }
\ No newline at end of file
diff --git a/src/include/custommem.h b/src/include/custommem.h
index d5e8a09a..c1de067f 100644
--- a/src/include/custommem.h
+++ b/src/include/custommem.h
@@ -29,6 +29,7 @@ void cleanDBFromAddressRange(uintptr_t addr, uintptr_t size, int destroy);
 dynablocklist_t* getDB(uintptr_t idx);
 void addJumpTableIfDefault64(void* addr, void* jmp);
 void setJumpTableDefault64(void* addr);
+int isJumpTableDefault64(void* addr);
 uintptr_t getJumpTable64();
 uintptr_t getJumpTableAddress64(uintptr_t addr);
 #endif
diff --git a/src/tools/bridge.c b/src/tools/bridge.c
index a5aecc89..3a3e6768 100755
--- a/src/tools/bridge.c
+++ b/src/tools/bridge.c
@@ -91,14 +91,15 @@ uintptr_t AddBridge(bridge_t* bridge, wrapper_t w, void* fnc, int N, const char*
             b = b->next;
             bridge->last = b;
         }
-	sz = b->sz;
+	    sz = b->sz;
         #ifdef DYNAREC
         pthread_mutex_unlock(&bridge->mutex);
         if(box64_dynarec) {
             prot=(getProtection((uintptr_t)b->b)&PROT_DYNAREC)?1:0;
             if(prot)
                 unprotectDB((uintptr_t)b->b, NBRICK*sizeof(onebridge_t));
-            addDBFromAddressRange((uintptr_t)&b->b[b->sz].CC, sizeof(onebridge_t));
+            else    // only add DB if there is no protection
+                addDBFromAddressRange((uintptr_t)&b->b[b->sz].CC, sizeof(onebridge_t));
         }
     } while(sz!=b->sz); // this while loop if someone took the slot when the bridge mutex was unlocked doing memory protection managment
     pthread_mutex_lock(&bridge->mutex);
@@ -116,7 +117,7 @@ uintptr_t AddBridge(bridge_t* bridge, wrapper_t w, void* fnc, int N, const char*
     kh_value(bridge->bridgemap, k) = (uintptr_t)&b->b[sz].CC;
     pthread_mutex_unlock(&bridge->mutex);
     #ifdef DYNAREC
-    if(box64_dynarec && prot)
+    if(box64_dynarec)
         protectDB((uintptr_t)b->b, NBRICK*sizeof(onebridge_t));
     #endif
     #ifdef HAVE_TRACE