From 984da28f4062e29875ad0ce20d4cb4b221ceb3fd Mon Sep 17 00:00:00 2001 From: ptitSeb Date: Sun, 19 May 2024 19:13:40 +0200 Subject: [PATCH] [DYNAREC] Handling of memfd_create backed mmap on dynarec (backported from box64) --- src/custommem.c | 6 ++--- src/dynarec/dynablock.c | 4 +-- src/dynarec/dynarec_arm.c | 7 +++++ src/include/custommem.h | 6 +++-- src/wrapped/wrappedlibc.c | 56 +++++++++++++++++++++++++++------------ 5 files changed, 55 insertions(+), 24 deletions(-) diff --git a/src/custommem.c b/src/custommem.c index 1e134096..6896f112 100644 --- a/src/custommem.c +++ b/src/custommem.c @@ -804,7 +804,7 @@ void protectDB(uintptr_t addr, uintptr_t size) uint32_t dyn = prot&PROT_DYN; if(!prot) prot = PROT_READ | PROT_WRITE | PROT_EXEC; - if(!(dyn&PROT_NOPROT)) { + if(!(dyn&PROT_NEVERPROT)) { prot&=~PROT_CUSTOM; if(prot&PROT_WRITE) { if(!dyn) @@ -843,7 +843,7 @@ void unprotectDB(uintptr_t addr, uintptr_t size, int mark) oprot = prot; if(bend>end) bend = end; - if(!(prot&PROT_NOPROT)) { + if(!(prot&PROT_NEVERPROT)) { if(prot&PROT_DYNAREC) { prot&=~PROT_DYN; if(mark) @@ -915,7 +915,7 @@ void updateProtection(uintptr_t addr, uintptr_t size, uint32_t prot) uint32_t oprot; rb_get_end(memprot, cur, &oprot, &bend); uint32_t dyn=(oprot&PROT_DYN); - if(!(dyn&PROT_NOPROT)) { + if(!(dyn&PROT_NEVERPROT)) { if(dyn && (prot&PROT_WRITE)) { // need to remove the write protection from this block dyn = PROT_DYNAREC; mprotect((void*)cur, bend-cur, prot&~PROT_WRITE); diff --git a/src/dynarec/dynablock.c b/src/dynarec/dynablock.c index 7e291bbb..66a6e4ce 100755 --- a/src/dynarec/dynablock.c +++ b/src/dynarec/dynablock.c @@ -272,7 +272,7 @@ dynablock_t* DBGetBlock(x86emu_t* emu, uintptr_t addr, int create) int need_lock = mutex_trylock(&my_context->mutex_dyndump); if(hash!=db->hash) { db->done = 0; // invalidating the block - dynarec_log(LOG_DEBUG, "Invalidating block %p from %p:%p (hash:%X/%X) for %p\n", db, db->x86_addr, db->x86_addr+db->x86_size-1, hash, db->hash, (void*)addr); + dynarec_log(LOG_DEBUG, "Invalidating block %p from %p:%p (hash:%X/%X, always_test:%d) for %p\n", db, db->x86_addr, db->x86_addr+db->x86_size-1, hash, db->hash, db->always_test, (void*)addr); // Free db, it's now invalid! dynablock_t* old = InvalidDynablock(db, need_lock); // start again... (will create a new block) @@ -284,7 +284,7 @@ dynablock_t* DBGetBlock(x86emu_t* emu, uintptr_t addr, int create) } else FreeInvalidDynablock(old, need_lock); } else { - dynarec_log(LOG_DEBUG, "Validating block %p from %p:%p (hash:%X) for %p\n", db, db->x86_addr, db->x86_addr+db->x86_size-1, db->hash, (void*)addr); + dynarec_log(LOG_DEBUG, "Validating block %p from %p:%p (hash:%X, always_test:%d) for %p\n", db, db->x86_addr, db->x86_addr+db->x86_size-1, db->hash, db->always_test, (void*)addr); protectDB((uintptr_t)db->x86_addr, db->x86_size); // fill back jumptable if(isprotectedDB((uintptr_t)db->x86_addr, db->x86_size) && !db->always_test) { diff --git a/src/dynarec/dynarec_arm.c b/src/dynarec/dynarec_arm.c index 1703c697..40a739ea 100755 --- a/src/dynarec/dynarec_arm.c +++ b/src/dynarec/dynarec_arm.c @@ -665,6 +665,13 @@ dynarec_log(LOG_DEBUG, "Asked to Fill block %p with %p\n", block, (void*)addr); block->dirty = 1; //protectDB(addr, end-addr); } + if(getProtection(addr)&PROT_NEVERCLEAN) { + block->dirty = 1; + block->always_test = 1; + } + if(block->always_test) { + dynarec_log(LOG_DEBUG, "Note: block marked as always dirty %p:%ld\n", block->x86_addr, block->x86_size); + } current_helper = NULL; //block->done = 1; return (void*)block; diff --git a/src/include/custommem.h b/src/include/custommem.h index db87bcf7..bc661438 100644 --- a/src/include/custommem.h +++ b/src/include/custommem.h @@ -39,11 +39,13 @@ uintptr_t getJumpTableAddress(uintptr_t addr); uintptr_t getJumpAddress(uintptr_t addr); #endif +#define PROT_NEVERCLEAN 0x100 #define PROT_DYNAREC 0x80 #define PROT_DYNAREC_R 0x40 #define PROT_NOPROT 0x20 -#define PROT_DYN (PROT_DYNAREC | PROT_DYNAREC_R | PROT_NOPROT) -#define PROT_CUSTOM (PROT_DYNAREC | PROT_DYNAREC_R | PROT_NOPROT) +#define PROT_DYN (PROT_DYNAREC | PROT_DYNAREC_R | PROT_NOPROT | PROT_NEVERCLEAN) +#define PROT_CUSTOM (PROT_DYNAREC | PROT_DYNAREC_R | PROT_NOPROT | PROT_NEVERCLEAN) +#define PROT_NEVERPROT (PROT_NOPROT | PROT_NEVERCLEAN) void updateProtection(uintptr_t addr, size_t size, uint32_t prot); void setProtection(uintptr_t addr, size_t size, uint32_t prot); diff --git a/src/wrapped/wrappedlibc.c b/src/wrapped/wrappedlibc.c index 845a6087..4abb88f9 100755 --- a/src/wrapped/wrappedlibc.c +++ b/src/wrapped/wrappedlibc.c @@ -2991,33 +2991,33 @@ EXPORT void* my_mmap(x86emu_t* emu, void *addr, unsigned long length, int prot, #endif void* ret = mmap(new_addr, length, prot, flags, fd, offset); #ifndef NOALIGN - if(!addr && ret!=new_addr && ret!=(void*)-1) { + if(!addr && ret!=new_addr && ret!=MAP_FAILED) { munmap(ret, length); loadProtectionFromMap(); // reload map, because something went wrong previously new_addr = findBlockNearHint(addr, length, 0); ret = mmap(new_addr, length, prot, flags, fd, offset); - } else if(addr && ret!=(void*)-1 && ret!=new_addr && + } else if(addr && ret!=MAP_FAILED && ret!=new_addr && ((uintptr_t)ret&0xffff) && !(flags&MAP_FIXED) && box86_wine) { munmap(ret, length); loadProtectionFromMap(); // reload map, because something went wrong previously new_addr = findBlockNearHint(addr, length, 0); ret = mmap(new_addr, length, prot, flags, fd, offset); - if(ret!=(void*)-1 && ret!=addr && ((uintptr_t)ret&0xffff) && box86_wine) { + if(ret!=MAP_FAILED && ret!=addr && ((uintptr_t)ret&0xffff) && box86_wine) { // addr is probably too high, start again with a low address munmap(ret, length); loadProtectionFromMap(); // reload map, because something went wrong previously new_addr = findBlockNearHint(NULL, length, 0); // is this the best way? ret = mmap(new_addr, length, prot, flags, fd, offset); - if(ret!=(void*)-1 && (uintptr_t)ret&0xffff) { + if(ret!=MAP_FAILED && (uintptr_t)ret&0xffff) { munmap(ret, length); - ret = (void*)-1; + ret = MAP_FAILED; } } } #endif if(box86_log0)) { + uint32_t flags = fcntl(fd, F_GETFL); + if((flags&O_ACCMODE)==O_RDWR) { + if((box86_log>=LOG_DEBUG || box86_dynarec_log>=LOG_DEBUG)) {printf_log(LOG_NONE, "Note: Marking the region (%p-%p prot=%x) as NEVERCLEAN because fd have O_RDWR attribute\n", ret, ret+length, prot);} + prot |= PROT_NEVERCLEAN; + } + } + if(emu) + setProtection_mmap((uintptr_t)ret, length, prot); + else + setProtection((uintptr_t)ret, length, prot); + } return ret; } @@ -3048,34 +3059,34 @@ EXPORT void* my_mmap64(x86emu_t* emu, void *addr, unsigned long length, int prot #endif void* ret = mmap64(new_addr, length, prot, flags, fd, offset); #ifndef NOALIGN - if(!addr && ret!=new_addr && ret!=(void*)-1) { + if(!addr && ret!=new_addr && ret!=MAP_FAILED) { munmap(ret, length); loadProtectionFromMap(); // reload map, because something went wrong previously new_addr = (flags&MAP_FIXED)?addr:(addr?findBlockNearHint(addr, length, 0):find32bitBlock(length)); ret = mmap64(new_addr, length, prot, flags, fd, offset); - } else if(addr && ret!=(void*)-1 && ret!=new_addr && + } else if(addr && ret!=MAP_FAILED && ret!=new_addr && ((uintptr_t)ret&0xffff) && !(flags&MAP_FIXED) && box86_wine) { munmap(ret, length); loadProtectionFromMap(); // reload map, because something went wrong previously new_addr = findBlockNearHint(addr, length, 0); ret = mmap64(new_addr, length, prot, flags, fd, offset); - if(ret!=(void*)-1 && ret!=addr && ((uintptr_t)ret&0xffff) && box86_wine) { + if(ret!=MAP_FAILED && ret!=addr && ((uintptr_t)ret&0xffff) && box86_wine) { // addr is probably too high, start again with a low address munmap(ret, length); loadProtectionFromMap(); // reload map, because something went wrong previously new_addr = findBlockNearHint(NULL, length, 0); // is this the best way? ret = mmap64(new_addr, length, prot, flags, fd, offset); - if(ret!=(void*)-1 && (uintptr_t)ret&0xffff) { + if(ret!=MAP_FAILED && (uintptr_t)ret&0xffff) { munmap(ret, length); errno = EEXIST; - ret = (void*)-1; + ret = MAP_FAILED; } } } #endif if(box86_log0)) { + uint32_t flags = fcntl(fd, F_GETFL); + if((flags&O_ACCMODE)==O_RDWR) { + if((box86_log>=LOG_DEBUG || box86_dynarec_log>=LOG_DEBUG)) {printf_log(LOG_NONE, "Note: Marking the region (%p-%p prot=%x) as NEVERCLEAN because fd have O_RDWR attribute\n", ret, ret+length, prot);} + prot |= PROT_NEVERCLEAN; + } + } + if(emu) + setProtection_mmap((uintptr_t)ret, length, prot); + else + setProtection((uintptr_t)ret, length, prot); + } return ret; } @@ -3099,7 +3121,7 @@ EXPORT void* my_mremap(x86emu_t* emu, void* old_addr, size_t old_size, size_t ne dynarec_log(/*LOG_DEBUG*/LOG_NONE, "mremap(%p, 0x%x, 0x%x, %d, %p)=>", old_addr, old_size, new_size, flags, new_addr); void* ret = mremap(old_addr, old_size, new_size, flags, new_addr); dynarec_log(/*LOG_DEBUG*/LOG_NONE, "%p\n", ret); - if(ret==(void*)-1) + if(ret==MAP_FAILED) return ret; // failed... uint32_t prot = getProtection((uintptr_t)old_addr)&~PROT_CUSTOM; if(ret==old_addr) {