[DYNAREC] Handling of memfd_create backed mmap on dynarec (backported from box64)

This commit is contained in:
ptitSeb 2024-05-19 19:13:40 +02:00
parent a8babcba8d
commit 984da28f40
5 changed files with 55 additions and 24 deletions

View File

@ -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);

View File

@ -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) {

View File

@ -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;

View File

@ -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);

View File

@ -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_log<LOG_DEBUG) {dynarec_log(LOG_DEBUG, "%p\n", ret);}
#ifdef DYNAREC
if(box86_dynarec && ret!=(void*)-1) {
if(box86_dynarec && ret!=MAP_FAILED) {
/*if(flags&0x100000 && addr!=ret)
{
// program used MAP_FIXED_NOREPLACE but the host linux didn't support it
@ -3030,8 +3030,19 @@ EXPORT void* my_mmap(x86emu_t* emu, void *addr, unsigned long length, int prot,
}
}
#endif
if(ret!=(void*)-1 && emu)
setProtection_mmap((uintptr_t)ret, length, prot);
if(ret!=MAP_FAILED) {
if((flags&MAP_SHARED) && (fd>0)) {
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_log<LOG_DEBUG) {dynarec_log(LOG_DEBUG, "%p\n", ret);}
#ifdef DYNAREC
if(box86_dynarec && ret!=(void*)-1) {
if(box86_dynarec && ret!=MAP_FAILED) {
/*if(flags&0x100000 && addr!=ret)
{
// program used MAP_FIXED_NOREPLACE but the host linux didn't support it
@ -3088,8 +3099,19 @@ EXPORT void* my_mmap64(x86emu_t* emu, void *addr, unsigned long length, int prot
}
}
#endif
if(ret!=(void*)-1 && emu)
setProtection_mmap((uintptr_t)ret, length, prot);
if(ret!=MAP_FAILED) {
if((flags&MAP_SHARED) && (fd>0)) {
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) {