about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/custommem.c50
-rw-r--r--src/dynarec/dynarec_native_pass.c5
-rw-r--r--src/include/custommem.h1
-rw-r--r--src/include/env.h2
-rw-r--r--src/libtools/signals.c1
5 files changed, 55 insertions, 4 deletions
diff --git a/src/custommem.c b/src/custommem.c
index 87d55778..f966c835 100644
--- a/src/custommem.c
+++ b/src/custommem.c
@@ -1446,6 +1446,47 @@ void unprotectDB(uintptr_t addr, size_t size, int mark)
     }
     UNLOCK_PROT();
 }
+// Add the NEVERCLEAN flag for an adress range, mark all block as dirty, and lift write protection if needed
+void neverprotectDB(uintptr_t addr, size_t size, int mark)
+{
+    dynarec_log(LOG_DEBUG, "neverprotectDB %p -> %p (mark=%d)\n", (void*)addr, (void*)(addr+size-1), mark);
+
+    uintptr_t cur = addr&~(box64_pagesize-1);
+    uintptr_t end = ALIGN(addr+size);
+
+    LOCK_PROT();
+    while(cur!=end) {
+        uint32_t prot = 0, oprot;
+        uintptr_t bend = 0;
+        if (!rb_get_end(memprot, cur, &prot, &bend)) {
+            if(bend>=end) break;
+            else {
+                cur = bend;
+                continue;
+            }
+        }
+        oprot = prot;
+        if(bend>end)
+            bend = end;
+        if(!(prot&PROT_NEVERPROT)) {
+            if(prot&PROT_DYNAREC) {
+                prot&=~PROT_DYN;
+                if(mark)
+                    cleanDBFromAddressRange(cur, bend-cur, 0);
+                mprotect((void*)cur, bend-cur, prot);
+            } else if(prot&PROT_DYNAREC_R) {
+                if(mark)
+                    cleanDBFromAddressRange(cur, bend-cur, 0);
+                prot &= ~PROT_DYN;
+            }
+            prot |= PROT_NEVERCLEAN;
+        }
+        if (prot != oprot)
+            rb_set(memprot, cur, bend, prot);
+        cur = bend;
+    }
+    UNLOCK_PROT();
+}
 
 int isprotectedDB(uintptr_t addr, size_t size)
 {
@@ -1484,8 +1525,13 @@ void CheckHotPage(uintptr_t addr)
 {
     uintptr_t page = (uintptr_t)addr&~(box64_pagesize-1);
     if(repeated_count==1 && repeated_page==page) {
-        dynarec_log(LOG_DEBUG, "Detecting a Hotpage at %p (%d)\n", (void*)repeated_page, repeated_count);
-        SetHotPage(repeated_page);
+        if(BOX64ENV(dynarec_dirty)>1) {
+            dynarec_log(LOG_INFO, "Detecting a Hotpage at %p (%d), marking page as NEVERCLEAN\n", (void*)repeated_page, repeated_count);
+            neverprotectDB(repeated_page, box64_pagesize, 1);
+        } else {
+            dynarec_log(LOG_INFO, "Detecting a Hotpage at %p (%d)\n", (void*)repeated_page, repeated_count);
+            SetHotPage(repeated_page);
+        }
         repeated_count = 0;
         repeated_page = 0;
     } else {
diff --git a/src/dynarec/dynarec_native_pass.c b/src/dynarec/dynarec_native_pass.c
index b91c3074..343093c4 100644
--- a/src/dynarec/dynarec_native_pass.c
+++ b/src/dynarec/dynarec_native_pass.c
@@ -67,10 +67,13 @@ uintptr_t native_pass(dynarec_native_t* dyn, uintptr_t addr, int alternate, int
         #if STEP == 0
         if(cur_page != ((addr)&~(box64_pagesize-1))) {
             cur_page = (addr)&~(box64_pagesize-1);
-            if(!(getProtection(addr)&PROT_READ) || checkInHotPage(addr)) {
+            uint32_t prot = getProtection(addr);
+            if(!(prot&PROT_READ) || checkInHotPage(addr)) {
                 need_epilog = 1;
                 break;
             }
+            if(prot&PROT_NEVERCLEAN)
+                dyn->always_test = 1;
         }
         // This test is here to prevent things like TABLE64 to be out of range
         // native_size is not exact at this point, but it should be larger, not smaller, and not by a huge margin anyway
diff --git a/src/include/custommem.h b/src/include/custommem.h
index 7acbda18..b17eff99 100644
--- a/src/include/custommem.h
+++ b/src/include/custommem.h
@@ -107,6 +107,7 @@ void loadProtectionFromMap(void);
 void protectDB(uintptr_t addr, size_t size);
 void protectDBJumpTable(uintptr_t addr, size_t size, void* jump, void* ref);
 void unprotectDB(uintptr_t addr, size_t size, int mark);    // if mark==0, the blocks are not marked as potentially dirty
+void neverprotectDB(uintptr_t addr, size_t size, int mark);
 int isprotectedDB(uintptr_t addr, size_t size);
 #endif
 void* find32bitBlock(size_t size);
diff --git a/src/include/env.h b/src/include/env.h
index a35efa65..d820931d 100644
--- a/src/include/env.h
+++ b/src/include/env.h
@@ -40,7 +40,7 @@ extern char* ftrace_name;
     BOOLEAN(BOX64_DYNAREC_BLEEDING_EDGE, dynarec_bleeding_edge, 1)      \
     BOOLEAN(BOX64_DYNAREC_CALLRET, dynarec_callret, 0)                  \
     BOOLEAN(BOX64_DYNAREC_DF, dynarec_df, 1)                            \
-    BOOLEAN(BOX64_DYNAREC_DIRTY, dynarec_dirty, 0)                      \
+    INTEGER(BOX64_DYNAREC_DIRTY, dynarec_dirty, 0, 0, 2)                \
     BOOLEAN(BOX64_DYNAREC_DIV0, dynarec_div0, 0)                        \
     INTEGER(BOX64_DYNAREC_DUMP, dynarec_dump, 0, 0, 2)                  \
     BOOLEAN(BOX64_DYNAREC_FASTNAN, dynarec_fastnan, 1)                  \
diff --git a/src/libtools/signals.c b/src/libtools/signals.c
index 9b304e65..9b5cee6b 100644
--- a/src/libtools/signals.c
+++ b/src/libtools/signals.c
@@ -1694,6 +1694,7 @@ void my_box64signalhandler(int32_t sig, siginfo_t* info, void * ucntx)
         // done
         if((prot&PROT_WRITE)/*|| (prot&PROT_DYNAREC)*/) {
             unlock_signal();
+            dynarec_log(LOG_INFO, "Writting from %p(%s) to %p!\n", (void*)R_RIP, getAddrFunctionName(R_RIP), (void*)addr);
             // if there is no write permission, don't return and continue to program signal handling
             relockMutex(Locks);
             return;