diff options
| author | ptitSeb <sebastien.chev@gmail.com> | 2023-04-16 10:50:12 +0200 |
|---|---|---|
| committer | ptitSeb <sebastien.chev@gmail.com> | 2023-04-16 10:50:12 +0200 |
| commit | 3adf31c85b8bb4366d063fbe8f7d9fc36084366d (patch) | |
| tree | 42d8fb12e6079f362c54226a862cabd8b1980ad9 | |
| parent | 9b2c6caf22e6dc91ad72f4d90116b80237bd3487 (diff) | |
| download | box64-3adf31c85b8bb4366d063fbe8f7d9fc36084366d.tar.gz box64-3adf31c85b8bb4366d063fbe8f7d9fc36084366d.zip | |
[DYNAREC] General fixes and improvment for multithread and jit program. Helps Java, mono and Unity3d program... (should help #519, #464, #433, #272, #232, #193, #112...)
| -rw-r--r-- | src/custommem.c | 27 | ||||
| -rwxr-xr-x | src/dynarec/arm64/dynarec_arm64_pass2.h | 4 | ||||
| -rwxr-xr-x | src/dynarec/arm64/dynarec_arm64_pass3.h | 7 | ||||
| -rwxr-xr-x | src/dynarec/arm64/dynarec_arm64_private.h | 4 | ||||
| -rwxr-xr-x | src/dynarec/dynablock.c | 129 | ||||
| -rwxr-xr-x | src/dynarec/dynablock_private.h | 5 | ||||
| -rwxr-xr-x | src/dynarec/dynarec_native.c | 82 | ||||
| -rw-r--r-- | src/dynarec/rv64/dynarec_rv64_pass2.h | 4 | ||||
| -rw-r--r-- | src/dynarec/rv64/dynarec_rv64_pass3.h | 4 | ||||
| -rw-r--r-- | src/dynarec/rv64/dynarec_rv64_private.h | 4 | ||||
| -rw-r--r-- | src/include/custommem.h | 1 | ||||
| -rwxr-xr-x | src/include/dynablock.h | 2 | ||||
| -rwxr-xr-x | src/libtools/signals.c | 13 | ||||
| -rw-r--r-- | system/box64.box64rc | 6 |
14 files changed, 199 insertions, 93 deletions
diff --git a/src/custommem.c b/src/custommem.c index 4cf1dd0a..45c7a01f 100644 --- a/src/custommem.c +++ b/src/custommem.c @@ -26,6 +26,7 @@ #include "threads.h" #ifdef DYNAREC #include "dynablock.h" +#include "dynarec/dynablock_private.h" #include "dynarec/native_lock.h" #include "dynarec/dynarec_next.h" @@ -770,6 +771,28 @@ dynablock_t* getDB(uintptr_t addr) return *(dynablock_t**)(ret - sizeof(void*)); } +int getNeedTest(uintptr_t addr) +{ + uintptr_t idx3, idx2, idx1, idx0; + idx3 = ((addr)>>JMPTABL_START3)&JMPTABLE_MASK3; + idx2 = ((addr)>>JMPTABL_START2)&JMPTABLE_MASK2; + idx1 = ((addr)>>JMPTABL_START1)&JMPTABLE_MASK1; + idx0 = ((addr) )&JMPTABLE_MASK0; + uintptr_t ret = (uintptr_t)box64_jmptbl3[idx3][idx2][idx1][idx0]; + dynablock_t* db = *(dynablock_t**)(ret - sizeof(void*)); + return db?((ret!=(uintptr_t)db->block)?1:0):0; +} + +uintptr_t getJumpAddress64(uintptr_t addr) +{ + uintptr_t idx3, idx2, idx1, idx0; + idx3 = ((addr)>>JMPTABL_START3)&JMPTABLE_MASK3; + idx2 = ((addr)>>JMPTABL_START2)&JMPTABLE_MASK2; + idx1 = ((addr)>>JMPTABL_START1)&JMPTABLE_MASK1; + idx0 = ((addr) )&JMPTABLE_MASK0; + return (uintptr_t)box64_jmptbl3[idx3][idx2][idx1][idx0]; +} + // Remove the Write flag from an adress range, so DB can be executed safely void protectDB(uintptr_t addr, uintptr_t size) { @@ -1032,8 +1055,10 @@ void refreshProtection(uintptr_t addr) uintptr_t idx = (addr>>MEMPROT_SHIFT); if(memprot[idx>>16].prot!=memprot_default) { int prot = memprot[idx>>16].prot[idx&0xffff]; - int ret = mprotect((void*)(idx<<MEMPROT_SHIFT), box64_pagesize, prot&~PROT_CUSTOM); + if(!(prot&PROT_DYNAREC)) { + int ret = mprotect((void*)(idx<<MEMPROT_SHIFT), box64_pagesize, prot&~PROT_CUSTOM); printf_log(LOG_INFO, "refreshProtection(%p): %p/0x%x (ret=%d/%s)\n", (void*)addr, (void*)(idx<<MEMPROT_SHIFT), prot, ret, ret?strerror(errno):"ok"); + } } mutex_unlock(&mutex_prot); } diff --git a/src/dynarec/arm64/dynarec_arm64_pass2.h b/src/dynarec/arm64/dynarec_arm64_pass2.h index 57a37572..86692795 100755 --- a/src/dynarec/arm64/dynarec_arm64_pass2.h +++ b/src/dynarec/arm64/dynarec_arm64_pass2.h @@ -14,5 +14,5 @@ } #define INST_EPILOG dyn->insts[ninst].epilog = dyn->native_size; #define INST_NAME(name) -#define TABLE64(A, V) {Table64(dyn, (V)); EMIT(0);} -#define FTABLE64(A, V) {mmx87_regs_t v = {.d = V}; Table64(dyn, v.q); EMIT(0);} \ No newline at end of file +#define TABLE64(A, V) {Table64(dyn, (V), 2); EMIT(0);} +#define FTABLE64(A, V) {mmx87_regs_t v = {.d = V}; Table64(dyn, v.q, 2); EMIT(0);} \ No newline at end of file diff --git a/src/dynarec/arm64/dynarec_arm64_pass3.h b/src/dynarec/arm64/dynarec_arm64_pass3.h index c39aa5e4..bdc41db9 100755 --- a/src/dynarec/arm64/dynarec_arm64_pass3.h +++ b/src/dynarec/arm64/dynarec_arm64_pass3.h @@ -6,7 +6,8 @@ #define EMIT(A) \ do{ \ if(box64_dynarec_dump) print_opcode(dyn, ninst, (uint32_t)(A)); \ - *(uint32_t*)(dyn->block) = (uint32_t)(A); \ + if((uintptr_t)dyn->block<dyn->tablestart) \ + *(uint32_t*)(dyn->block) = (uint32_t)(A); \ dyn->block += 4; dyn->native_size += 4; \ dyn->insts[ninst].size2 += 4; \ }while(0) @@ -17,5 +18,5 @@ addInst(dyn->instsize, &dyn->insts_size, dyn->insts[ninst-1].x64.size, dyn->insts[ninst-1].size/4); #define INST_EPILOG #define INST_NAME(name) inst_name_pass3(dyn, ninst, name) -#define TABLE64(A, V) {int val64offset = Table64(dyn, (V)); MESSAGE(LOG_DUMP, " Table64: 0x%lx\n", (V)); LDRx_literal(A, val64offset);} -#define FTABLE64(A, V) {mmx87_regs_t v = {.d = V}; int val64offset = Table64(dyn, v.q); MESSAGE(LOG_DUMP, " FTable64: %g\n", v.d); VLDR64_literal(A, val64offset);} +#define TABLE64(A, V) {int val64offset = Table64(dyn, (V), 3); MESSAGE(LOG_DUMP, " Table64: 0x%lx\n", (V)); LDRx_literal(A, val64offset);} +#define FTABLE64(A, V) {mmx87_regs_t v = {.d = V}; int val64offset = Table64(dyn, v.q, 3); MESSAGE(LOG_DUMP, " FTable64: %g\n", v.d); VLDR64_literal(A, val64offset);} diff --git a/src/dynarec/arm64/dynarec_arm64_private.h b/src/dynarec/arm64/dynarec_arm64_private.h index 15705634..be57a790 100755 --- a/src/dynarec/arm64/dynarec_arm64_private.h +++ b/src/dynarec/arm64/dynarec_arm64_private.h @@ -95,6 +95,7 @@ typedef struct dynarec_arm_s { int table64size;// size of table (will be appended at end of executable code) int table64cap; uintptr_t tablestart; + uintptr_t jmp_next; // address of the jump_next address flagcache_t f; neoncache_t n; // cache for the 8..31 double reg from fpu, plus x87 stack delta uintptr_t* next; // variable array of "next" jump address @@ -112,6 +113,7 @@ typedef struct dynarec_arm_s { int forward_ninst; // ninst at the forward point uint8_t doublepush; uint8_t doublepop; + uint8_t always_test; } dynarec_arm_t; void add_next(dynarec_arm_t *dyn, uintptr_t addr); @@ -119,7 +121,7 @@ uintptr_t get_closest_next(dynarec_arm_t *dyn, uintptr_t addr); int is_nops(dynarec_arm_t *dyn, uintptr_t addr, int n); int is_instructions(dynarec_arm_t *dyn, uintptr_t addr, int n); -int Table64(dynarec_arm_t *dyn, uint64_t val); // add a value to etable64 (if needed) and gives back the imm19 to use in LDR_literal +int Table64(dynarec_arm_t *dyn, uint64_t val, int pass); // add a value to etable64 (if needed) and gives back the imm19 to use in LDR_literal void CreateJmpNext(void* addr, void* next); diff --git a/src/dynarec/dynablock.c b/src/dynarec/dynablock.c index 17c6aa0c..d5c95111 100755 --- a/src/dynarec/dynablock.c +++ b/src/dynarec/dynablock.c @@ -37,6 +37,39 @@ uint32_t X31_hash_code(void* addr, int len) return (uint32_t)h; } +dynablock_t* InvalidDynablock(dynablock_t* db, int need_lock) +{ + if(db) { + if(db->gone) + return NULL; // already in the process of deletion! + dynarec_log(LOG_DEBUG, "InvalidDynablock(%p), db->block=%p x64=%p:%p already gone=%d\n", db, db->block, db->x64_addr, db->x64_addr+db->x64_size-1, db->gone); + if(need_lock) + mutex_lock(&my_context->mutex_dyndump); + // remove jumptable + setJumpTableDefault64(db->x64_addr); + db->done = 0; + db->gone = 1; + if(need_lock) + mutex_unlock(&my_context->mutex_dyndump); + } + return db; +} + +void FreeInvalidDynablock(dynablock_t* db, int need_lock) +{ + if(db) { + if(!db->gone) + return; // already in the process of deletion! + dynarec_log(LOG_DEBUG, "FreeInvalidDynablock(%p), db->block=%p x64=%p:%p already gone=%d\n", db, db->block, db->x64_addr, db->x64_addr+db->x64_size-1, db->gone); + if(need_lock) + mutex_lock(&my_context->mutex_dyndump); + FreeDynarecMap((uintptr_t)db->actual_block); + customFree(db); + if(need_lock) + mutex_unlock(&my_context->mutex_dyndump); + } +} + void FreeDynablock(dynablock_t* db, int need_lock) { if(db) { @@ -50,6 +83,8 @@ void FreeDynablock(dynablock_t* db, int need_lock) dynarec_log(LOG_DEBUG, " -- FreeDyrecMap(%p, %d)\n", db->actual_block, db->size); db->done = 0; db->gone = 1; + if(db->previous) + FreeInvalidDynablock(db->previous, 0); FreeDynarecMap((uintptr_t)db->actual_block); customFree(db); if(need_lock) @@ -57,14 +92,26 @@ void FreeDynablock(dynablock_t* db, int need_lock) } } + + void MarkDynablock(dynablock_t* db) { if(db) { - if(db->need_test) - return; // already done dynarec_log(LOG_DEBUG, "MarkDynablock %p %p-%p\n", db, db->x64_addr, db->x64_addr+db->x64_size-1); - db->need_test = 1; - setJumpTableIfRef64(db->x64_addr, db->jmpnext, db->block); + if(!setJumpTableIfRef64(db->x64_addr, db->jmpnext, db->block)) { + dynablock_t* old = db; + db = getDB((uintptr_t)old->x64_addr); + if(!old->gone && db!=old) { + printf_log(LOG_INFO, "Warning, couldn't mark block as dirty for %p, block=%p, current_block=%p\n", old->x64_addr, old, db); + // the block is lost, need to invalidate it... + old->gone = 1; + old->done = 0; + if(!db || db->previous) + FreeInvalidDynablock(old, 1); + else + db->previous = old; + } + } } } @@ -78,7 +125,7 @@ static int IntervalIntersects(uintptr_t start1, uintptr_t end1, uintptr_t start2 static int MarkedDynablock(dynablock_t* db) { if(db) { - if(db->need_test) + if(getNeedTest((uintptr_t)db->x64_addr)) return 1; // already done } return 0; @@ -90,9 +137,8 @@ void MarkRangeDynablock(dynablock_t* db, uintptr_t addr, uintptr_t size) if(!db) return; dynarec_log(LOG_DEBUG, "MarkRangeDynablock %p-%p .. startdb=%p, sizedb=%p\n", (void*)addr, (void*)addr+size-1, (void*)db->x64_addr, (void*)db->x64_size); - if(!MarkedDynablock(db)) - if(IntervalIntersects((uintptr_t)db->x64_addr, (uintptr_t)db->x64_addr+db->x64_size-1, addr, addr+size+1)) - MarkDynablock(db); + if(IntervalIntersects((uintptr_t)db->x64_addr, (uintptr_t)db->x64_addr+db->x64_size-1, addr, addr+size+1)) + MarkDynablock(db); } int FreeRangeDynablock(dynablock_t* db, uintptr_t addr, uintptr_t size) @@ -153,13 +199,11 @@ static dynablock_t* internalDBGetBlock(x64emu_t* emu, uintptr_t addr, uintptr_t if(mutex_trylock(&my_context->mutex_dyndump)) // FillBlock not available for now return NULL; } - } - - block = getDB(addr); // just in case - if(block) { - if(need_lock) + block = getDB(addr); // just in case + if(block) { mutex_unlock(&my_context->mutex_dyndump); - return block; + return block; + } } block = AddNewDynablock(addr); @@ -184,9 +228,10 @@ static dynablock_t* internalDBGetBlock(x64emu_t* emu, uintptr_t addr, uintptr_t if(blocksz>my_context->max_db_size) my_context->max_db_size = blocksz; // fill-in jumptable - if(!addJumpTableIfDefault64(block->x64_addr, block->block)) { + if(!addJumpTableIfDefault64(block->x64_addr, block->dirty?block->jmpnext:block->block)) { FreeDynablock(block, 0); block = getDB(addr); + MarkDynablock(block); // just in case... } else { if(block->x64_size) block->done = 1; // don't validate the block if the size is null, but keep the block @@ -203,7 +248,9 @@ static dynablock_t* internalDBGetBlock(x64emu_t* emu, uintptr_t addr, uintptr_t dynablock_t* DBGetBlock(x64emu_t* emu, uintptr_t addr, int create) { dynablock_t *db = internalDBGetBlock(emu, addr, addr, create, 1); - if(db && db->done && db->block && db->need_test) { + if(db && db->done && db->block && getNeedTest(addr)) { + if(db->always_test) + sched_yield(); // just calm down... if(AreaInHotPage((uintptr_t)db->x64_addr, (uintptr_t)db->x64_addr + db->x64_size - 1)) { emu->test.test = 0; if(box64_dynarec_fastpage) { @@ -221,25 +268,30 @@ dynablock_t* DBGetBlock(x64emu_t* emu, uintptr_t addr, int create) } } uint32_t hash = X31_hash_code(db->x64_addr, db->x64_size); - if(mutex_trylock(&my_context->mutex_dyndump)) { - dynarec_log(LOG_DEBUG, "mutex_dyndump not available when trying to validate block %p from %p:%p (hash:%X) for %p\n", db, db->x64_addr, db->x64_addr+db->x64_size-1, db->hash, (void*)addr); - return NULL; - } + 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->x64_addr, db->x64_addr+db->x64_size-1, hash, db->hash, (void*)addr); // Free db, it's now invalid! - FreeDynablock(db, 0); + dynablock_t* old = InvalidDynablock(db, need_lock); // start again... (will create a new block) - db = internalDBGetBlock(emu, addr, addr, create, 0); + db = internalDBGetBlock(emu, addr, addr, create, need_lock); + if(db) { + if(db->previous) + FreeInvalidDynablock(db->previous, need_lock); + db->previous = old; + } else + FreeInvalidDynablock(old, need_lock); } else { - db->need_test = 0; dynarec_log(LOG_DEBUG, "Validating block %p from %p:%p (hash:%X) for %p\n", db, db->x64_addr, db->x64_addr+db->x64_size-1, db->hash, (void*)addr); protectDB((uintptr_t)db->x64_addr, db->x64_size); // fill back jumptable - setJumpTableIfRef64(db->x64_addr, db->block, db->jmpnext); + if(isprotectedDB((uintptr_t)db->x64_addr, db->x64_size) && !db->always_test) { + setJumpTableIfRef64(db->x64_addr, db->block, db->jmpnext); + } } - mutex_unlock(&my_context->mutex_dyndump); + if(!need_lock) + mutex_unlock(&my_context->mutex_dyndump); } if(!db || !db->block || !db->done) emu->test.test = 0; @@ -251,26 +303,33 @@ dynablock_t* DBAlternateBlock(x64emu_t* emu, uintptr_t addr, uintptr_t filladdr) dynarec_log(LOG_DEBUG, "Creating AlternateBlock at %p for %p\n", (void*)addr, (void*)filladdr); int create = 1; dynablock_t *db = internalDBGetBlock(emu, addr, filladdr, create, 1); - if(db && db->done && db->block && db->need_test) { - if(mutex_trylock(&my_context->mutex_dyndump)) { - emu->test.test = 0; - return NULL; - } + if(db && db->done && db->block && getNeedTest(filladdr)) { + if(db->always_test) + sched_yield(); // just calm down... + int need_lock = mutex_trylock(&my_context->mutex_dyndump); uint32_t hash = X31_hash_code(db->x64_addr, db->x64_size); if(hash!=db->hash) { db->done = 0; // invalidating the block dynarec_log(LOG_DEBUG, "Invalidating alt block %p from %p:%p (hash:%X/%X) for %p\n", db, db->x64_addr, db->x64_addr+db->x64_size, hash, db->hash, (void*)addr); // Free db, it's now invalid! - FreeDynablock(db, 0); + dynablock_t* old = InvalidDynablock(db, need_lock); // start again... (will create a new block) - db = internalDBGetBlock(emu, addr, filladdr, create, 0); + db = internalDBGetBlock(emu, addr, filladdr, create, need_lock); + if(db) { + if(db->previous) + FreeInvalidDynablock(db->previous, need_lock); + db->previous = old; + } else + FreeInvalidDynablock(old, need_lock); } else { - db->need_test = 0; protectDB((uintptr_t)db->x64_addr, db->x64_size); // fill back jumptable - addJumpTableIfDefault64(db->x64_addr, db->block); + if(isprotectedDB((uintptr_t)db->x64_addr, db->x64_size) && !db->always_test) { + setJumpTableIfRef64(db->x64_addr, db->block, db->jmpnext); + } } - mutex_unlock(&my_context->mutex_dyndump); + if(!need_lock) + mutex_unlock(&my_context->mutex_dyndump); } if(!db || !db->block || !db->done) emu->test.test = 0; diff --git a/src/dynarec/dynablock_private.h b/src/dynarec/dynablock_private.h index dbe8c502..18666e04 100755 --- a/src/dynarec/dynablock_private.h +++ b/src/dynarec/dynablock_private.h @@ -9,14 +9,15 @@ typedef struct instsize_s { typedef struct dynablock_s { void* block; // block-sizeof(void*) == self void* actual_block; // the actual start of the block (so block-sizeof(void*)) + struct dynablock_s* previous; // a previous block that might need to be freed int size; void* x64_addr; uintptr_t x64_size; uint32_t hash; - uint8_t need_test; uint8_t done; uint8_t gone; - uint8_t dummy; + uint8_t always_test; + uint8_t dirty; // if need to be tested as soon as it's created int isize; instsize_t* instsize; void* jmpnext; // a branch jmpnext code when block is marked diff --git a/src/dynarec/dynarec_native.c b/src/dynarec/dynarec_native.c index c57b7d64..64d28342 100755 --- a/src/dynarec/dynarec_native.c +++ b/src/dynarec/dynarec_native.c @@ -267,7 +267,7 @@ void addInst(instsize_t* insts, size_t* size, int x64_size, int native_size) } // add a value to table64 (if needed) and gives back the imm19 to use in LDR_literal -int Table64(dynarec_native_t *dyn, uint64_t val) +int Table64(dynarec_native_t *dyn, uint64_t val, int pass) { // find the value if already present int idx = -1; @@ -278,10 +278,12 @@ int Table64(dynarec_native_t *dyn, uint64_t val) if(idx==-1) { if(dyn->table64size == dyn->table64cap) { dyn->table64cap+=16; - dyn->table64 = (uint64_t*)customRealloc(dyn->table64, dyn->table64cap * sizeof(uint64_t)); + if(pass<3) // do not resize on pass3, it's not the same type of memory anymore + dyn->table64 = (uint64_t*)customRealloc(dyn->table64, dyn->table64cap * sizeof(uint64_t)); } idx = dyn->table64size++; - dyn->table64[idx] = val; + if(dyn->table64size <= dyn->table64cap) + dyn->table64[idx] = val; } // calculate offset int delta = dyn->tablestart + idx*sizeof(uint64_t) - (uintptr_t)dyn->block; @@ -381,19 +383,17 @@ void CancelBlock64(int need_lock) mutex_lock(&my_context->mutex_dyndump); dynarec_native_t* helper = (dynarec_native_t*)current_helper; current_helper = NULL; - if(!helper) { - if(need_lock) - mutex_unlock(&my_context->mutex_dyndump); - return; + if(helper) { + customFree(helper->next); + customFree(helper->insts); + customFree(helper->predecessor); + if(helper->table64 && (helper->table64!=(uint64_t*)helper->tablestart)) + customFree(helper->table64); + if(helper->dynablock && helper->dynablock->actual_block) { + FreeDynarecMap((uintptr_t)helper->dynablock->actual_block); + helper->dynablock->actual_block = NULL; + } } - customFree(helper->next); - customFree(helper->insts); - customFree(helper->predecessor); - customFree(helper->table64); - if(helper->dynablock && helper->dynablock->actual_block) - FreeDynarecMap((uintptr_t)helper->dynablock->actual_block); - else if(helper->dynablock && helper->block) - FreeDynarecMap((uintptr_t)helper->block-sizeof(void*)); if(need_lock) mutex_unlock(&my_context->mutex_dyndump); } @@ -421,7 +421,6 @@ void* CreateEmptyBlock(dynablock_t* block, uintptr_t addr) { *(dynablock_t**)actual_p = block; *(void**)(p+2*sizeof(void*)) = native_epilog; CreateJmpNext(block->jmpnext, p+2*sizeof(void*)); - block->need_test = 0; // all done... __clear_cache(actual_p, actual_p+sz); // need to clear the cache before execution... return block; @@ -491,6 +490,8 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr) { if(helper.insts[i].x64.jmp) { uintptr_t j = helper.insts[i].x64.jmp; if(j<start || j>=end || j==helper.insts[i].x64.addr) { + if(j==helper.insts[i].x64.addr) // if there is a loop on some opcode, make the block "always to tested" + helper.always_test = 1; helper.insts[i].x64.jmp_insts = -1; helper.insts[i].x64.need_after |= X_PEND; } else { @@ -525,7 +526,7 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr) { size_t sz = sizeof(void*) + native_size + helper.table64size*sizeof(uint64_t) + 4*sizeof(void*) + insts_rsize; // dynablock_t* block (arm insts) table64 jmpnext code instsize void* actual_p = (void*)AllocDynarecMap(sz); - void* p = actual_p + sizeof(void*); + void* p = (void*)(((uintptr_t)actual_p) + sizeof(void*)); void* next = p + native_size + helper.table64size*sizeof(uint64_t); void* instsize = next + 4*sizeof(void*); if(actual_p==NULL) { @@ -534,11 +535,16 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr) { return NULL; } helper.block = p; + block->actual_block = actual_p; helper.native_start = (uintptr_t)p; helper.tablestart = helper.native_start + native_size; + helper.jmp_next = (uintptr_t)next+sizeof(void*); helper.insts_size = 0; // reset helper.instsize = (instsize_t*)instsize; *(dynablock_t**)actual_p = block; + helper.table64cap = helper.table64size; + customFree(helper.table64); + helper.table64 = (uint64_t*)helper.tablestart; // pass 3, emit (log emit native opcode) if(box64_dynarec_dump) { dynarec_log(LOG_NONE, "%s%04d|Emitting %zu bytes for %u x64 bytes", (box64_dynarec_dump>1)?"\e[01;36m":"", GetTID(), helper.native_size, helper.isize); @@ -550,43 +556,24 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr) { helper.native_size = 0; helper.table64size = 0; // reset table64 (but not the cap) native_pass3(&helper, addr); - if((oldnativesize!=helper.native_size) || (oldtable64size<helper.table64size)) { - printf_log(LOG_NONE, "BOX64: Warning, size difference in block between pass2 (%zu) & pass3 (%zu)!\n", sz, helper.native_size+helper.table64size*8); - uint8_t *dump = (uint8_t*)helper.start; - printf_log(LOG_NONE, "Dump of %d x64 opcodes:\n", helper.size); - for(int i=0; i<helper.size; ++i) { - printf_log(LOG_NONE, "%p:", dump); - for(; dump<(uint8_t*)helper.insts[i+1].x64.addr; ++dump) - printf_log(LOG_NONE, " %02X", *dump); - printf_log(LOG_NONE, "\t%d -> %d\n", helper.insts[i].size2, helper.insts[i].size); - } - printf_log(LOG_NONE, "Table64 \t%d -> %d\n", oldtable64size*8, helper.table64size*8); - printf_log(LOG_NONE, " ------------\n"); - //TODO: Cancel block and return empty one - } - // add table64 if needed - if(helper.table64size) { - memcpy((void*)helper.tablestart, helper.table64, helper.table64size*8); - } // keep size of instructions for signal handling block->instsize = instsize; // ok, free the helper now customFree(helper.insts); helper.insts = NULL; - customFree(helper.table64); helper.table64 = NULL; helper.instsize = NULL; customFree(helper.predecessor); helper.predecessor = NULL; block->size = sz; block->isize = helper.size; - block->actual_block = actual_p; block->block = p; block->jmpnext = next+sizeof(void*); + block->always_test = helper.always_test; + block->dirty = block->always_test; *(dynablock_t**)next = block; *(void**)(next+3*sizeof(void*)) = native_next; CreateJmpNext(block->jmpnext, next+3*sizeof(void*)); - block->need_test = 0; //block->x64_addr = (void*)start; block->x64_size = end-start; // all done... @@ -599,10 +586,25 @@ void* FillBlock64(dynablock_t* block, uintptr_t addr) { CancelBlock64(0); return NULL; } + if((oldnativesize!=helper.native_size) || (oldtable64size<helper.table64size)) { + printf_log(LOG_NONE, "BOX64: Warning, size difference in block between pass2 (%zu) & pass3 (%zu)!\n", sz, helper.native_size+helper.table64size*8); + uint8_t *dump = (uint8_t*)helper.start; + printf_log(LOG_NONE, "Dump of %d x64 opcodes:\n", helper.size); + for(int i=0; i<helper.size; ++i) { + printf_log(LOG_NONE, "%p:", dump); + for(; dump<(uint8_t*)helper.insts[i+1].x64.addr; ++dump) + printf_log(LOG_NONE, " %02X", *dump); + printf_log(LOG_NONE, "\t%d -> %d\n", helper.insts[i].size2, helper.insts[i].size); + } + printf_log(LOG_NONE, "Table64 \t%d -> %d\n", oldtable64size*8, helper.table64size*8); + printf_log(LOG_NONE, " ------------\n"); + CancelBlock64(0); + return NULL; + } if(!isprotectedDB(addr, end-addr)) { - dynarec_log(LOG_DEBUG, "Warning, block unprotected while being processed %p:%ld, cancelling\n", block->x64_addr, block->x64_size); + dynarec_log(LOG_DEBUG, "Warning, block unprotected while being processed %p:%ld, marking as need_test\n", block->x64_addr, block->x64_size); AddHotPage(addr); - block->need_test = 1; + block->dirty = 1; //protectDB(addr, end-addr); } current_helper = NULL; diff --git a/src/dynarec/rv64/dynarec_rv64_pass2.h b/src/dynarec/rv64/dynarec_rv64_pass2.h index 176d512d..d71f9180 100644 --- a/src/dynarec/rv64/dynarec_rv64_pass2.h +++ b/src/dynarec/rv64/dynarec_rv64_pass2.h @@ -14,5 +14,5 @@ } #define INST_EPILOG dyn->insts[ninst].epilog = dyn->native_size; #define INST_NAME(name) -#define TABLE64(A, V) {Table64(dyn, (V)); EMIT(0); EMIT(0);} -#define FTABLE64(A, V) {mmx87_regs_t v = {.d = V}; Table64(dyn, v.q); EMIT(0); EMIT(0);} \ No newline at end of file +#define TABLE64(A, V) {Table64(dyn, (V), 2); EMIT(0); EMIT(0);} +#define FTABLE64(A, V) {mmx87_regs_t v = {.d = V}; Table64(dyn, v.q, 2); EMIT(0); EMIT(0);} \ No newline at end of file diff --git a/src/dynarec/rv64/dynarec_rv64_pass3.h b/src/dynarec/rv64/dynarec_rv64_pass3.h index 24ab0dfa..dafef0c5 100644 --- a/src/dynarec/rv64/dynarec_rv64_pass3.h +++ b/src/dynarec/rv64/dynarec_rv64_pass3.h @@ -19,5 +19,5 @@ #define INST_EPILOG #define INST_NAME(name) inst_name_pass3(dyn, ninst, name) -#define TABLE64(A, V) {int val64offset = Table64(dyn, (V)); MESSAGE(LOG_DUMP, " Table64: 0x%lx\n", (V)); AUIPC(A, SPLIT20(val64offset)); LD(A, A, SPLIT12(val64offset));} -#define FTABLE64(A, V) {mmx87_regs_t v = {.d = V}; int val64offset = Table64(dyn, v.q); MESSAGE(LOG_DUMP, " FTable64: %g\n", v.d); AUIPC(x1, SPLIT20(val64offset)); FLD(A, x1, SPLIT12(val64offset));} +#define TABLE64(A, V) {int val64offset = Table64(dyn, (V), 3); MESSAGE(LOG_DUMP, " Table64: 0x%lx\n", (V)); AUIPC(A, SPLIT20(val64offset)); LD(A, A, SPLIT12(val64offset));} +#define FTABLE64(A, V) {mmx87_regs_t v = {.d = V}; int val64offset = Table64(dyn, v.q, 3); MESSAGE(LOG_DUMP, " FTable64: %g\n", v.d); AUIPC(x1, SPLIT20(val64offset)); FLD(A, x1, SPLIT12(val64offset));} diff --git a/src/dynarec/rv64/dynarec_rv64_private.h b/src/dynarec/rv64/dynarec_rv64_private.h index 3d6205d9..01657427 100644 --- a/src/dynarec/rv64/dynarec_rv64_private.h +++ b/src/dynarec/rv64/dynarec_rv64_private.h @@ -96,6 +96,7 @@ typedef struct dynarec_rv64_s { int table64size;// size of table (will be appended at end of executable code) int table64cap; uintptr_t tablestart; + uintptr_t jmp_next; // address of the jump_next address flagcache_t f; extcache_t e; // cache for the 10..31 0..1 double reg from fpu, plus x87 stack delta uintptr_t* next; // variable array of "next" jump address @@ -111,6 +112,7 @@ typedef struct dynarec_rv64_s { uintptr_t forward_to; // address of the next jump to (to check if everything is ok) int32_t forward_size; // size at the forward point int forward_ninst; // ninst at the forward point + uint8_t always_test; } dynarec_rv64_t; // convert idx (0..24) to reg index (10..31 0..1) @@ -123,7 +125,7 @@ uintptr_t get_closest_next(dynarec_rv64_t *dyn, uintptr_t addr); int is_nops(dynarec_rv64_t *dyn, uintptr_t addr, int n); int is_instructions(dynarec_rv64_t *dyn, uintptr_t addr, int n); -int Table64(dynarec_rv64_t *dyn, uint64_t val); // add a value to etable64 (if needed) and gives back the imm19 to use in LDR_literal +int Table64(dynarec_rv64_t *dyn, uint64_t val, int pass); // add a value to etable64 (if needed) and gives back the imm19 to use in LDR_literal void CreateJmpNext(void* addr, void* next); diff --git a/src/include/custommem.h b/src/include/custommem.h index 5f9164f3..e7623db2 100644 --- a/src/include/custommem.h +++ b/src/include/custommem.h @@ -26,6 +26,7 @@ void addDBFromAddressRange(uintptr_t addr, size_t size); void cleanDBFromAddressRange(uintptr_t addr, size_t size, int destroy); dynablock_t* getDB(uintptr_t idx); +int getNeedTest(uintptr_t idx); int addJumpTableIfDefault64(void* addr, void* jmp); // return 1 if write was succesfull int setJumpTableIfRef64(void* addr, void* jmp, void* ref); // return 1 if write was succesfull void setJumpTableDefault64(void* addr); diff --git a/src/include/dynablock.h b/src/include/dynablock.h index 1868deea..4e9d0b36 100755 --- a/src/include/dynablock.h +++ b/src/include/dynablock.h @@ -9,6 +9,8 @@ void FreeDynablock(dynablock_t* db, int need_lock); void MarkDynablock(dynablock_t* db); void MarkRangeDynablock(dynablock_t* db, uintptr_t addr, uintptr_t size); int FreeRangeDynablock(dynablock_t* db, uintptr_t addr, uintptr_t size); +void FreeInvalidDynablock(dynablock_t* db, int need_lock); +dynablock_t* InvalidDynablock(dynablock_t* db, int need_lock); dynablock_t* FindDynablockFromNativeAddress(void* addr); // defined in box64context.h diff --git a/src/libtools/signals.c b/src/libtools/signals.c index 3e9bbce5..263711f2 100755 --- a/src/libtools/signals.c +++ b/src/libtools/signals.c @@ -939,7 +939,7 @@ void my_box64signalhandler(int32_t sig, siginfo_t* info, void * ucntx) } // access error, unprotect the block (and mark them dirty) unprotectDB((uintptr_t)addr, 1, 1); // unprotect 1 byte... But then, the whole page will be unprotected - if(db && ((addr>=db->x64_addr && addr<(db->x64_addr+db->x64_size)) || db->need_test)) { + if(db && ((addr>=db->x64_addr && addr<(db->x64_addr+db->x64_size)) || getNeedTest((uintptr_t)db->x64_addr))) { // dynablock got auto-dirty! need to get out of it!!! emu_jmpbuf_t* ejb = GetJmpBuf(); if(ejb->jmpbuf_ok) { @@ -998,6 +998,8 @@ void my_box64signalhandler(int32_t sig, siginfo_t* info, void * ucntx) if(db && db->x64_addr>= addr && (db->x64_addr+db->x64_size)<addr) { dynarec_log(LOG_INFO, "Warning, addr inside current dynablock!\n"); } + // mark stuff as unclean + cleanDBFromAddressRange(((uintptr_t)addr)&~(box64_pagesize-1), box64_pagesize, 0); static void* glitch_pc = NULL; static void* glitch_addr = NULL; static int glitch_prot = 0; @@ -1057,10 +1059,13 @@ dynarec_log(/*LOG_DEBUG*/LOG_INFO, "Repeated SIGSEGV with Access error on %p for printf_log(log_minimum, "%04d|Double %s (code=%d, pc=%p, addr=%p)!\n", GetTID(), signame, old_code, old_pc, old_addr); exit(-1); } else { - if(sig==SIGSEGV && info->si_code==2 && ((prot&~PROT_DYN)==5 || (prot&~PROT_DYN)==7)) { + if((sig==SIGSEGV) && (info->si_code == SEGV_ACCERR) && ((prot&~PROT_CUSTOM)==5 || (prot&~PROT_CUSTOM)==7)) { static uintptr_t old_addr = 0; printf_log(/*LOG_DEBUG*/LOG_INFO, "Strange SIGSEGV with Access error on %p for %p, db=%p, prot=0x%x (old_addr=%p)\n", pc, addr, db, prot, (void*)old_addr); - if(old_addr!=(uintptr_t)addr) { + #ifdef DYNAREC + cleanDBFromAddressRange(((uintptr_t)addr)&~(box64_pagesize-1), box64_pagesize, 0); + #endif + if(old_addr!=(uintptr_t)addr || getMmapped((uintptr_t)addr)) { old_addr = (uintptr_t)addr; refreshProtection(old_addr); relockMutex(Locks); @@ -1222,7 +1227,7 @@ exit(-1); prot, db, db?db->block:0, db?(db->block+db->size):0, db?db->x64_addr:0, db?(db->x64_addr+db->x64_size):0, getAddrFunctionName((uintptr_t)(db?db->x64_addr:0)), - (db?db->need_test:0)?"need_stest":"clean", db?db->hash:0, hash, + (db?getNeedTest((uintptr_t)db->x64_addr):0)?"need_stest":"clean", db?db->hash:0, hash, (void*)my_context->signals[sig]); #if defined(ARM64) if(db) { diff --git a/system/box64.box64rc b/system/box64.box64rc index 765b2132..8d8b641d 100644 --- a/system/box64.box64rc +++ b/system/box64.box64rc @@ -72,6 +72,12 @@ BOX64_DYNAREC_CALLRET=1 [pressure-vessel-wrap] BOX64_NOGTK=1 +[ProjectZomboid64] +# This one is still a bit unstable. This might help, but will also slowdown emulation +BOX64_DYNAREC_STRONGMEM=2 +BOX64_DYNAREC_BIGBLOCKS=0 +BOX64_DYNAREC_SAFEFLAGS=2 + [Soma.bin.x86_64] # This is needed or the physics engine will not behave correctly BOX64_DYNAREC_FASTROUND=0 |