about summary refs log tree commit diff stats
path: root/src
diff options
context:
space:
mode:
authorptitSeb <sebastien.chev@gmail.com>2021-07-01 17:09:03 +0200
committerptitSeb <sebastien.chev@gmail.com>2021-07-01 17:09:03 +0200
commit56401f667525063eac16081d19395527d3403e60 (patch)
tree996b917a9d139eaa26e3d313fe3672a8abc6d010 /src
parent99ba7707f63d906f5e22a44ae2cbbc8dbd5e3f3e (diff)
downloadbox64-56401f667525063eac16081d19395527d3403e60.tar.gz
box64-56401f667525063eac16081d19395527d3403e60.zip
Improved low memory pre-allocation and added 47bits pre-allocation for Wine64
Diffstat (limited to 'src')
-rw-r--r--src/custommem.c169
-rwxr-xr-xsrc/elfs/elfloader.c2
-rwxr-xr-xsrc/emu/x64run.c8
-rw-r--r--src/include/custommem.h3
-rwxr-xr-xsrc/include/debug.h1
-rwxr-xr-xsrc/main.c17
-rwxr-xr-xsrc/wrapped/wrappedlibc.c5
7 files changed, 168 insertions, 37 deletions
diff --git a/src/custommem.c b/src/custommem.c
index e1413157..0794353c 100644
--- a/src/custommem.c
+++ b/src/custommem.c
@@ -826,6 +826,51 @@ void setProtection(uintptr_t addr, size_t size, uint32_t prot)
     pthread_mutex_unlock(&mutex_prot);
 }
 
+void allocProtection(uintptr_t addr, size_t size, uint32_t prot)
+{
+    dynarec_log(LOG_DEBUG, "allocProtection %p:%p 0x%x\n", (void*)addr, (void*)(addr+size-1), prot);
+    uintptr_t idx = (addr>>MEMPROT_SHIFT);
+    uintptr_t end = ((addr+size-1LL)>>MEMPROT_SHIFT);
+    int ret;
+    pthread_mutex_lock(&mutex_prot);
+    for (uintptr_t i=idx; i<=end; ++i) {
+        const uint32_t key = (i>>MEMPROT_SHIFT2)&0xffffffff;
+        khint_t k = kh_put(memprot, memprot, key, &ret);
+        if(ret) {
+            uint8_t *m = (uint8_t*)calloc(1, MEMPROT_SIZE);
+            kh_value(memprot, k) = m;
+        }
+        const uintptr_t start = i&(MEMPROT_SIZE-1);
+        const uintptr_t finish = (((i|(MEMPROT_SIZE-1))<end)?(MEMPROT_SIZE-1):end)&(MEMPROT_SIZE-1);
+        uint8_t* block = kh_value(memprot, k);
+        for(uintptr_t ii = start; ii<=finish; ++ii) {
+            if(!block[ii])
+                block[ii] = prot;
+        }
+        i+=finish-start;    // +1 from the "for" loop
+    }
+    pthread_mutex_unlock(&mutex_prot);
+}
+
+void loadProtectionFromMap()
+{
+    char buf[500];
+    FILE *f = fopen("/proc/self/maps", "r");
+    if(!f)
+        return;
+    while(!feof(f)) {
+        char* ret = fgets(buf, sizeof(buf), f);
+        (void)ret;
+        char r, w, x;
+        uintptr_t s, e;
+        if(sscanf(buf, "%lx-%lx %c%c%c", &s, &e, &r, &w, &x)==5) {
+            int prot = ((r=='r')?PROT_READ:0)|((w=='w')?PROT_WRITE:0)|((x=='x')?PROT_EXEC:0);
+            allocProtection(s, e-s, prot);
+        }
+    }
+    fclose(f);
+}
+
 static int blockempty(uint8_t* mem)
 {
     for (int i=0; i<(MEMPROT_SIZE); ++i)
@@ -881,52 +926,112 @@ int availableBlock(uint8_t* p, size_t n)
             return 0;
     return 1;
 }
+static uintptr_t nextFree(uintptr_t addr)
+{
+    do {
+        const uint32_t key = (addr>>32)&0xffffffff;
+        khint_t k = kh_get(memprot, memprot, key);
+        if(k==kh_end(memprot)) {
+            return addr;
+        }
+        uint8_t *block = kh_value(memprot, k);
+        for (uintptr_t i=(addr&0xffffffffLL)>>MEMPROT_SHIFT; i<MEMPROT_SIZE; ++i)
+            if(!block[i]) {
+                return addr+(i<<MEMPROT_SHIFT);
+            }
+        addr += 0x100000000LL;
+        addr &= ~0xffffffffLL;
+    } while(1);
+}
+static uintptr_t maxFree(uintptr_t addr, uintptr_t sz)
+{
+    uintptr_t mfree = 0;
+    do {
+        const uint32_t key = (addr>>32)&0xffffffff;
+        khint_t k = kh_get(memprot, memprot, key);
+        if(k==kh_end(memprot)) {
+            mfree+=0x100000000LL;
+            if(mfree>sz) {
+                return addr;
+            }
+        } else {
+            uint8_t *block = kh_value(memprot, k);
+            for (uintptr_t i=(addr&0xffffffffLL)>>MEMPROT_SHIFT; i<MEMPROT_SIZE; ++i)
+                if(!block[i]) {
+                    mfree+=1<<MEMPROT_SHIFT;
+                } else
+                    return mfree;
+        }
+        addr += 0x100000000LL;
+        addr &= ~0xffffffffLL;
+    } while(1);
+}
 void* find32bitBlock(size_t size)
 {
+    return findBlockNearHint(LOWEST, size);
+}
+void* find47bitBlock(size_t size)
+{
     // slow iterative search... Would need something better one day
-    const uint32_t key = 0; // upper value is 0 by request
+    uintptr_t addr = 0x100000000LL;
     pthread_mutex_lock(&mutex_prot);
-    khint_t k = kh_get(memprot, memprot, key);
-    if(k==kh_end(memprot)) {
-        pthread_mutex_unlock(&mutex_prot);
-        return LOWEST;
-    }
-    uint8_t *prot = kh_val(memprot, k);
+    do {
+        addr = nextFree(addr);
+        uintptr_t sz = maxFree(addr, size);
+        if(sz>=size) {
+            pthread_mutex_unlock(&mutex_prot);
+            return (void*)addr;
+        }
+        addr += sz;
+    } while(addr<0x800000000000LL);
+    // search in 32bits as a backup
+    addr = (uintptr_t)LOWEST;
+    do {
+        addr = nextFree(addr);
+        uintptr_t sz = maxFree(addr, size);
+        if(sz>=size) {
+            pthread_mutex_unlock(&mutex_prot);
+            return (void*)addr;
+        }
+        addr += sz;
+    } while(addr<0x100000000LL);
     pthread_mutex_unlock(&mutex_prot);
-    void* p = (void*)LOWEST;
-    int pages = (size+MEMPROT_SIZE-1)>>MEMPROT_SHIFT;
+    printf_log(LOG_NONE, "Warning: cannot find a 0x%zx block in 47bits address space\n", size);
+    return NULL;
+}
+void* find47bitBlockNearHint(void* hint, size_t size)
+{
+    // slow iterative search... Would need something better one day
+    uintptr_t addr = (uintptr_t)hint;
+    pthread_mutex_lock(&mutex_prot);
     do {
-        const uintptr_t idx = ((uintptr_t)p)>>MEMPROT_SHIFT;
-        if(availableBlock(prot+idx, pages))
-            return p;
-        p += 0x10000;
-    } while(p!=(void*)0xffff0000);
+        addr = nextFree(addr);
+        uintptr_t sz = maxFree(addr, size);
+        if(sz>=size) {
+            pthread_mutex_unlock(&mutex_prot);
+            return (void*)addr;
+        }
+        addr += sz;
+    } while(addr<0x800000000000LL);
+    pthread_mutex_unlock(&mutex_prot);
     printf_log(LOG_NONE, "Warning: cannot find a 0x%zx block in 32bits address space\n", size);
     return NULL;
 }
 void* findBlockNearHint(void* hint, size_t size)
 {
     // slow iterative search... Would need something better one day
-    if(!hint) hint=LOWEST;
-    const uint32_t key = (((uintptr_t)hint)>>32)&0xffffffff;
+    uintptr_t addr = (uintptr_t)hint;
     pthread_mutex_lock(&mutex_prot);
-    khint_t k = kh_get(memprot, memprot, key);
-    if(k==kh_end(memprot)) {
-        pthread_mutex_unlock(&mutex_prot);
-        return hint;
-    }
-    uint8_t *prot = kh_val(memprot, k);
-    pthread_mutex_unlock(&mutex_prot);
-    void* p = hint;
-    void* end = (void*)((uintptr_t)hint+0x100000000LL);
-    uintptr_t step = (size+0xfff)&~0xfff;
-    int pages = (size+MEMPROT_SIZE-1)>>MEMPROT_SHIFT;
     do {
-        const uintptr_t idx = (((uintptr_t)p)&0xffffffff)>>MEMPROT_SHIFT;
-        if(availableBlock(prot+idx, pages))
-            return p;
-        p += step;
-    } while(p!=end);
+        addr = nextFree(addr);
+        uintptr_t sz = maxFree(addr, size);
+        if(sz>=size) {
+            pthread_mutex_unlock(&mutex_prot);
+            return (void*)addr;
+        }
+        addr += sz;
+    } while(addr<0x100000000LL);
+    pthread_mutex_unlock(&mutex_prot);
     printf_log(LOG_NONE, "Warning: cannot find a 0x%zx block in 32bits address space\n", size);
     return NULL;
 }
diff --git a/src/elfs/elfloader.c b/src/elfs/elfloader.c
index b2ba5aac..6bac1c18 100755
--- a/src/elfs/elfloader.c
+++ b/src/elfs/elfloader.c
@@ -235,6 +235,8 @@ int AllocElfMemory(box64context_t* context, elfheader_t* head, int mainbin)
         }
     } else {
         // vaddr is 0, load everything has a One block
+        if(!offs && box64_wine)
+            offs = (uintptr_t)find47bitBlock(head->memsz); // limit to 47bits...
         printf_log(LOG_DEBUG, "Allocating 0x%lx memory @%p for Elf \"%s\"\n", head->memsz, (void*)offs, head->name);
         void* p = mmap((void*)offs, head->memsz
             , PROT_READ | PROT_WRITE | PROT_EXEC
diff --git a/src/emu/x64run.c b/src/emu/x64run.c
index 792cc06e..2e01e28c 100755
--- a/src/emu/x64run.c
+++ b/src/emu/x64run.c
@@ -1051,6 +1051,14 @@ x64emurun:
             if(emu->quit) goto fini;
             break;
 
+        case 0xCF:                      /* IRET */
+            R_RIP = Pop(emu);
+            emu->segs[_CS] = Pop(emu);
+            emu->segs_serial[_CS] = 0;
+            emu->eflags.x64 = ((Pop(emu) & 0x3F7FD7)/* & (0xffff-40)*/ ) | 0x2; // mask off res2 and res3 and on res1
+            RESET_FLAGS(emu);
+            goto fini;      // exit, to recompute CS if needed
+            break;
         case 0xD0:                      /* GRP2 Eb,1 */
         case 0xD2:                      /* GRP2 Eb,CL */
             nextop = F8;
diff --git a/src/include/custommem.h b/src/include/custommem.h
index 14a8248c..4e4ff6b4 100644
--- a/src/include/custommem.h
+++ b/src/include/custommem.h
@@ -42,6 +42,7 @@ void updateProtection(uintptr_t addr, size_t size, uint32_t prot);
 void setProtection(uintptr_t addr, size_t size, uint32_t prot);
 void freeProtection(uintptr_t addr, size_t size);
 uint32_t getProtection(uintptr_t addr);
+void loadProtectionFromMap();
 #ifdef DYNAREC
 void protectDB(uintptr_t addr, size_t size);
 void protectDBnolock(uintptr_t addr, size_t size);
@@ -51,6 +52,8 @@ void unlockDB();
 #endif
 void* find32bitBlock(size_t size);
 void* findBlockNearHint(void* hint, size_t size);
+void* find47bitBlock(size_t size);
+void* find47bitBlockNearHint(void* hint, size_t size);
 
 // unlock mutex that are locked by current thread (for signal handling). Return a mask of unlock mutex
 int unlockCustommemMutex();
diff --git a/src/include/debug.h b/src/include/debug.h
index 1b6ae3c8..5341435f 100755
--- a/src/include/debug.h
+++ b/src/include/debug.h
@@ -24,6 +24,7 @@ extern char* trace_func;
 #endif
 extern int allow_missing_libs;
 extern int box64_steam;
+extern int box64_wine;
 extern int box64_nopulse;   // disabling the use of wrapped pulseaudio
 extern int box64_nogtk; // disabling the use of wrapped gtk
 extern int box64_novulkan;  // disabling the use of wrapped vulkan
diff --git a/src/main.c b/src/main.c
index 4c03f525..ce924c94 100755
--- a/src/main.c
+++ b/src/main.c
@@ -8,6 +8,7 @@
 #include <dirent.h>
 #include <signal.h>
 #include <sys/syscall.h>
+#include <sys/mman.h>
 
 #include "build_info.h"
 #include "debug.h"
@@ -52,12 +53,13 @@ char* trace_func = NULL;
 int box64_dynarec_trace = 0;
 #endif
 #endif
-int box64_zoom = 0;
 int x11threads = 0;
 int x11glx = 1;
 int allow_missing_libs = 0;
 int fix_64bit_inodes = 0;
+int box64_zoom = 0;
 int box64_steam = 0;
+int box64_wine = 0;
 int box64_nopulse = 0;
 int box64_nogtk = 0;
 int box64_novulkan = 0;
@@ -731,7 +733,8 @@ int main(int argc, const char **argv, const char **env) {
     if(!box64_nobanner)
         PrintBox64Version();
     // precheck, for win-preload
-    if(strstr(prog, "wine-preloader")==(prog+strlen(prog)-strlen("wine-preloader"))) {
+    if(strstr(prog, "wine-preloader")==(prog+strlen(prog)-strlen("wine-preloader")) 
+     || strstr(prog, "wine64-preloader")==(prog+strlen(prog)-strlen("wine64-preloader"))) {
         // wine-preloader detecter, skipping it if next arg exist and is an x86 binary
         int x64 = (nextarg<argc)?FileIsX64ELF(argv[nextarg]):0;
         if(x64) {
@@ -741,9 +744,9 @@ int main(int argc, const char **argv, const char **env) {
         }
     }
     // check if this is wine
-    if(!strcmp(prog, "wine") || (strlen(prog)>5 && !strcmp(prog+strlen(prog)-strlen("/wine"), "/wine"))) {
+    if(!strcmp(prog, "wine64") || (strlen(prog)>5 && !strcmp(prog+strlen(prog)-strlen("/wine64"), "/wine64"))) {
         const char* prereserve = getenv("WINEPRELOADRESERVE");
-        printf_log(LOG_INFO, "BOX64: Wine detected, WINEPRELOADRESERVE=\"%s\"\n", prereserve?prereserve:"");
+        printf_log(LOG_INFO, "BOX64: Wine64 detected, WINEPRELOADRESERVE=\"%s\"\n", prereserve?prereserve:"");
         if(wine_preloaded)
             wine_prereserve(prereserve);
         // special case for winedbg, doesn't work anyway
@@ -751,6 +754,11 @@ int main(int argc, const char **argv, const char **env) {
             printf_log(LOG_NONE, "winedbg detected, not launching it!\n");
             exit(0);    // exiting, it doesn't work anyway
         }
+        box64_wine = 1;
+    }
+    // check if this is wineserver
+    if(!strcmp(prog, "wineserver") || !strcmp(prog, "wineserver64") || (strlen(prog)>9 && !strcmp(prog+strlen(prog)-strlen("/wineserver"), "/wineserver"))) {
+        box64_wine = 1;
     }
     // Create a new context
     my_context = NewBox64Context(argc - nextarg);
@@ -1045,6 +1053,7 @@ int main(int argc, const char **argv, const char **env) {
 #endif
 
     atexit(endBox64);
+    loadProtectionFromMap();
 
     // emulate!
     printf_log(LOG_DEBUG, "Start x64emu on Main\n");
diff --git a/src/wrapped/wrappedlibc.c b/src/wrapped/wrappedlibc.c
index 94d7d761..f27c15e4 100755
--- a/src/wrapped/wrappedlibc.c
+++ b/src/wrapped/wrappedlibc.c
@@ -1958,7 +1958,7 @@ EXPORT void* my_mmap64(x64emu_t* emu, void *addr, unsigned long length, int prot
     (void)emu;
     if(prot&PROT_WRITE) 
         prot|=PROT_READ;    // PROT_READ is implicit with PROT_WRITE on i386
-    if(box64_log<LOG_DEBUG) {dynarec_log(LOG_DEBUG, "mmap64(%p, %lu, 0x%x, 0x%x, %d, %ld) =>", addr, length, prot, flags, fd, offset);}
+    if(box64_log<LOG_DEBUG) {dynarec_log(LOG_DEBUG, "mmap64(%p, %lu, 0x%x, 0x%x, %d, %ld) => ", addr, length, prot, flags, fd, offset);}
     #ifndef NOALIGN
     if(flags&0x40) {
         // 0x40 is MAP_32BIT, wich only exist on x86_64!
@@ -1967,6 +1967,9 @@ EXPORT void* my_mmap64(x64emu_t* emu, void *addr, unsigned long length, int prot
             addr = find32bitBlock(length);
         else
             addr = findBlockNearHint(addr, length);
+    } else if (box64_wine) {
+        if(!addr)
+            addr = find47bitBlock(length);
     }
     #endif
     void* ret = mmap64(addr, length, prot, flags, fd, offset);