diff --git a/CMakeLists.txt b/CMakeLists.txt index 6503cf52..86f9519c 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -572,6 +572,7 @@ if(ARM_DYNAREC) "${BOX86_ROOT}/src/dynarec/dynarec_arm.c" "${BOX86_ROOT}/src/dynarec/dynarec_arm_functions.c" + "${BOX86_ROOT}/src/dynarec/dynarec_arm_jmpnext.c" "${BOX86_ROOT}/src/dynarec/arm_printer.c" "${BOX86_ROOT}/src/emu/x86test.c" diff --git a/docs/USAGE.md b/docs/USAGE.md index 3198d7b1..3495bf7a 100755 --- a/docs/USAGE.md +++ b/docs/USAGE.md @@ -175,11 +175,21 @@ Handling of HotPage (Page beeing both executed and writen) * 0 : Don't track hotpage * 1-255 : Trak HotPage, and disable execution of a page beeing writen for N attempts (default is 16) +#### BOX86_DYNAREC_FASTPAGE * +Will use a faster handling of HotPage (Page being both executed and written) +* 0 : use regular hotpage (Default) +* 1 : Use faster hotpage, taking the risk of running obsolete JIT code (might be faster, but more prone to crash) + #### BOX86_DYNAREC_BLEEDING_EDGE * Detect MonoBleedingEdge and apply conservative settings * 0 : Don't detect MonoBleedingEdge * 1 : Detect MonoBleedingEdge, and apply BIGBLOCK=0 STRONGMEM=1 if detected (Default) +#### BOX86_DYNAREC_WAIT * +Behavior with FillBlock is not availble (FillBlock build Dynarec blocks and is not multithreaded) +* 0 : Dynarec will not wait for FillBlock to ready and use Interpreter instead (might speedup a bit massive multithread or JIT programs) +* 1 : Dynarec will wait for FillBlock to be ready (Default) + #### BOX86_SSE_FLUSHTO0 * Handling of SSE Flush to 0 flags * 0 : Just track the flag (Default) diff --git a/src/custommem.c b/src/custommem.c index 56f3fef9..3e680155 100644 --- a/src/custommem.c +++ b/src/custommem.c @@ -4,6 +4,7 @@ #include #include #include +#include #include "box86context.h" #include "elfloader.h" @@ -24,6 +25,7 @@ #include "threads.h" #ifdef DYNAREC #include "dynablock.h" +#include "dynarec/dynablock_private.h" #include "dynarec/arm_lock_helper.h" #include "khash.h" @@ -31,16 +33,22 @@ //#define USE_MMAP_MORE // init inside dynablocks.c -KHASH_MAP_INIT_INT(dynablocks, dynablock_t*) -static dynablocklist_t* dynmap[DYNAMAP_SIZE] = {0}; // 4G of memory mapped by 4K block static mmaplist_t *mmaplist = NULL; +//#define TRACE_MEMSTAT +#ifdef TRACE_MEMSTAT +static size_t jmptbl_allocated = 0, jmptbl_allocated1 = 0; +#endif static int mmapsize = 0; -static kh_dynablocks_t *dblist_oversized; // store the list of oversized dynablocks (normal sized are inside mmaplist) -static uintptr_t *box86_jumptable[JMPTABL_SIZE]; +static uintptr_t *box86_jmptbl[JMPTABL_SIZE]; static uintptr_t box86_jmptbl_default[1<prev.size) - sizeof(blockmark_t)) #define LAST_BLOCK(b, s) (blockmark_t*)(((uintptr_t)(b)+(s))-sizeof(blockmark_t)) -#ifdef DYNAREC static void printBlock(blockmark_t* b, void* start) { printf_log(LOG_INFO, "========== Block is:\n"); @@ -105,7 +107,6 @@ static void printBlock(blockmark_t* b, void* start) } while(b->next.x32); printf_log(LOG_INFO, "===================\n"); } -#endif // get first subblock free in block. Return NULL if no block, else first subblock free (mark included), filling size static void* getFirstBlock(void* block, size_t maxsize, size_t* size, void* start) @@ -123,12 +124,29 @@ static void* getFirstBlock(void* block, size_t maxsize, size_t* size, void* star return NULL; } +static void* getNextFreeBlock(void* block) +{ + blockmark_t *m = (blockmark_t*)block; + while (m->next.fill) { + m = NEXT_BLOCK(m); + }; + return m; +} +static void* getPrevFreeBlock(void* block) +{ + blockmark_t *m = (blockmark_t*)block; + do { + m = PREV_BLOCK(m); + } while (m->next.fill); + return m; +} + static size_t getMaxFreeBlock(void* block, size_t block_size, void* start) { // get start of block if(start) { blockmark_t *m = (blockmark_t*)start; - size_t maxsize = 0; + int maxsize = 0; while(m->next.x32) { // while there is a subblock if(!m->next.fill && m->next.size>maxsize) { maxsize = m->next.size; @@ -138,7 +156,7 @@ static size_t getMaxFreeBlock(void* block, size_t block_size, void* start) return (maxsize>=sizeof(blockmark_t))?maxsize:0; } else { blockmark_t *m = LAST_BLOCK(block, block_size); // start with the end - size_t maxsize = 0; + int maxsize = 0; while(m->prev.x32) { // while there is a subblock if(!m->prev.fill && m->prev.size>maxsize) { maxsize = m->prev.size; @@ -253,19 +271,43 @@ static size_t sizeBlock(void* sub) return s->next.size; } +#define THRESHOLD (128-2*sizeof(blockmark_t)) + +static size_t roundSize(size_t size) +{ + if(!size) + return size; + size = (size+7)&~7LL; // 8 bytes align in size + + if(size=size) { size_t rsize = 0; - sub = getFirstBlock(p_blocks[i].block, size, &rsize, NULL); + sub = getFirstBlock(p_blocks[i].block, size, &rsize, p_blocks[i].first); if(sub) { + if(rsize-sizeallocsize) - allocsize = size+2*sizeof(blockmark_t); - #ifdef USE_MMAP_MORE + if(n_blocks>c_blocks) { + c_blocks += 4; + p_blocks = (blocklist_t*)box_realloc(p_blocks, c_blocks*sizeof(blocklist_t)); + } + size_t allocsize = (fullsize>MMAPSIZE)?fullsize:MMAPSIZE; + #ifdef USE_MMAP void* p = mmap(NULL, allocsize, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); memset(p, 0, allocsize); - setProtection((uintptr_t)p, allocsize, PROT_READ|PROT_WRITE); #else void* p = box_calloc(1, allocsize); #endif +#ifdef TRACE_MEMSTAT + customMalloc_allocated += allocsize; +#endif p_blocks[i].block = p; + p_blocks[i].first = p; p_blocks[i].size = allocsize; // setup marks blockmark_t* m = (blockmark_t*)p; @@ -303,7 +349,7 @@ void* customMalloc(size_t size) } void* customCalloc(size_t n, size_t size) { - size_t newsize = n*size; + size_t newsize = roundSize(n*size); void* ret = customMalloc(newsize); memset(ret, 0, newsize); return ret; @@ -312,6 +358,7 @@ void* customRealloc(void* p, size_t size) { if(!p) return customMalloc(size); + size = roundSize(size); uintptr_t addr = (uintptr_t)p; mutex_lock(&mutex_blocks); for(int i=0; i(uintptr_t)p_blocks[i].block) && (addr<((uintptr_t)p_blocks[i].block+p_blocks[i].size))) { void* sub = (void*)(addr-sizeof(blockmark_t)); + void* n = NEXT_BLOCK((blockmark_t*)sub); size_t newfree = freeBlock(p_blocks[i].block, sub, NULL); + if(sub<=p_blocks[i].first) + p_blocks[i].first = getPrevFreeBlock(n); if(p_blocks[i].maxfree < newfree) p_blocks[i].maxfree = newfree; mutex_unlock(&mutex_blocks); return; @@ -357,390 +409,332 @@ void customFree(void* p) } #ifdef DYNAREC -typedef struct mmapchunk_s { - void* block; - int maxfree; - size_t size; - kh_dynablocks_t* dblist; - uint8_t* helper; - void* first; // first free block, to speed up things - uint8_t lock; // don't try to add stuff on locked block -} mmapchunk_t; +void arm_next(void); + #define NCHUNK 64 typedef struct mmaplist_s { - mmapchunk_t chunks[NCHUNK]; + blocklist_t chunks[NCHUNK]; mmaplist_t* next; } mmaplist_t; -mmapchunk_t* addChunk(int mmapsize) { - if(!mmaplist) - mmaplist = (mmaplist_t*)box_calloc(1, sizeof(mmaplist_t)); - mmaplist_t* head = mmaplist; - int i = mmapsize; - while(1) { - if(i>=NCHUNK) { - i-=NCHUNK; - if(!head->next) { - head->next = (mmaplist_t*)box_calloc(1, sizeof(mmaplist_t)); - } - head=head->next; - } else - return &head->chunks[i]; - } -} - -uintptr_t FindFreeDynarecMap(dynablock_t* db, int size) +dynablock_t* FindDynablockFromNativeAddress(void* p) { - // look for free space - void* sub = NULL; - mmaplist_t* head = mmaplist; - int i = mmapsize; - while(head) { - const int n = (i>NCHUNK)?NCHUNK:i; - i-=n; - for(int i=0; ichunks[i]; - if(chunk->maxfree>=size+sizeof(blockmark_t) && !arm_lock_incif0b(&chunk->lock)) { - size_t rsize = 0; - sub = getFirstBlock(chunk->block, size, &rsize, chunk->first); - if(sub) { - uintptr_t ret = (uintptr_t)allocBlock(chunk->block, sub, size, &chunk->first); - if(rsize==chunk->maxfree) { - chunk->maxfree = getMaxFreeBlock(chunk->block, chunk->size, chunk->first); - } - kh_dynablocks_t *blocks = chunk->dblist; - if(!blocks) { - blocks = chunk->dblist = kh_init(dynablocks); - kh_resize(dynablocks, blocks, 64); - } - khint_t k; - int r; - k = kh_put(dynablocks, blocks, (uintptr_t)ret, &r); - kh_value(blocks, k) = db; - int size255=(size<256)?size:255; - for(size_t j=0; jhelper[(uintptr_t)ret-(uintptr_t)(chunk->block)+j] = j; - if(size!=size255) - memset(&chunk->helper[(uintptr_t)ret-(uintptr_t)(chunk->block)+256], -1, size-255); - arm_lock_decifnot0b(&chunk->lock); - return ret; - } else { - printf_log(LOG_INFO, "BOX86: Warning, sub not found, corrupted %p->chunk[%d] info?\n", head, i); - arm_lock_decifnot0b(&chunk->lock); - if(box86_log >= LOG_DEBUG) - printBlock(chunk->block, chunk->first); + if(!p) + return NULL; + + uintptr_t addr = (uintptr_t)p; + + int i= 0; + mmaplist_t* list = mmaplist; + if(!list) + return NULL; + while(list) { + if ((addr>(uintptr_t)list->chunks[i].block) + && (addr<((uintptr_t)list->chunks[i].block+list->chunks[i].size))) { + blockmark_t* sub = (blockmark_t*)list->chunks[i].block; + while((uintptr_t)subaddr) { + // found it! + // self is the field of a block + return *(dynablock_t**)((uintptr_t)sub+sizeof(blockmark_t)); } + sub = n; } + return NULL; } - head = head->next; - } - return 0; -} - -uintptr_t AddNewDynarecMap(dynablock_t* db, int size) -{ - dynarec_log(LOG_DEBUG, "Ask for DynaRec Block Alloc #%zu\n", mmapsize); - mmapchunk_t* chunk = addChunk(mmapsize++); - arm_lock_incb(&chunk->lock); - #ifndef USE_MMAP - void *p = NULL; - if(posix_memalign(&p, box86_pagesize, MMAPSIZE)) { - dynarec_log(LOG_INFO, "Cannot create memory map of %d byte for dynarec block #%d\n", MMAPSIZE, i); - arm_lock_storeb(&chunk->lock, 0); - --mmapsize; - return 0; - } - mprotect(p, MMAPSIZE, PROT_READ | PROT_WRITE | PROT_EXEC); - #else - void* p = mmap(NULL, MMAPSIZE, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0); - if(p==(void*)-1) { - dynarec_log(LOG_INFO, "Cannot create memory map of %d byte for dynarec block #%d\n", MMAPSIZE, mmapsize-1); - arm_lock_storeb(&chunk->lock, 0); - --mmapsize; - return 0; - } - #endif - setProtection((uintptr_t)p, MMAPSIZE, PROT_READ | PROT_WRITE | PROT_EXEC); - - chunk->block = p; - chunk->size = MMAPSIZE; - chunk->helper = (uint8_t*)box_calloc(1, MMAPSIZE); - chunk->first = p; - // setup marks - blockmark_t* m = (blockmark_t*)p; - m->prev.x32 = 0; - m->next.fill = 0; - m->next.size = MMAPSIZE-2*sizeof(blockmark_t); - blockmark_t* n = NEXT_BLOCK(m); - n->next.x32 = 0; - n->prev.fill = 0; - n->prev.size = m->next.size; - // alloc 1st block - uintptr_t sub = (uintptr_t)allocBlock(chunk->block, p, size, &chunk->first); - chunk->maxfree = getMaxFreeBlock(chunk->block, chunk->size, chunk->first); - kh_dynablocks_t *blocks = chunk->dblist = kh_init(dynablocks); - kh_resize(dynablocks, blocks, 64); - khint_t k; - int ret; - k = kh_put(dynablocks, blocks, (uintptr_t)sub, &ret); - kh_value(blocks, k) = db; - for(int j=0; jhelper[(uintptr_t)sub-(uintptr_t)chunk->block + j] = (j<256)?j:255; - arm_lock_decifnot0b(&chunk->lock); - return sub; -} - -void ActuallyFreeDynarecMap(dynablock_t* db, uintptr_t addr, int size) -{ - if(!addr || !size) - return; - mmaplist_t* head = mmaplist; - int i = mmapsize; - while(head) { - const int n = (i>NCHUNK)?NCHUNK:i; - i-=n; - for(int i=0; ichunks[i]; - if ((addr>(uintptr_t)(chunk->block)) - && (addr<((uintptr_t)(chunk->block)+chunk->size))) { - int loopedwait = 256; - while (arm_lock_incif0b(&chunk->lock) && loopedwait) { - sched_yield(); - --loopedwait; - } - if(!loopedwait) { - printf_log(LOG_INFO, "BOX86: Warning, Free a chunk in a locked mmaplist[%d]\n", i); - //arm_lock_incb(&chunk->lock); - if(cycle_log) - print_cycle_log(LOG_INFO); - } - void* sub = (void*)(addr-sizeof(blockmark_t)); - size_t newfree = freeBlock(chunk->block, sub, &chunk->first); - if(chunk->maxfree < newfree) chunk->maxfree = newfree; - kh_dynablocks_t *blocks = chunk->dblist; - if(blocks) { - khint_t k = kh_get(dynablocks, blocks, (uintptr_t)sub); - if(k!=kh_end(blocks)) - kh_del(dynablocks, blocks, k); - memset(&chunk->helper[(uintptr_t)sub-(uintptr_t)chunk->block], 0, size); - } - arm_lock_decifnot0b(&chunk->lock); - return; - } + ++i; + if(i==NCHUNK) { + i = 0; + list = list->next; } - head = head->next; } - if(mmapsize) - dynarec_log(LOG_NONE, "Warning, block %p (size %d) not found in mmaplist for Free\n", (void*)addr, size); + return NULL; } -dynablock_t* FindDynablockFromNativeAddress(void* addr) -{ - // look in actual list - mmaplist_t* head = mmaplist; - int i = mmapsize; - while(head) { - const int n = (i>NCHUNK)?NCHUNK:i; - i-=n; - for(int i=0; ichunks[i]; - if ((uintptr_t)addr>=(uintptr_t)chunk->block - && ((uintptr_t)addr<(uintptr_t)chunk->block+chunk->size)) { - if(!chunk->helper) - return FindDynablockDynablocklist(addr, chunk->dblist); - else { - uintptr_t p = (uintptr_t)addr - (uintptr_t)chunk->block; - while(chunk->helper[p]) p -= chunk->helper[p]; - khint_t k = kh_get(dynablocks, chunk->dblist, (uintptr_t)chunk->block + p); - if(k!=kh_end(chunk->dblist)) - return kh_value(chunk->dblist, k); - return NULL; - } - } - } - head = head->next; - } - // look in oversized - return FindDynablockDynablocklist(addr, dblist_oversized); -} - -uintptr_t AllocDynarecMap(dynablock_t* db, int size) +#ifdef TRACE_MEMSTAT +static uint64_t dynarec_allocated = 0; +#endif +uintptr_t AllocDynarecMap(size_t size) { if(!size) return 0; - if(size>MMAPSIZE-2*sizeof(blockmark_t)) { - #ifndef USE_MMAP - void *p = NULL; - if(posix_memalign(&p, box86_pagesize, size)) { - dynarec_log(LOG_INFO, "Cannot create dynamic map of %d bytes\n", size); - return 0; + + size = roundSize(size); + + mmaplist_t* list = mmaplist; + if(!list) + list = mmaplist = (mmaplist_t*)box_calloc(1, sizeof(mmaplist_t)); + // check if there is space in current open ones + int i = 0; + uintptr_t sz = size + 2*sizeof(blockmark_t); + while(1) { + if(list->chunks[i].maxfree>=size) { + // looks free, try to alloc! + size_t rsize = 0; + void* sub = getFirstBlock(list->chunks[i].block, size, &rsize, list->chunks[i].first); + if(sub) { + void* ret = allocBlock(list->chunks[i].block, sub, size, NULL); + if(sub==list->chunks[i].first) + list->chunks[i].first = getNextFreeBlock(sub); + if(rsize==list->chunks[i].maxfree) + list->chunks[i].maxfree = getMaxFreeBlock(list->chunks[i].block, list->chunks[i].size, list->chunks[i].first); + return (uintptr_t)ret; + } } - mprotect(p, size, PROT_READ | PROT_WRITE | PROT_EXEC); - #else - void* p = mmap(NULL, size, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); - if(p==(void*)-1) { - dynarec_log(LOG_INFO, "Cannot create dynamic map of %d bytes\n", size); - return 0; + // check if new + if(!list->chunks[i].size) { + // alloc a new block, aversized or not, we are at the end of the list + size_t allocsize = (sz>MMAPSIZE)?sz:MMAPSIZE; + // allign sz with pagesize + allocsize = (allocsize+(box86_pagesize-1))&~(box86_pagesize-1); + #ifndef USE_MMAP + void *p = NULL; + if(!(p=box_memalign(box86_pagesize, allocsize))) { + dynarec_log(LOG_INFO, "Cannot create dynamic map of %zu bytes\n", allocsize); + return 0; + } + mprotect(p, allocsize, PROT_READ | PROT_WRITE | PROT_EXEC); + #else + void* p = mmap(NULL, allocsize, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0); + if(p==(void*)-1) { + dynarec_log(LOG_INFO, "Cannot create dynamic map of %zu bytes\n", allocsize); + return 0; + } + #endif +#ifdef TRACE_MEMSTAT + dynarec_allocated += allocsize; +#endif + setProtection((uintptr_t)p, allocsize, PROT_READ | PROT_WRITE | PROT_EXEC); + list->chunks[i].block = p; + list->chunks[i].first = p; + list->chunks[i].size = allocsize; + // setup marks + blockmark_t* m = (blockmark_t*)p; + m->prev.x32 = 0; + m->next.fill = 0; + m->next.size = allocsize-2*sizeof(blockmark_t); + blockmark_t* n = NEXT_BLOCK(m); + n->next.x32 = 0; + n->prev.fill = 0; + n->prev.size = m->next.size; + // alloc 1st block + void* ret = allocBlock(list->chunks[i].block, p, size, NULL); + list->chunks[i].maxfree = getMaxFreeBlock(list->chunks[i].block, list->chunks[i].size, NULL); + if(list->chunks[i].maxfree) + list->chunks[i].first = getNextFreeBlock(m); + return (uintptr_t)ret; } - #endif - setProtection((uintptr_t)p, size, PROT_READ | PROT_WRITE | PROT_EXEC); - kh_dynablocks_t *blocks = dblist_oversized; - if(!blocks) { - blocks = dblist_oversized = kh_init(dynablocks); - kh_resize(dynablocks, blocks, 64); + // next chunk... + ++i; + if(i==NCHUNK) { + i = 0; + if(!list->next) + list->next = (mmaplist_t*)box_calloc(1, sizeof(mmaplist_t)); + list = list->next; } - khint_t k; - int ret; - k = kh_put(dynablocks, blocks, (uintptr_t)p, &ret); - kh_value(blocks, k) = db; - return (uintptr_t)p; } +} + +void FreeDynarecMap(uintptr_t addr) +{ + if(!addr) + return; - uintptr_t ret = FindFreeDynarecMap(db, size); - if(!ret) - ret = AddNewDynarecMap(db, size); + int i= 0; + mmaplist_t* list = mmaplist; - return ret; -} - -void FreeDynarecMap(dynablock_t* db, uintptr_t addr, uint32_t size) -{ - if(!addr || !size) - return; - if(size>MMAPSIZE-2*sizeof(blockmark_t)) { - #ifndef USE_MMAP - box_free((void*)addr); - #else - munmap((void*)addr, size); - #endif - kh_dynablocks_t *blocks = dblist_oversized; - if(blocks) { - khint_t k = kh_get(dynablocks, blocks, addr); - if(k!=kh_end(blocks)) - kh_del(dynablocks, blocks, k); + while(list) { + if ((addr>(uintptr_t)list->chunks[i].block) + && (addr<((uintptr_t)list->chunks[i].block+list->chunks[i].size))) { + void* sub = (void*)(addr-sizeof(blockmark_t)); + void* n = NEXT_BLOCK((blockmark_t*)sub); + size_t newfree = freeBlock(list->chunks[i].block, sub, NULL); + if(sub<=list->chunks[i].first) + list->chunks[i].first = getPrevFreeBlock(n); + if(list->chunks[i].maxfree < newfree) + list->chunks[i].maxfree = newfree; + return; + } + ++i; + if(i==NCHUNK) { + i = 0; + list = list->next; } - return; } - ActuallyFreeDynarecMap(db, addr, size); } -dynablocklist_t* getDB(uintptr_t idx) +static uintptr_t getDBSize(uintptr_t addr, size_t maxsize, dynablock_t** db) { - return dynmap[idx]; + uintptr_t idx1 = addr>>JMPTABL_SHIFT; + uintptr_t idx0 = addr&JMPTABLE_MASK; + *db = *(dynablock_t**)(box86_jmptbl[idx1][idx0]- sizeof(void*)); + if(*db) + return addr+1; + uintptr_t* block = box86_jmptbl[idx1]; + if(block == box86_jmptbl_default) + return ((idx1+1)<JMPTABLE_MASK) + maxsize = JMPTABLE_MASK; + while(block[idx0]==(uintptr_t)arm_next) { + ++idx0; + if(idx0>maxsize) + return (addr&~JMPTABLE_MASK)+idx0; + } + *db = *(dynablock_t**)(block[idx0]- sizeof(void*)); + return (addr&~JMPTABLE_MASK)+idx0+1; } // each dynmap is 64k of size -void addDBFromAddressRange(uintptr_t addr, uintptr_t size) +void addDBFromAddressRange(uintptr_t addr, size_t size) { dynarec_log(LOG_DEBUG, "addDBFromAddressRange %p -> %p\n", (void*)addr, (void*)(addr+size-1)); - uintptr_t idx = (addr>>DYNAMAP_SHIFT); - uintptr_t end = ((addr+size-1)>>DYNAMAP_SHIFT); - for (uintptr_t i=idx; i<=end; ++i) { - if(!dynmap[i]) { - dynablocklist_t* p = NewDynablockList(i<max_db_size)?0:(addr-my_context->max_db_size)):addr; + dynarec_log(LOG_DEBUG, "cleanDBFromAddressRange %p/%p -> %p %s\n", (void*)addr, (void*)start_addr, (void*)(addr+size-1), destroy?"destroy":"mark"); + dynablock_t* db = NULL; + uintptr_t end = addr+size; + while (start_addr %p %s\n", (void*)addr, (void*)(addr+size-1), destroy?"destroy":"mark"); - uintptr_t idx = (addr>>DYNAMAP_SHIFT); - uintptr_t end = ((addr+size-1)>>DYNAMAP_SHIFT); - for (uintptr_t i=idx; i<=end; ++i) { - int need_free = (destroy && addr<=(i<=((i+1)>>DYNAMAP_SHIFT)-1)?1:0; - dynablocklist_t* dblist = (need_free)?((dynablocklist_t*)arm_lock_xchg(&dynmap[i], 0)):dynmap[i]; - if(dblist) { - if(destroy) { - FreeRangeDynablock(dblist, addr, size); - if(need_free) - FreeDynablockList(&dblist); - } else - MarkRangeDynablock(dblist, addr, size); - } - } -} - -#ifdef ARM -void arm_next(void); -#endif - -void addJumpTableIfDefault(void* addr, void* jmp) -{ - const uintptr_t idx = ((uintptr_t)addr>>JMPTABL_SHIFT); - if(box86_jumptable[idx] == box86_jmptbl_default) { + if(box86_jmptbl[idx1] == box86_jmptbl_default) { uintptr_t* tbl = (uintptr_t*)box_malloc((1<>JMPTABL_SHIFT)&JMPTABLE_MASK; + idx0 = (((uintptr_t)addr) )&JMPTABLE_MASK; + + return (arm_lock_storeifref(create_jmptbl(idx0, idx1), jmp, arm_next)==jmp)?1:0; } void setJumpTableDefault(void* addr) { - const uintptr_t idx = ((uintptr_t)addr>>JMPTABL_SHIFT); - if(box86_jumptable[idx] == box86_jmptbl_default) { + uintptr_t idx1, idx0; + idx1 = (((uintptr_t)addr)>>JMPTABL_SHIFT)&JMPTABLE_MASK; + if(box86_jmptbl[idx1] == box86_jmptbl_default) return; - } - const uintptr_t off = (uintptr_t)addr&((1<>JMPTABL_SHIFT)&JMPTABLE_MASK; + if(box86_jmptbl[idx1] == box86_jmptbl_default) + return; + idx0 = (((uintptr_t)addr) )&JMPTABLE_MASK; + arm_lock_storeifref(&box86_jmptbl[idx1][idx0], arm_next, jmp); +} +int setJumpTableIfRef(void* addr, void* jmp, void* ref) +{ + uintptr_t idx1, idx0; + idx1 = (((uintptr_t)addr)>>JMPTABL_SHIFT)&JMPTABLE_MASK; + idx0 = (((uintptr_t)addr) )&JMPTABLE_MASK; + return (arm_lock_storeifref(create_jmptbl(idx0, idx1), jmp, ref)==jmp)?1:0; } int isJumpTableDefault(void* addr) { - const uintptr_t idx = ((uintptr_t)addr>>JMPTABL_SHIFT); - if(box86_jumptable[idx] == box86_jmptbl_default) { + uintptr_t idx1, idx0; + idx1 = (((uintptr_t)addr)>>JMPTABL_SHIFT)&JMPTABLE_MASK; + if(box86_jmptbl[idx1] == box86_jmptbl_default) return 1; - } - const uintptr_t off = (uintptr_t)addr&((1<>JMPTABL_SHIFT); - if(box86_jumptable[idx] == box86_jmptbl_default) { - uintptr_t* tbl = (uintptr_t*)box_malloc((1<>JMPTABL_SHIFT)&JMPTABLE_MASK; + idx0 = ((addr) )&JMPTABLE_MASK; + return (uintptr_t)create_jmptbl(idx0, idx1); +} + +dynablock_t* getDB(uintptr_t addr) +{ + uintptr_t idx1, idx0; + idx1 = ((addr)>>JMPTABL_SHIFT)&JMPTABLE_MASK; + idx0 = ((addr) )&JMPTABLE_MASK; + uintptr_t ret = (uintptr_t)box86_jmptbl[idx1][idx0]; + + return *(dynablock_t**)(ret - sizeof(void*)); +} + +int getNeedTest(uintptr_t addr) +{ + uintptr_t idx1, idx0; + idx1 = ((addr)>>JMPTABL_SHIFT)&JMPTABLE_MASK; + idx0 = ((addr) )&JMPTABLE_MASK; + uintptr_t ret = (uintptr_t)box86_jmptbl[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 idx1, idx0; + idx1 = ((addr)>>JMPTABL_SHIFT)&JMPTABLE_MASK; + idx0 = ((addr) )&JMPTABLE_MASK; + return (uintptr_t)box86_jmptbl[idx1][idx0]; } // Remove the Write flag from an adress range, so DB can be executed -// no log, as it can be executed inside a signal handler void protectDB(uintptr_t addr, uintptr_t size) { dynarec_log(LOG_DEBUG, "protectDB %p -> %p\n", (void*)addr, (void*)(addr+size-1)); uintptr_t idx = (addr>>MEMPROT_SHIFT); uintptr_t end = ((addr+size-1)>>MEMPROT_SHIFT); - PROT_LOCK(); + mutex_lock(&mutex_prot); for (uintptr_t i=idx; i<=end; ++i) { - uint32_t prot = PROT_GET(i); - if(!(prot&PROT_NOPROT)) { - uint32_t dyn = prot&PROT_CUSTOM; - prot&=~PROT_CUSTOM; - if(!prot) - prot = PROT_READ | PROT_WRITE | PROT_EXEC; // comes from malloc & co, so should not be able to execute + uint32_t prot = memprot[i]; + uint32_t dyn = prot&PROT_DYN; + uint32_t mapped = prot&PROT_MMAP; + if(!prot) + prot = PROT_READ | PROT_WRITE | PROT_EXEC; // comes from malloc & co, so should not be able to execute + prot&=~PROT_CUSTOM; + if(!(dyn&PROT_NOPROT)) { if(prot&PROT_WRITE) { - PROT_SET(i, prot|PROT_DYNAREC); if(!dyn) mprotect((void*)(i< %p (mark=%d)\n", (void*)addr, (void*)(addr+size-1), mark); uintptr_t idx = (addr>>MEMPROT_SHIFT); uintptr_t end = ((addr+size-1)>>MEMPROT_SHIFT); - PROT_LOCK(); + mutex_lock(&mutex_prot); for (uintptr_t i=idx; i<=end; ++i) { - uint32_t prot = PROT_GET(i); + uint32_t prot = memprot[i]; if(!(prot&PROT_NOPROT)) { if(prot&PROT_DYNAREC) { - PROT_SET(i, prot&~PROT_CUSTOM); - mprotect((void*)(i< %p => ", (void*)addr, (void*)(addr+size-1)); uintptr_t idx = (addr>>MEMPROT_SHIFT); uintptr_t end = ((addr+size-1)>>MEMPROT_SHIFT); - PROT_LOCK(); for (uintptr_t i=idx; i<=end; ++i) { - uint32_t prot = PROT_GET(i); - if(!(prot&PROT_NOPROT)) { - if(!(prot&(PROT_DYNAREC|PROT_DYNAREC_R))) { - dynarec_log(LOG_DEBUG, "0\n"); - PROT_UNLOCK(); - return 0; - } + uint32_t prot = memprot[i]; + if(!(prot&PROT_DYN)) { + dynarec_log(LOG_DEBUG, "0\n"); + return 0; } } dynarec_log(LOG_DEBUG, "1\n"); - PROT_UNLOCK(); return 1; } @@ -802,8 +792,8 @@ void addMapMem(uintptr_t begin, uintptr_t end) { if(!mapmem) return; - begin &=~0xfff; - end = (end&~0xfff)+0xfff; // full page + begin &=~(box86_pagesize-1); + end = (end&~(box86_pagesize-1))+(box86_pagesize-1); // full page // sanitize values if(end<0x10000) return; if(!begin) begin = 0x10000; @@ -841,8 +831,8 @@ void removeMapMem(uintptr_t begin, uintptr_t end) { if(!mapmem) return; - begin &=~0xfff; - end = (end&~0xfff)+0xfff; // full page + begin &=~(box86_pagesize-1); + end = (end&~(box86_pagesize-1))+(box86_pagesize-1); // full page // sanitize values if(end<0x10000) return; if(!begin) begin = 0x10000; @@ -886,12 +876,14 @@ void removeMapMem(uintptr_t begin, uintptr_t end) void updateProtection(uintptr_t addr, uintptr_t size, uint32_t prot) { //dynarec_log(LOG_DEBUG, "updateProtection %p -> %p to 0x%02x\n", (void*)addr, (void*)(addr+size-1), prot); - PROT_LOCK(); + mutex_lock(&mutex_prot); addMapMem(addr, addr+size-1); const uintptr_t idx = (addr>>MEMPROT_SHIFT); const uintptr_t end = ((addr+size-1)>>MEMPROT_SHIFT); for (uintptr_t i=idx; i<=end; ++i) { - uint32_t dyn=(PROT_GET(i)&(PROT_DYNAREC|PROT_DYNAREC_R|PROT_NOPROT)); + uint32_t old_prot = memprot[i]; + uint32_t dyn=(old_prot&PROT_DYN); + uint32_t mapped=(old_prot&PROT_MMAP); if(!(dyn&PROT_NOPROT)) { if(dyn && (prot&PROT_WRITE)) { // need to remove the write protection from this block dyn = PROT_DYNAREC; @@ -900,70 +892,86 @@ void updateProtection(uintptr_t addr, uintptr_t size, uint32_t prot) dyn = PROT_DYNAREC_R; } } - PROT_SET(i, prot|dyn); + memprot[i] = prot|dyn|mapped; } - PROT_UNLOCK(); -} - -void forceProtection(uintptr_t addr, uintptr_t size, uint32_t prot) -{ - //dynarec_log(LOG_DEBUG, "forceProtection %p -> %p to 0x%02x\n", (void*)addr, (void*)(addr+size-1), prot); - PROT_LOCK(); - addMapMem(addr, addr+size-1); - const uintptr_t idx = (addr>>MEMPROT_SHIFT); - const uintptr_t end = ((addr+size-1)>>MEMPROT_SHIFT); - for (uintptr_t i=idx; i<=end; ++i) { - mprotect((void*)(i< %p to 0x%02x\n", (void*)addr, (void*)(addr+size-1), prot); - PROT_LOCK(); + mutex_lock(&mutex_prot); addMapMem(addr, addr+size-1); const uintptr_t idx = (addr>>MEMPROT_SHIFT); const uintptr_t end = ((addr+size-1)>>MEMPROT_SHIFT); for (uintptr_t i=idx; i<=end; ++i) { - PROT_SET(i, prot); + memprot[i] = prot; } - PROT_UNLOCK(); + mutex_unlock(&mutex_prot); } -void freeProtection(uintptr_t addr, uintptr_t size) +void setProtection_mmap(uintptr_t addr, size_t size, uint32_t prot) { - PROT_LOCK(); - removeMapMem(addr, addr+size-1); - const uintptr_t idx = (addr>>MEMPROT_SHIFT); - const uintptr_t end = ((addr+size-1)>>MEMPROT_SHIFT); + setProtection(addr, size, prot|PROT_MMAP); +} + +void refreshProtection(uintptr_t addr) +{ + mutex_lock(&mutex_prot); + uintptr_t idx = (addr>>MEMPROT_SHIFT); + int prot = memprot[idx]; + if(!(prot&PROT_DYNAREC)) { + int ret = mprotect((void*)(idx<>MEMPROT_SHIFT); + uintptr_t end = ((addr+size-1LL)>>MEMPROT_SHIFT); + mutex_lock(&mutex_prot); + addMapMem(addr, addr+size-1); + mutex_unlock(&mutex_prot); +} + +#ifdef DYNAREC +int IsInHotPage(uintptr_t addr) { + if(addr>=(1LL<<48)) + return 0; + int idx = (addr>>MEMPROT_SHIFT); + if(!hotpages[idx]) + return 0; + // decrement hot + arm_lock_decifnot0b(&hotpages[idx]); + return 1; +} + +int AreaInHotPage(uintptr_t start, uintptr_t end_) { + uintptr_t idx = (start>>MEMPROT_SHIFT); + uintptr_t end = (end_>>MEMPROT_SHIFT); + int ret = 0; for (uintptr_t i=idx; i<=end; ++i) { - PROT_SET(i, 0); + uint32_t hot = hotpages[i]; + if(hot) { + // decrement hot + arm_lock_decifnot0b(&hotpages[i]); + ret = 1; + } } - PROT_UNLOCK(); -} - -uint32_t getProtection(uintptr_t addr) -{ - const uintptr_t idx = (addr>>MEMPROT_SHIFT); - PROT_LOCK(); - uint32_t ret = PROT_GET(idx); - PROT_UNLOCK(); + if(ret && box86_dynarec_log>LOG_INFO) + dynarec_log(LOG_DEBUG, "BOX64: AreaInHotPage %p-%p\n", (void*)start, (void*)end_); return ret; + } -void allocProtection(uintptr_t addr, uintptr_t size, uint32_t prot) -{ - PROT_LOCK(); - addMapMem(addr, addr+size-1); - const uintptr_t idx = (addr>>MEMPROT_SHIFT); - const uintptr_t end = ((addr+size-1)>>MEMPROT_SHIFT); - for (uintptr_t i=idx; i<=end; ++i) { - PROT_SET_IF_0(i, prot); - } - PROT_UNLOCK(); +void AddHotPage(uintptr_t addr) { + int idx = (addr>>MEMPROT_SHIFT); + arm_lock_storeb(&hotpages[idx], box86_dynarec_hotpage); } +#endif void loadProtectionFromMap() { @@ -971,8 +979,6 @@ void loadProtectionFromMap() return; char buf[500]; FILE *f = fopen("/proc/self/maps", "r"); - uintptr_t current = 0x0; - if(box86_log>=LOG_DEBUG || box86_dynarec_log>=LOG_DEBUG) {printf_log(LOG_NONE, "Refresh mmap allocated block start =============\n");} if(!f) return; while(!feof(f)) { @@ -980,24 +986,46 @@ void loadProtectionFromMap() (void)ret; char r, w, x; uintptr_t s, e; - if(box86_log>=LOG_DEBUG || box86_dynarec_log>=LOG_DEBUG) {printf_log(LOG_NONE, "\t%s", buf);} - if(sscanf(buf, "%x-%x %c%c%c", &s, &e, &r, &w, &x)==5) { - if(current=LOG_DEBUG || box86_dynarec_log>=LOG_DEBUG) { - printf_log(LOG_NONE, "Refresh mmap allocated block done =============\n"); - printMapMem(); - } box86_mapclean = 1; } +void freeProtection(uintptr_t addr, uintptr_t size) +{ + mutex_lock(&mutex_prot); + removeMapMem(addr, addr+size-1); + const uintptr_t idx = (addr>>MEMPROT_SHIFT); + const uintptr_t end = ((addr+size-1)>>MEMPROT_SHIFT); + for (uintptr_t i=idx; i<=end; ++i) { + memprot[i] = 0; + } + mutex_unlock(&mutex_prot); +} + +uint32_t getProtection(uintptr_t addr) +{ + const uintptr_t idx = (addr>>MEMPROT_SHIFT); + mutex_lock(&mutex_prot); + uint32_t ret = memprot[idx]; + mutex_unlock(&mutex_prot); + return ret&~PROT_MMAP; +} + +int getMmapped(uintptr_t addr) +{ + mutex_lock(&mutex_prot); + const uintptr_t idx = (addr>>MEMPROT_SHIFT); + uint32_t ret = memprot[idx]; + mutex_unlock(&mutex_prot); + return (ret&PROT_MMAP)?1:0; +} + + #define LOWEST (void*)0x10000 #define MEDIAN (void*)0x40000000 static void* findBlockHinted(void* hint, size_t size) @@ -1030,45 +1058,6 @@ void* find32bitBlock(size_t size) return ret; } -#ifdef DYNAREC -int IsInHotPage(uintptr_t addr) { - if(addr<=(1LL<<48)) - return 0; - int idx = (addr>>MEMPROT_SHIFT); - if(!hotpages[idx]) - return 0; - // decrement hot - arm_lock_decifnot0b(&hotpages[idx]); - return 1; -} - -int AreaInHotPage(uintptr_t start, uintptr_t end_) { - uintptr_t idx = (start>>MEMPROT_SHIFT); - uintptr_t end = (end_>>MEMPROT_SHIFT); - if(endLOG_INFO) - dynarec_log(LOG_DEBUG, "BOX86: AreaInHotPage %p-%p\n", (void*)start, (void*)end_); - return ret; - -} - -void AddHotPage(uintptr_t addr) { - int idx = (addr>>MEMPROT_SHIFT); - arm_lock_storeb(&hotpages[idx], box86_dynarec_hotpage); -} -#endif - - int unlockCustommemMutex() { int ret = 0; @@ -1088,6 +1077,7 @@ int unlockCustommemMutex() } #endif GO(mutex_blocks, 0) + GO(mutex_prot, 1) #undef GO return ret; } @@ -1099,6 +1089,7 @@ void relockCustommemMutex(int locks) mutex_lock(&A); \ GO(mutex_blocks, 0) + GO(mutex_prot, 1) #undef GO } @@ -1106,6 +1097,7 @@ static void init_mutexes(void) { #ifdef DYNAREC arm_lock_stored(&mutex_blocks, 0); + arm_lock_stored(&mutex_prot, 0); #else pthread_mutexattr_t attr; pthread_mutexattr_init(&attr); @@ -1134,7 +1126,7 @@ void init_custommem_helper(box86context_t* ctx) for(int i=0; i<(1< njmps_in_lv1_max) njmps_in_lv1_max = njmps_in_cur_lv1; + } + printf_log(LOG_INFO, "Allocation:\n- dynarec: %lld kio\n- customMalloc: %lld kio\n- memprot: %lld kio (peak at %lld kio)\n- jump table: %lld kio (%lld level 1 table allocated, for %lld jumps, with at most %lld per level 1)\n", dynarec_allocated / 1024, customMalloc_allocated / 1024, memprot_allocated / 1024, memprot_max_allocated / 1024, jmptbl_allocated / 1024, jmptbl_allocated1, njmps, njmps_in_lv1_max); +#endif if(!inited) return; inited = 0; @@ -1167,40 +1173,25 @@ void fini_custommem_helper(box86context_t *ctx) #else box_free(head->chunks[i].block); #endif - if(head->chunks[i].dblist) { - kh_destroy(dynablocks, head->chunks[i].dblist); - head->chunks[i].dblist = NULL; - } - if(head->chunks[i].helper) { - box_free(head->chunks[i].helper); - head->chunks[i].helper = NULL; - } } mmaplist_t *old = head; head = head->next; free(old); } - if(dblist_oversized) { - kh_destroy(dynablocks, dblist_oversized); - dblist_oversized = NULL; - } mmapsize = 0; dynarec_log(LOG_DEBUG, "Free dynamic Dynarecblocks\n"); uintptr_t idx = 0; uintptr_t end = ((0xFFFFFFFF)>>DYNAMAP_SHIFT); - for (uintptr_t i=idx; i<=end; ++i) - if(dynmap[i]) - FreeDynablockList(&dynmap[i]); box_free(mmaplist); for (int i=0; i=0)?1:0)<<23 | 0<<21 | 1<<20 | 0b1111<<16 | (reg)<<12 | (abs(imm12))) // str reg, [addr, #+/-imm9] #define STR_IMM9(reg, addr, imm9) EMIT(0xe5000000 | (((imm9)<0)?0:1)<<23 | ((reg) << 12) | ((addr) << 16) | brIMM(imm9) ) diff --git a/src/dynarec/arm_next.S b/src/dynarec/arm_next.S index c6bc097f..4cd02588 100755 --- a/src/dynarec/arm_next.S +++ b/src/dynarec/arm_next.S @@ -9,6 +9,7 @@ .extern LinkNext .global arm_next + .4byte 0 // NULL pointer before arm64_next, for getDB arm_next: // emu is r0 //stm r0, {r4-r12,r14} // don't put put back reg value in emu, faster but more tricky to debug diff --git a/src/dynarec/dynablock.c b/src/dynarec/dynablock.c index 7b98fe34..23e890c6 100755 --- a/src/dynarec/dynablock.c +++ b/src/dynarec/dynablock.c @@ -41,21 +41,37 @@ uint32_t X31_hash_code(void* addr, int len) return (uint32_t)h; } -dynablocklist_t* NewDynablockList(uintptr_t text, int textsz, int direct) +dynablock_t* InvalidDynablock(dynablock_t* db, int need_lock) { - if(!textsz) { - printf_log(LOG_NONE, "Error, creating a NULL sized Dynablock\n"); - return NULL; + if(db) { + if(db->gone) + return NULL; // already in the process of deletion! + dynarec_log(LOG_DEBUG, "InvalidDynablock(%p), db->block=%p x86=%p:%p already gone=%d\n", db, db->block, db->x86_addr, db->x86_addr+db->x86_size-1, db->gone); + if(need_lock) + mutex_lock(&my_context->mutex_dyndump); + // remove jumptable + setJumpTableDefault(db->x86_addr); + db->done = 0; + db->gone = 1; + if(need_lock) + mutex_unlock(&my_context->mutex_dyndump); } - dynablocklist_t* ret = (dynablocklist_t*)box_calloc(1, sizeof(dynablocklist_t)); - ret->text = text; - ret->textsz = textsz; - if(direct && textsz) { - ret->direct = (dynablock_t**)box_calloc(textsz, sizeof(dynablock_t*)); - if(!ret->direct) {printf_log(LOG_NONE, "Warning, fail to create direct block for dynablock @%p\n", (void*)text);} + 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 x86=%p:%p already gone=%d\n", db, db->block, db->x86_addr, db->x86_addr+db->x86_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); } - dynarec_log(LOG_DEBUG, "New Dynablocklist %p, from %p->%p\n", ret, (void*)text, (void*)(text+textsz)); - return ret; } void FreeDynablock(dynablock_t* db, int need_lock) @@ -63,224 +79,100 @@ void FreeDynablock(dynablock_t* db, int need_lock) if(db) { if(db->gone) return; // already in the process of deletion! - dynarec_log(LOG_DEBUG, "FreeDynablock(%p), db->block=%p x86=%p:%p already gone=%d\n", db, db->block, db->x86_addr, db->x86_addr+db->x86_size, db->gone); + dynarec_log(LOG_DEBUG, "FreeDynablock(%p), db->block=%p x86=%p:%p already gone=%d\n", db, db->block, db->x86_addr, db->x86_addr+db->x86_size-1, db->gone); if(need_lock) mutex_lock(&my_context->mutex_dyndump); - db->done = 0; - db->gone = 1; - // remove from direct if there - uintptr_t startdb = db->parent->text; - uintptr_t enddb = db->parent->text + db->parent->textsz; - if(db->parent->direct) { - uintptr_t addr = (uintptr_t)db->x86_addr; - if(addr>=startdb && addrparent->direct[addr-startdb] = NULL; - } // remove jumptable setJumpTableDefault(db->x86_addr); - // remove and free the sons - dynarec_log(LOG_DEBUG, " -- FreeDyrecMap(%p, %d)\n", db->block, db->size); - FreeDynarecMap(db, (uintptr_t)db->block, db->size); - box_free(db->instsize); - - box_free(db); + 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) mutex_unlock(&my_context->mutex_dyndump); } } -void FreeDynablockList(dynablocklist_t** dynablocks) -{ - if(!dynablocks) - return; - if(!*dynablocks) - return; - dynarec_log(LOG_DEBUG, "Free Dynablocklist %p, with Direct Blocks %p\n", *dynablocks, (*dynablocks)->direct); - if((*dynablocks)->direct) { - for (int i=0; i<(*dynablocks)->textsz; ++i) { - if((*dynablocks)->direct[i]) - FreeDynablock((*dynablocks)->direct[i], my_context?1:0); - } - box_free((*dynablocks)->direct); - } - (*dynablocks)->direct = NULL; - box_free(*dynablocks); - *dynablocks = NULL; -} void MarkDynablock(dynablock_t* db) { if(db) { - if(db->need_test) - return; // already done - db->need_test = 1; - setJumpTableDefault(db->x86_addr); + dynarec_log(LOG_DEBUG, "MarkDynablock %p %p-%p\n", db, db->x86_addr, db->x86_addr+db->x86_size-1); + if(!setJumpTableIfRef(db->x86_addr, db->jmpnext, db->block)) { + dynablock_t* old = db; + db = getDB((uintptr_t)old->x86_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->x86_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; + } + } } } -uintptr_t StartDynablockList(dynablocklist_t* db) -{ - if(db) - return db->text; - return 0; -} -uintptr_t EndDynablockList(dynablocklist_t* db) -{ - if(db) - return db->text+db->textsz-1; - return 0; -} - -int IntervalIntersects(uintptr_t start1, uintptr_t end1, uintptr_t start2, uintptr_t end2) +static int IntervalIntersects(uintptr_t start1, uintptr_t end1, uintptr_t start2, uintptr_t end2) { if(start1 > end2 || start2 > end1) return 0; return 1; } -void MarkDirectDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size) +static int MarkedDynablock(dynablock_t* db) { - if(!dynablocks) - return; - if(!dynablocks->direct) - return; - uintptr_t startdb = dynablocks->text; - uintptr_t enddb = startdb + dynablocks->textsz -1; - uintptr_t start = addr; - uintptr_t end = addr+size-1; - if(startenddb) - end = enddb; - dynablock_t *db; - if(end>startdb && startdirect[i-startdb])) - if(IntervalIntersects((uintptr_t)db->x86_addr, (uintptr_t)db->x86_addr+db->x86_size-1, addr, addr+size+1)) - MarkDynablock(db); -} - -void FreeRangeDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size) -{ - if(!dynablocks) - return; - - if(dynablocks->direct) { - int need_lock = my_context?1:0; - dynablock_t* db; - int ret; - khint_t k; - kh_dynablocks_t *blocks = kh_init(dynablocks); - // copy in a temporary list - if(dynablocks->direct) { - uintptr_t startdb = dynablocks->text; - uintptr_t enddb = startdb + dynablocks->textsz; - uintptr_t start = addr; - uintptr_t end = addr+size; - if(startenddb) - end = enddb; - if(end>startdb && startdirect[i-startdb], 0); - if(db) { - if(db->parent==dynablocks) { - k = kh_put(dynablocks, blocks, (uintptr_t)db, &ret); - kh_value(blocks, k) = db; - } - } - } - } - // purge the list - kh_foreach_value(blocks, db, - FreeDynablock(db, need_lock); - ); - kh_destroy(dynablocks, blocks); + if(db) { + if(getNeedTest((uintptr_t)db->x86_addr)) + return 1; // already done } + return 0; } -void MarkRangeDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size) + +void MarkRangeDynablock(dynablock_t* db, uintptr_t addr, uintptr_t size) { - if(!dynablocks) + // Mark will try to find *any* blocks that intersect the range to mark + if(!db) return; - if(dynablocks->direct) { - uintptr_t new_addr = addr - dynablocks->maxsz; - uintptr_t new_size = size + dynablocks->maxsz; - MarkDirectDynablock(dynablocks, new_addr, new_size); - // the blocks check before - for(int idx=(new_addr)>>DYNAMAP_SHIFT; idx<(addr>>DYNAMAP_SHIFT); ++idx) - MarkDirectDynablock(getDB(idx), new_addr, new_size); + dynarec_log(LOG_DEBUG, "MarkRangeDynablock %p-%p .. startdb=%p, sizedb=%p\n", (void*)addr, (void*)addr+size-1, (void*)db->x86_addr, (void*)db->x86_size); + if(IntervalIntersects((uintptr_t)db->x86_addr, (uintptr_t)db->x86_addr+db->x86_size-1, addr, addr+size+1)) + MarkDynablock(db); +} + +int FreeRangeDynablock(dynablock_t* db, uintptr_t addr, uintptr_t size) +{ + if(!db) + return 1; + + int need_lock = my_context?1:0; + if(IntervalIntersects((uintptr_t)db->x86_addr, (uintptr_t)db->x86_addr+db->x86_size-1, addr, addr+size+1)) { + FreeDynablock(db, need_lock); + return 0; } + return 1; } -dynablock_t* FindDynablockDynablocklist(void* addr, kh_dynablocks_t* dynablocks) +dynablock_t *AddNewDynablock(uintptr_t addr) { - if(!dynablocks) - return NULL; - dynablock_t* db; - kh_foreach_value(dynablocks, db, - const uintptr_t s = (uintptr_t)db->block; - const uintptr_t e = (uintptr_t)db->block+db->size; - if((uintptr_t)addr>=s && (uintptr_t)addr>DYNAMAP_SHIFT); - return getDB(idx); -} - -dynablock_t *AddNewDynablock(dynablocklist_t* dynablocks, uintptr_t addr, int* created) -{ - if(!dynablocks) { - dynarec_log(LOG_INFO, "Warning: Ask to create a dynablock with a NULL dynablocklist (addr=%p)\n", (void*)addr); - *created = 0; + dynablock_t* block; + #if 0 + // check if memory as the correct flags + int prot = getProtection(addr); + if(!(prot&(PROT_EXEC|PROT_DYNAREC|PROT_DYNAREC_R))) { + dynarec_log(LOG_VERBOSE, "Block asked on a memory with no execution flags 0x%02X\n", prot); return NULL; } - if((addrtext) || (addr>=(dynablocks->text+dynablocks->textsz))) { - // this should be useless - //dynarec_log(LOG_INFO, "Warning: Refused to create a Direct Block that is out-of-bound: dynablocks=%p (%p:%p), addr=%p\n", dynablocks, (void*)(dynablocks->text), (void*)(dynablocks->text+dynablocks->textsz), (void*)addr); - //*created = 0; - //return NULL; - return AddNewDynablock(getDBFromAddress(addr), addr, created); - } - dynablock_t* block = NULL; - // first, check if it exist in direct access mode - if(dynablocks->direct) { - block = dynablocks->direct[addr-dynablocks->text]; - if(block) { - dynarec_log(LOG_VERBOSE, "Block already exist in Direct Map\n"); - *created = 0; - return block; - } - } - if (!*created) - return block; - - if(!dynablocks->direct) { - dynablock_t** p = (dynablock_t**)box_calloc(dynablocks->textsz, sizeof(dynablock_t*)); - if(arm_lock_storeifnull(&dynablocks->direct, p)!=NULL) - box_free(p); // someone already create the direct array, too late... - } - + #endif // create and add new block dynarec_log(LOG_VERBOSE, "Ask for DynaRec Block creation @%p\n", (void*)addr); - - block = (dynablock_t*)box_calloc(1, sizeof(dynablock_t)); - block->parent = dynablocks; - dynablock_t* tmp = (dynablock_t*)arm_lock_storeifref(&dynablocks->direct[addr-dynablocks->text], block, NULL); - if(tmp != block) { - // a block appeard! - box_free(block); - *created = 0; - return tmp; - } - *created = 1; + block = (dynablock_t*)customCalloc(1, sizeof(dynablock_t)); return block; } @@ -296,41 +188,29 @@ void cancelFillBlock() return NULL if block is not found / cannot be created. Don't create if create==0 */ -static dynablock_t* internalDBGetBlock(x86emu_t* emu, uintptr_t addr, uintptr_t filladdr, int create, dynablock_t* current, int need_lock) +static dynablock_t* internalDBGetBlock(x86emu_t* emu, uintptr_t addr, uintptr_t filladdr, int create, int need_lock) { if(hasAlternate((void*)addr)) return NULL; - // try the quickest way first: get parent of current and check if ok! - dynablocklist_t *dynablocks = NULL; - dynablock_t* block = NULL; - if(current && current->done) { - dynablocks = current->parent; - if(dynablocks && !(addr>=dynablocks->text && addr<(dynablocks->text+dynablocks->textsz))) - dynablocks = NULL; - } - // nope, lets do the long way - if(!dynablocks) { - dynablocks = getDBFromAddress(addr); - if(!dynablocks) { - dynablocks = GetDynablocksFromAddress(emu->context, addr); - if(!dynablocks) + dynablock_t* block = getDB(addr); + if(block || !create) + return block; + + if(need_lock) { + if(box86_dynarec_wait) { + mutex_lock(&my_context->mutex_dyndump); + } else { + if(mutex_trylock(&my_context->mutex_dyndump)) // FillBlock not available for now return NULL; } - } - // check direct first, without lock - if(dynablocks->direct/* && (addr>=dynablocks->text) && (addr<(dynablocks->text+dynablocks->textsz))*/) - if((block = dynablocks->direct[addr-dynablocks->text])) - return block; - - int created = create; - if(need_lock) - mutex_lock(&my_context->mutex_dyndump); - block = AddNewDynablock(dynablocks, addr, &created); - if(!created) { - if(need_lock) + block = getDB(addr); // just in case + if(block) { mutex_unlock(&my_context->mutex_dyndump); - return block; // existing block... + return block; + } } + + block = AddNewDynablock(addr); // fill the block block->x86_addr = (void*)addr; @@ -341,73 +221,83 @@ static dynablock_t* internalDBGetBlock(x86emu_t* emu, uintptr_t addr, uintptr_t return NULL; } void* ret = FillBlock(block, filladdr); - if(need_lock) - mutex_unlock(&my_context->mutex_dyndump); if(!ret) { dynarec_log(LOG_DEBUG, "Fillblock of block %p for %p returned an error\n", block, (void*)addr); - void* old = (void*)arm_lock_storeifref(&dynablocks->direct[addr-dynablocks->text], 0, block); - if(old!=block && old) { // put it back in place, strange things are happening here! - dynarec_log(LOG_INFO, "Warning, a wild block appeared at %p: %p\n", (void*)addr, old); - // Doing nothing else, the block has not been written - } - box_free(block); + customFree(block); block = NULL; } // check size - if(block && block->x86_size) { + if(block && (block->x86_size || (!block->x86_size && !block->done))) { int blocksz = block->x86_size; - if(dynablocks->maxszmaxsz = blocksz; - for(int idx=(addr>>DYNAMAP_SHIFT)+1; idx<=((addr+blocksz)>>DYNAMAP_SHIFT); ++idx) { - dynablocklist_t* dblist; - if((dblist = getDB(idx))) - if(dblist->maxszmaxsz = blocksz; - } - } - //protectDB((uintptr_t)block->x86_addr, block->x86_size); // already protected in FillBlock - // but check if it already need test - if(block->need_test) - return NULL; + if(blocksz>my_context->max_db_size) + my_context->max_db_size = blocksz; // fill-in jumptable - addJumpTableIfDefault(block->x86_addr, block->block); + if(!addJumpTableIfDefault(block->x86_addr, block->dirty?block->jmpnext:block->block)) { + FreeDynablock(block, 0); + block = getDB(addr); + MarkDynablock(block); // just in case... + } else { + if(block->x86_size) + block->done = 1; // don't validate the block if the size is null, but keep the block + } } + if(need_lock) + mutex_unlock(&my_context->mutex_dyndump); - dynarec_log(LOG_DEBUG, " --- DynaRec Block %s @%p:%p (%p, 0x%x bytes)\n", created?"created":"recycled", (void*)addr, (void*)(addr+((block)?block->x86_size:0)), (block)?block->block:0, (block)?block->size:0); + dynarec_log(LOG_DEBUG, "%04d| --- DynaRec Block created @%p:%p (%p, 0x%x bytes)\n", GetTID(), (void*)addr, (void*)(addr+((block)?block->x86_size:1)-1), (block)?block->block:0, (block)?block->size:0); return block; } -dynablock_t* DBGetBlock(x86emu_t* emu, uintptr_t addr, int create, dynablock_t** current) +dynablock_t* DBGetBlock(x86emu_t* emu, uintptr_t addr, int create) { - dynablock_t *db = internalDBGetBlock(emu, addr, addr, create, *current, 1); - if(db && db->done && db->block && (db->need_test)) { + dynablock_t *db = internalDBGetBlock(emu, addr, addr, create, 1); + if(db && db->done && db->block && getNeedTest(addr)) { + if(db->always_test) + sched_yield(); // just calm down... if(AreaInHotPage((uintptr_t)db->x86_addr, (uintptr_t)db->x86_addr + db->x86_size - 1)) { emu->test.test = 0; - dynarec_log(LOG_DEBUG, "Not running block %p from %p:%p with for %p because it's in a hotpage\n", db, db->x86_addr, db->x86_addr+db->x86_size-1, (void*)addr); - return NULL; + if(box86_dynarec_fastpage) { + uint32_t hash = X31_hash_code(db->x86_addr, db->x86_size); + if(hash==db->hash) { // seems ok, run it without reprotecting it + setJumpTableIfRef(db->x86_addr, db->block, db->jmpnext); + return db; + } + db->done = 0; // invalidating the block, it's already not good + 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); + // Free db, it's now invalid! + FreeDynablock(db, 1); + return NULL; // not building a new one, it's still a hotpage + } else { + dynarec_log(LOG_INFO, "Not running block %p from %p:%p with for %p because it's in a hotpage\n", db, db->x86_addr, db->x86_addr+db->x86_size-1, (void*)addr); + return NULL; + } } - if(mutex_trylock(&my_context->mutex_dyndump)) { - emu->test.test = 0; - return NULL; - } - uint32_t hash = (getProtection((uintptr_t)db->x86_addr)&PROT_READ)?X31_hash_code(db->x86_addr, db->x86_size):0; + uint32_t hash = X31_hash_code(db->x86_addr, db->x86_size); + int need_lock = mutex_trylock(&my_context->mutex_dyndump); if(hash!=db->hash) { - 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, hash, db->hash, (void*)addr); - // no more current if it gets invalidated too - if(*current && db->x86_addr>=(*current)->x86_addr && (db->x86_addr+db->x86_size)<(*current)->x86_addr) - *current = NULL; + 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); // 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, *current, 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->x86_addr, db->x86_addr+db->x86_size-1, db->hash, (void*)addr); protectDB((uintptr_t)db->x86_addr, db->x86_size); // fill back jumptable - addJumpTableIfDefault(db->x86_addr, db->block); + if(isprotectedDB((uintptr_t)db->x86_addr, db->x86_size) && !db->always_test) { + setJumpTableIfRef(db->x86_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; @@ -418,26 +308,34 @@ dynablock_t* DBAlternateBlock(x86emu_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, NULL, 1); - if(db && db->done && db->block && (db->need_test)) { - if(mutex_trylock(&my_context->mutex_dyndump)) { - emu->test.test = 0; - return NULL; - } - uint32_t hash = (getProtection((uintptr_t)db->x86_addr)&PROT_READ)?X31_hash_code(db->x86_addr, db->x86_size):0; + dynablock_t *db = internalDBGetBlock(emu, addr, filladdr, create, 1); + 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->x86_addr, db->x86_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->x86_addr, db->x86_addr+db->x86_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, NULL, 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->x86_addr, db->x86_size); // fill back jumptable - addJumpTableIfDefault(db->x86_addr, db->block); + if(isprotectedDB((uintptr_t)db->x86_addr, db->x86_size) && !db->always_test) { + setJumpTableIfRef(db->x86_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 c0521b61..0a01e64b 100755 --- a/src/dynarec/dynablock_private.h +++ b/src/dynarec/dynablock_private.h @@ -9,25 +9,20 @@ typedef struct instsize_s { } instsize_t; typedef struct dynablock_s { - dynablocklist_t* parent; - void* block; + 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* x86_addr; uintptr_t x86_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 } dynablock_t; -typedef struct dynablocklist_s { - uintptr_t text; - int textsz; - int maxsz; // maxblock size (for this block or previous block) - dynablock_t** direct; // direct mapping (waste of space, so the array is created at first write) -} dynablocklist_t; - #endif //__DYNABLOCK_PRIVATE_H_ \ No newline at end of file diff --git a/src/dynarec/dynarec.c b/src/dynarec/dynarec.c index 8762f46f..24f8e766 100755 --- a/src/dynarec/dynarec.c +++ b/src/dynarec/dynarec.c @@ -45,9 +45,8 @@ void* LinkNext(x86emu_t* emu, uintptr_t addr, void* x2) printf_log(LOG_NONE, "Warning, jumping to NULL address from %p (db=%p, x86addr=%p/%s)\n", x2, db, x86addr, pcname); } #endif - dynablock_t* current = NULL; void * jblock; - dynablock_t* block = DBGetBlock(emu, addr, 1, ¤t); + dynablock_t* block = DBGetBlock(emu, addr, 1); if(!block) { // no block, let link table as is... if(hasAlternate((void*)addr)) { @@ -55,12 +54,15 @@ void* LinkNext(x86emu_t* emu, uintptr_t addr, void* x2) addr = (uintptr_t)getAlternate((void*)addr); R_EIP = addr; printf_log(LOG_INFO, " -> %p\n", (void*)addr); - block = DBGetBlock(emu, addr, 1, ¤t); + block = DBGetBlock(emu, addr, 1); } if(!block) { #ifdef HAVE_TRACE - dynablock_t* db = FindDynablockFromNativeAddress(x2); - dynarec_log(LOG_INFO, "Warning, jumping to a no-block address %p from %p (db=%p, x86addr=%p)\n", (void*)addr, x2, db, db?(void*)getX86Address(db, (uintptr_t)x2):NULL); + if(LOG_INFO<=box86_dynarec_log) { + dynablock_t* db = FindDynablockFromNativeAddress(x2); + elfheader_t* h = FindElfAddress(my_context, (uintptr_t)x2); + dynarec_log(LOG_INFO, "Warning, jumping to a no-block address %p from %p (db=%p, x64addr=%p(elf=%s))\n", (void*)addr, x2, db, db?(void*)getX86Address(db, (uintptr_t)x2-4):NULL, h?ElfName(h):"(none)"); + } #endif //tableupdate(arm_epilog, addr, table); return arm_epilog; @@ -125,7 +127,7 @@ void DynaCall(x86emu_t* emu, uintptr_t addr) dynablock_t* block = NULL; dynablock_t* current = NULL; while(!emu->quit) { - block = (skip==2)?NULL:DBGetBlock(emu, R_EIP, 1, ¤t); + block = (skip==2)?NULL:DBGetBlock(emu, R_EIP, 1); current = block; if(!block || !block->block || !block->done) { skip = 0; @@ -220,7 +222,7 @@ int DynaRun(x86emu_t* emu) dynablock_t* block = NULL; dynablock_t* current = NULL; while(!emu->quit) { - block = (skip==2)?NULL:DBGetBlock(emu, R_EIP, 1, ¤t); + block = (skip==2)?NULL:DBGetBlock(emu, R_EIP, 1); current = block; if(!block || !block->block || !block->done) { skip = 0; diff --git a/src/dynarec/dynarec_arm.c b/src/dynarec/dynarec_arm.c index c6d235c7..a3b09687 100755 --- a/src/dynarec/dynarec_arm.c +++ b/src/dynarec/dynarec_arm.c @@ -73,8 +73,8 @@ void add_next(dynarec_arm_t *dyn, uintptr_t addr) { } // add slots if(dyn->next_sz == dyn->next_cap) { - dyn->next_cap += 16; - dyn->next = (uintptr_t*)box_realloc(dyn->next, dyn->next_cap*sizeof(uintptr_t)); + dyn->next_cap += 64; + dyn->next = (uintptr_t*)customRealloc(dyn->next, dyn->next_cap*sizeof(uintptr_t)); } dyn->next[dyn->next_sz++] = addr; } @@ -243,35 +243,31 @@ int is_instructions(dynarec_arm_t *dyn, uintptr_t addr, int n) return (i==n)?1:0; } -static instsize_t* addInst(instsize_t* insts, size_t* size, size_t* cap, int x86_size, int arm_size) +void addInst(instsize_t* insts, size_t* size, int x86_size, int native_size) { // x86 instruction is <16 bytes int toadd; - if(x86_size>arm_size) + if(x86_size>native_size) toadd = 1 + x86_size/15; else - toadd = 1 + arm_size/15; - if((*size)+toadd>(*cap)) { - *cap = (*size)+toadd; - insts = (instsize_t*)box_realloc(insts, (*cap)*sizeof(instsize_t)); - } + toadd = 1 + native_size/15; while(toadd) { if(x86_size>15) insts[*size].x86 = 15; else insts[*size].x86 = x86_size; x86_size -= insts[*size].x86; - if(arm_size>15) + if(native_size>15) insts[*size].nat = 15; else - insts[*size].nat = arm_size; - arm_size -= insts[*size].nat; + insts[*size].nat = native_size; + native_size -= insts[*size].nat; ++(*size); --toadd; } - return insts; } + static void fillPredecessors(dynarec_arm_t* dyn) { int pred_sz = 1; // to be safe @@ -290,7 +286,7 @@ static void fillPredecessors(dynarec_arm_t* dyn) ++dyn->insts[i+1].pred_sz; } } - dyn->predecessor = (int*)box_malloc(pred_sz*sizeof(int)); + dyn->predecessor = (int*)customMalloc(pred_sz*sizeof(int)); // fill pred pointer int* p = dyn->predecessor; for(int i=0; isize; ++i) { @@ -358,36 +354,70 @@ static int updateNeed(dynarec_arm_t* dyn, int ninst, uint8_t need) { return ninst; } +void* current_helper = NULL; + +void CancelBlock(int need_lock) +{ + if(need_lock) + mutex_lock(&my_context->mutex_dyndump); + dynarec_arm_t* helper = (dynarec_arm_t*)current_helper; + current_helper = NULL; + if(helper) { + customFree(helper->next); + customFree(helper->insts); + customFree(helper->predecessor); + if(helper->dynablock && helper->dynablock->actual_block) { + FreeDynarecMap((uintptr_t)helper->dynablock->actual_block); + helper->dynablock->actual_block = NULL; + } + } + if(need_lock) + mutex_unlock(&my_context->mutex_dyndump); +} + uintptr_t arm_pass0(dynarec_arm_t* dyn, uintptr_t addr); uintptr_t arm_pass1(dynarec_arm_t* dyn, uintptr_t addr); uintptr_t arm_pass2(dynarec_arm_t* dyn, uintptr_t addr); uintptr_t arm_pass3(dynarec_arm_t* dyn, uintptr_t addr); - -void* current_helper = NULL; - -void CancelBlock() -{ - dynarec_arm_t* helper = (dynarec_arm_t*)current_helper; - current_helper = NULL; - if(!helper) - return; - box_free(helper->next); - box_free(helper->insts); - box_free(helper->predecessor); - if(helper->dynablock && helper->dynablock->block) - FreeDynarecMap(helper->dynablock, (uintptr_t)helper->dynablock->block, helper->dynablock->size); -} +void arm_epilog(); +void arm_next(); void* CreateEmptyBlock(dynablock_t* block, uintptr_t addr) { block->isize = 0; block->done = 0; - block->size = 0; - block->block = NULL; - block->need_test = 0; + size_t sz = 8*sizeof(void*); + void* actual_p = (void*)AllocDynarecMap(sz); + void* p = actual_p + sizeof(void*); + if(actual_p==NULL) { + dynarec_log(LOG_INFO, "AllocDynarecMap(%p, %zu) failed, cancelling block\n", block, sz); + CancelBlock(0); + return NULL; + } + block->size = sz; + block->actual_block = actual_p; + block->block = p; + block->jmpnext = p; + *(dynablock_t**)actual_p = block; + *(void**)(p+4*sizeof(void*)) = arm_epilog; + CreateJmpNext(block->jmpnext, p+4*sizeof(void*)); + // all done... + __clear_cache(actual_p, actual_p+sz); // need to clear the cache before execution... return block; } void* FillBlock(dynablock_t* block, uintptr_t addr) { + /* + A Block must have this layout: + + 0x0000..0x0003 : dynablock_t* : self + 0x0004..4+4*n : actual Native instructions, (n is the total number) + B .. B+3 : dynablock_t* : self (as part of JmpNext, that simulate another block) + B+4 .. B+15 : 3 Native code for jmpnext (or jmp epilog in case of empty block) + B+16 .. B+19 : jmpnext (or jmp_epilog) address + B+20 .. B+31 : empty (in case an architecture needs more than 3 opcodes) + B+32 .. B+32+sz : instsize (compressed array with each instruction lenght on x86 and native side) + + */ dynarec_log(LOG_DEBUG, "Asked to Fill block %p with %p\n", block, (void*)addr); if(IsInHotPage(addr)) { dynarec_log(LOG_DEBUG, "Cancelling dynarec FillBlock on hotpage for %p\n", (void*)addr); @@ -397,10 +427,6 @@ dynarec_log(LOG_DEBUG, "Asked to Fill block %p with %p\n", block, (void*)addr); dynarec_log(LOG_DEBUG, "Asked to fill a block in fobidden zone\n"); return CreateEmptyBlock(block, addr); } - if(!isJumpTableDefault((void*)addr)) { - dynarec_log(LOG_DEBUG, "Asked to fill a block at %p, but JumpTable is not default\n", (void*)addr); - return NULL; - } if(current_helper) { dynarec_log(LOG_DEBUG, "Cancelling dynarec FillBlock at %p as anothor one is going on\n", (void*)addr); return NULL; @@ -414,23 +440,23 @@ dynarec_log(LOG_DEBUG, "Asked to Fill block %p with %p\n", block, (void*)addr); helper.start = addr; uintptr_t start = addr; helper.cap = 64; // needs epilog handling - helper.insts = (instruction_arm_t*)box_calloc(helper.cap, sizeof(instruction_arm_t)); + helper.insts = (instruction_arm_t*)customCalloc(helper.cap, sizeof(instruction_arm_t)); // pass 0, addresses, x86 jump addresses, overall size of the block uintptr_t end = arm_pass0(&helper, addr); // no need for next anymore - box_free(helper.next); + customFree(helper.next); helper.next_sz = helper.next_cap = 0; helper.next = NULL; // basic checks if(!helper.size) { dynarec_log(LOG_DEBUG, "Warning, null-sized dynarec block (%p)\n", (void*)addr); - CancelBlock(); - return (void*)block; + CancelBlock(0); + return CreateEmptyBlock(block, addr); } if(!isprotectedDB(addr, 1)) { dynarec_log(LOG_INFO, "Warning, write on current page on pass0, aborting dynablock creation (%p)\n", (void*)addr); AddHotPage(addr); - CancelBlock(); + CancelBlock(0); return NULL; } // already protect the block and compute hash signature @@ -443,6 +469,8 @@ dynarec_log(LOG_DEBUG, "Asked to Fill block %p with %p\n", block, (void*)addr); if(helper.insts[i].x86.jmp) { uintptr_t j = helper.insts[i].x86.jmp; if(j=end || j==helper.insts[i].x86.addr) { + if(j==helper.insts[i].x86.addr) // if there is a loop on some opcode, make the block "always to tested" + helper.always_test = 1; helper.insts[i].x86.jmp_insts = -1; helper.insts[i].x86.need_after |= X_PEND; } else { @@ -470,24 +498,68 @@ dynarec_log(LOG_DEBUG, "Asked to Fill block %p with %p\n", block, (void*)addr); // pass 2, instruction size arm_pass2(&helper, addr); // ok, now allocate mapped memory, with executable flag on - int sz = helper.arm_size; - void* p = (void*)AllocDynarecMap(block, sz); - if(p==NULL) { - dynarec_log(LOG_DEBUG, "AllocDynarecMap(%p, %d) failed, cancelling block\n", block, sz); - CancelBlock(); + size_t insts_rsize = (helper.insts_size+2)*sizeof(instsize_t); + insts_rsize = (insts_rsize+7)&~7; // round the size... + size_t arm_size = (helper.arm_size+7)&~7; // round the size... + // ok, now allocate mapped memory, with executable flag on + size_t sz = sizeof(void*) + arm_size + 8*sizeof(void*) + insts_rsize; + // dynablock_t* block (arm insts) jmpnext code instsize + void* actual_p = (void*)AllocDynarecMap(sz); + void* p = (void*)(((uintptr_t)actual_p) + sizeof(void*)); + void* next = p + arm_size; + void* instsize = next + 8*sizeof(void*); + if(actual_p==NULL) { + dynarec_log(LOG_INFO, "AllocDynarecMap(%p, %zu) failed, cancelling block\n", block, sz); + CancelBlock(0); return NULL; } helper.block = p; - // pass 3, emit (log emit arm opcode) + block->actual_block = actual_p; + helper.arm_start = (uintptr_t)p; + helper.jmp_next = (uintptr_t)next+sizeof(void*); + helper.insts_size = 0; // reset + helper.instsize = (instsize_t*)instsize; + *(dynablock_t**)actual_p = block; + // pass 3, emit (log emit native opcode) if(box86_dynarec_dump) { dynarec_log(LOG_NONE, "%s%04d|Emitting %d bytes for %d x86 bytes", (box86_dynarec_dump>1)?"\e[01;36m":"", GetTID(), helper.arm_size, helper.isize); printFunctionAddr(helper.start, " => "); dynarec_log(LOG_NONE, "%s\n", (box86_dynarec_dump>1)?"\e[m":""); } + size_t oldarmsize = helper.arm_size; helper.arm_size = 0; arm_pass3(&helper, addr); - if(sz!=helper.arm_size) { - printf_log(LOG_NONE, "BOX86: Warning, size difference in block between pass2 (%d) & pass3 (%d)!\n", sz, helper.arm_size); + // keep size of instructions for signal handling + block->instsize = instsize; + // ok, free the helper now + customFree(helper.insts); + helper.insts = NULL; + helper.instsize = NULL; + customFree(helper.predecessor); + helper.predecessor = NULL; + block->size = sz; + block->isize = helper.size; + 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+5*sizeof(void*)) = arm_next; + CreateJmpNext(block->jmpnext, next+5*sizeof(void*)); + //block->x86_addr = (void*)start; + block->x86_size = end-start; + // all done... + __clear_cache(actual_p, actual_p+sz); // need to clear the cache before execution... + block->hash = X31_hash_code(block->x86_addr, block->x86_size); + // Check if something changed, to abbort if it as + if((block->hash != hash)) { + dynarec_log(LOG_DEBUG, "Warning, a block changed while being processed hash(%p:%ld)=%x/%x\n", block->x86_addr, block->x86_size, block->hash, hash); + AddHotPage(addr); + CancelBlock(0); + return NULL; + } + if((oldarmsize!=helper.arm_size)) { + printf_log(LOG_NONE, "BOx86: Warning, size difference in block between pass2 (%zu) & pass3 (%zu)!\n", sz, helper.arm_size); uint8_t *dump = (uint8_t*)helper.start; printf_log(LOG_NONE, "Dump of %d x86 opcodes:\n", helper.size); for(int i=0; i %d\n", helper.insts[i].size2, helper.insts[i].size); } printf_log(LOG_NONE, " ------------\n"); - } - // all done... - __clear_cache(p, p+sz); // need to clear the cache before execution... - // keep size of instructions for signal handling - { - size_t cap = 1; - for(int i=0; ihelper.insts[i].size)?helper.insts[i].x86.size:helper.insts[i].size)/15; - size_t size = 0; - block->instsize = (instsize_t*)box_calloc(cap, sizeof(instsize_t)); - for(int i=0; iinstsize = addInst(block->instsize, &size, &cap, helper.insts[i].x86.size, helper.insts[i].size/4); - block->instsize = addInst(block->instsize, &size, &cap, 0, 0); // add a "end of block" mark, just in case - } - // ok, free the helper now - box_free(helper.insts); - helper.insts = NULL; - box_free(helper.next); - helper.next = NULL; - block->size = sz; - block->isize = helper.size; - block->block = p; - block->need_test = 0; - //block->x86_addr = (void*)start; - block->x86_size = end-start; - if(box86_dynarec_largestx86_size) - box86_dynarec_largest = block->x86_size; - block->hash = X31_hash_code(block->x86_addr, block->x86_size); - // Check if something changed, to abbort if it as - if(block->hash != hash) { - dynarec_log(LOG_INFO, "Warning, a block changed while beeing processed hash(%p:%d)=%x/%x\n", block->x86_addr, block->x86_size, block->hash, hash); - CancelBlock(); - AddHotPage(addr); + CancelBlock(0); return NULL; } if(!isprotectedDB(addr, end-addr)) { - dynarec_log(LOG_DEBUG, "Warning, block unprotected while beeing processed %p:%zd, cancelling\n", block->x86_addr, block->x86_size); + dynarec_log(LOG_DEBUG, "Warning, block unprotected while being processed %p:%ld, marking as need_test\n", block->x86_addr, block->x86_size); AddHotPage(addr); - block->need_test = 1; + block->dirty = 1; //protectDB(addr, end-addr); } - box_free(helper.predecessor); - helper.predecessor = NULL; current_helper = NULL; - block->done = 1; + //block->done = 1; return (void*)block; } diff --git a/src/dynarec/dynarec_arm_00.c b/src/dynarec/dynarec_arm_00.c index fb094e40..4829cff1 100755 --- a/src/dynarec/dynarec_arm_00.c +++ b/src/dynarec/dynarec_arm_00.c @@ -2165,8 +2165,8 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, tmp = dyn->insts[ninst].pass2choice = 1; else if ((getProtection(u32)&PROT_READ) && (PKa(u32+0)==0x8B) && (((PKa(u32+1))&0xC7)==0x04) && (PKa(u32+2)==0x24) && (PKa(u32+3)==0xC3)) tmp = dyn->insts[ninst].pass2choice = 2; - /*else if(isNativeCall(dyn, u32, &dyn->insts[ninst].natcall, &dyn->insts[ninst].retn)) - tmp = dyn->insts[ninst].pass2choice = 3;*/ + else if(isNativeCall(dyn, u32, &dyn->insts[ninst].natcall, &dyn->insts[ninst].retn)) + tmp = dyn->insts[ninst].pass2choice = 3; else tmp = dyn->insts[ninst].pass2choice = 0; #else @@ -2188,8 +2188,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, gd = xEAX+((u8&0x38)>>3); MOV32(gd, addr); break; - // disabling this to avoid fetching data outside current block (in case this part changed, this block will not been marck as dirty) - /*case 3: + case 3: SETFLAGS(X_ALL, SF_SET); // Hack to set flags to "dont'care" state BARRIER(BARRIER_FULL); BARRIER_NEXT(BARRIER_FULL); @@ -2228,7 +2227,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, B_NEXT(cNE); // not quitting, so lets continue MARK; jump_to_epilog(dyn, 0, xEIP, ninst); - break;*/ + break; default: if((box86_dynarec_safeflags>1) || (ninst && dyn->insts[ninst-1].x86.set_flags)) { READFLAGS(X_PEND); // that's suspicious @@ -2844,7 +2843,7 @@ uintptr_t dynarec00(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t ip, int ninst, { READFLAGS(X_PEND); // that's suspicious } else { - //SETFLAGS(X_ALL, SF_SET); //Hack to put flag in "don't care" state + SETFLAGS(X_ALL, SF_SET); //Hack to put flag in "don't care" state } GETEDH(xEIP); BARRIER(BARRIER_FLOAT); diff --git a/src/dynarec/dynarec_arm_functions.c b/src/dynarec/dynarec_arm_functions.c index 5272abb7..3e2d474d 100755 --- a/src/dynarec/dynarec_arm_functions.c +++ b/src/dynarec/dynarec_arm_functions.c @@ -28,6 +28,7 @@ #include "dynarec_arm_functions.h" #include "bridge.h" #include "arm_printer.h" +#include "custommem.h" void arm_fstp(x86emu_t* emu, void* p) { @@ -705,13 +706,13 @@ int isNativeCall(dynarec_arm_t* dyn, uintptr_t addr, uintptr_t* calladdress, int #define PK(a) *(uint8_t*)(addr+a) #define PK32(a) *(uint32_t*)(addr+a) - if(!addr) + if(!addr || !getProtection(addr)) return 0; if(PK(0)==0xff && PK(1)==0x25) { // absolute jump, maybe the GOT uintptr_t a1 = (PK32(2)); // need to add a check to see if the address is from the GOT ! addr = (uintptr_t)getAlternate(*(void**)a1); } - if(addr<0x10000) // too low, that is suspicious + if(addr<0x10000 || !getProtection(addr)) // too low, that is suspicious return 0; onebridge_t *b = (onebridge_t*)(addr); if(b->CC==0xCC && b->S=='S' && b->C=='C' && b->w!=(wrapper_t)0 && b->f!=(uintptr_t)PltResolver) { diff --git a/src/dynarec/dynarec_arm_helper.c b/src/dynarec/dynarec_arm_helper.c index 3109efbb..b03eeb31 100755 --- a/src/dynarec/dynarec_arm_helper.c +++ b/src/dynarec/dynarec_arm_helper.c @@ -4,6 +4,7 @@ #include #include #include +#include #include "debug.h" #include "box86context.h" @@ -1936,3 +1937,64 @@ void emit_pf(dynarec_arm_t* dyn, int ninst, int s1, int s3, int s4) MVN_REG_LSR_REG(s4, s4, s3); BFI(xFlags, s4, F_PF, 1); } + +void fpu_reset_cache(dynarec_arm_t* dyn, int ninst, int reset_n) +{ + MESSAGE(LOG_DEBUG, "Reset Caches with %d\n",reset_n); + #if STEP > 1 + // for STEP 2 & 3, just need to refrest with current, and undo the changes (push & swap) + dyn->n = dyn->insts[ninst].n; + neoncacheUnwind(&dyn->n); + #ifdef HAVE_TRACE + if(box86_dynarec_dump) + if(memcmp(&dyn->n, &dyn->insts[reset_n].n, sizeof(neon_cache_t))) { + MESSAGE(LOG_DEBUG, "Warning, difference in neoncache: reset="); + for(int i=0; i<24; ++i) + if(dyn->insts[reset_n].n.neoncache[i].v) + MESSAGE(LOG_DEBUG, " %02d:%s", i, getCacheName(dyn->insts[reset_n].n.neoncache[i].t, dyn->insts[reset_n].n.neoncache[i].n)); + if(dyn->insts[reset_n].n.combined1 || dyn->insts[reset_n].n.combined2) + MESSAGE(LOG_DEBUG, " %s:%02d/%02d", dyn->insts[reset_n].n.swapped?"SWP":"CMB", dyn->insts[reset_n].n.combined1, dyn->insts[reset_n].n.combined2); + if(dyn->insts[reset_n].n.stack_push || dyn->insts[reset_n].n.stack_pop) + MESSAGE(LOG_DEBUG, " (%d:%d)", dyn->insts[reset_n].n.stack_push, -dyn->insts[reset_n].n.stack_pop); + MESSAGE(LOG_DEBUG, " ==> "); + for(int i=0; i<24; ++i) + if(dyn->insts[ninst].n.neoncache[i].v) + MESSAGE(LOG_DEBUG, " %02d:%s", i, getCacheName(dyn->insts[ninst].n.neoncache[i].t, dyn->insts[ninst].n.neoncache[i].n)); + if(dyn->insts[ninst].n.combined1 || dyn->insts[ninst].n.combined2) + MESSAGE(LOG_DEBUG, " %s:%02d/%02d", dyn->insts[ninst].n.swapped?"SWP":"CMB", dyn->insts[ninst].n.combined1, dyn->insts[ninst].n.combined2); + if(dyn->insts[ninst].n.stack_push || dyn->insts[ninst].n.stack_pop) + MESSAGE(LOG_DEBUG, " (%d:%d)", dyn->insts[ninst].n.stack_push, -dyn->insts[ninst].n.stack_pop); + MESSAGE(LOG_DEBUG, " -> "); + for(int i=0; i<24; ++i) + if(dyn->n.neoncache[i].v) + MESSAGE(LOG_DEBUG, " %02d:%s", i, getCacheName(dyn->n.neoncache[i].t, dyn->n.neoncache[i].n)); + if(dyn->n.combined1 || dyn->n.combined2) + MESSAGE(LOG_DEBUG, " %s:%02d/%02d", dyn->n.swapped?"SWP":"CMB", dyn->n.combined1, dyn->n.combined2); + if(dyn->n.stack_push || dyn->n.stack_pop) + MESSAGE(LOG_DEBUG, " (%d:%d)", dyn->n.stack_push, -dyn->n.stack_pop); + MESSAGE(LOG_DEBUG, "\n"); + } + #endif //HAVE_TRACE + #else + dyn->n = dyn->insts[reset_n].n; + #endif +} + +// propagate ST stack state, especial stack pop that are deferred +void fpu_propagate_stack(dynarec_arm_t* dyn, int ninst) +{ + if(dyn->n.stack_pop) { + for(int j=0; j<24; ++j) + if((dyn->n.neoncache[j].t == NEON_CACHE_ST_D || dyn->n.neoncache[j].t == NEON_CACHE_ST_F)) { + if(dyn->n.neoncache[j].nn.stack_pop) + dyn->n.neoncache[j].v = 0; + else + dyn->n.neoncache[j].n-=dyn->n.stack_pop; + } + dyn->n.stack_pop = 0; + } + dyn->n.stack = dyn->n.stack_next; + dyn->n.news = 0; + dyn->n.stack_push = 0; + dyn->n.swapped = 0; +} \ No newline at end of file diff --git a/src/dynarec/dynarec_arm_helper.h b/src/dynarec/dynarec_arm_helper.h index f6dbbcd8..7ebaa587 100755 --- a/src/dynarec/dynarec_arm_helper.h +++ b/src/dynarec/dynarec_arm_helper.h @@ -547,6 +547,8 @@ void* arm_next(x86emu_t* emu, uintptr_t addr); #define fpu_pushcache STEPNAME(fpu_pushcache) #define fpu_popcache STEPNAME(fpu_popcache) #define fpu_reset STEPNAME(fpu_reset) +#define fpu_reset_cache STEPNAME(fpu_reset_cache) +#define fpu_propagate_stack STEPNAME(fpu_propagate_stack) #define fpu_purgecache STEPNAME(fpu_purgecache) #define x87_purgecache STEPNAME(x87_purgecache) #define mmx_purgecache STEPNAME(mmx_purgecache) @@ -740,6 +742,10 @@ int sse_get_reg_empty(dynarec_arm_t* dyn, int ninst, int s1, int a); // common coproc helpers // reset the cache void fpu_reset(dynarec_arm_t* dyn); +// reset the cache with n +void fpu_reset_cache(dynarec_arm_t* dyn, int ninst, int reset_n); +// propagate stack state +void fpu_propagate_stack(dynarec_arm_t* dyn, int ninst); // purge the FPU cache (needs 3 scratch registers) next=1 if for a conditionnal branch jumping out of block (no tracking updated) void fpu_purgecache(dynarec_arm_t* dyn, int ninst, int next, int s1, int s2, int s3); void x87_purgecache(dynarec_arm_t* dyn, int ninst, int next, int s1, int s2, int s3); diff --git a/src/dynarec/dynarec_arm_jmpnext.c b/src/dynarec/dynarec_arm_jmpnext.c new file mode 100644 index 00000000..87236204 --- /dev/null +++ b/src/dynarec/dynarec_arm_jmpnext.c @@ -0,0 +1,12 @@ +#include +#include + +#include "arm_emitter.h" + +#define EMIT(A) *block = (A); ++block +void CreateJmpNext(void* addr, void* next) +{ + uint32_t* block = (uint32_t*)addr; + LDR_literal(x2, ((intptr_t)next - (intptr_t)addr)-8); + BX(x2); +} \ No newline at end of file diff --git a/src/dynarec/dynarec_arm_pass.c b/src/dynarec/dynarec_arm_pass.c index b7807f1d..32f2087f 100755 --- a/src/dynarec/dynarec_arm_pass.c +++ b/src/dynarec/dynarec_arm_pass.c @@ -56,44 +56,7 @@ uintptr_t arm_pass(dynarec_arm_t* dyn, uintptr_t addr) dyn->f.pending = 0; fpu_reset(dyn); } else { - MESSAGE(LOG_DEBUG, "Reset Caches with %d\n",reset_n); - #if STEP > 1 - // for STEP 2 & 3, just need to refrest with current, and undo the changes (push & swap) - dyn->n = dyn->insts[ninst].n; - neoncacheUnwind(&dyn->n); - #ifdef HAVE_TRACE - if(box86_dynarec_dump) - if(memcmp(&dyn->n, &dyn->insts[reset_n].n, sizeof(neon_cache_t))) { - MESSAGE(LOG_DEBUG, "Warning, difference in neoncache: reset="); - for(int i=0; i<24; ++i) - if(dyn->insts[reset_n].n.neoncache[i].v) - MESSAGE(LOG_DEBUG, " %02d:%s", i, getCacheName(dyn->insts[reset_n].n.neoncache[i].t, dyn->insts[reset_n].n.neoncache[i].n)); - if(dyn->insts[reset_n].n.combined1 || dyn->insts[reset_n].n.combined2) - MESSAGE(LOG_DEBUG, " %s:%02d/%02d", dyn->insts[reset_n].n.swapped?"SWP":"CMB", dyn->insts[reset_n].n.combined1, dyn->insts[reset_n].n.combined2); - if(dyn->insts[reset_n].n.stack_push || dyn->insts[reset_n].n.stack_pop) - MESSAGE(LOG_DEBUG, " (%d:%d)", dyn->insts[reset_n].n.stack_push, -dyn->insts[reset_n].n.stack_pop); - MESSAGE(LOG_DEBUG, " ==> "); - for(int i=0; i<24; ++i) - if(dyn->insts[ninst].n.neoncache[i].v) - MESSAGE(LOG_DEBUG, " %02d:%s", i, getCacheName(dyn->insts[ninst].n.neoncache[i].t, dyn->insts[ninst].n.neoncache[i].n)); - if(dyn->insts[ninst].n.combined1 || dyn->insts[ninst].n.combined2) - MESSAGE(LOG_DEBUG, " %s:%02d/%02d", dyn->insts[ninst].n.swapped?"SWP":"CMB", dyn->insts[ninst].n.combined1, dyn->insts[ninst].n.combined2); - if(dyn->insts[ninst].n.stack_push || dyn->insts[ninst].n.stack_pop) - MESSAGE(LOG_DEBUG, " (%d:%d)", dyn->insts[ninst].n.stack_push, -dyn->insts[ninst].n.stack_pop); - MESSAGE(LOG_DEBUG, " -> "); - for(int i=0; i<24; ++i) - if(dyn->n.neoncache[i].v) - MESSAGE(LOG_DEBUG, " %02d:%s", i, getCacheName(dyn->n.neoncache[i].t, dyn->n.neoncache[i].n)); - if(dyn->n.combined1 || dyn->n.combined2) - MESSAGE(LOG_DEBUG, " %s:%02d/%02d", dyn->n.swapped?"SWP":"CMB", dyn->n.combined1, dyn->n.combined2); - if(dyn->n.stack_push || dyn->n.stack_pop) - MESSAGE(LOG_DEBUG, " (%d:%d)", dyn->n.stack_push, -dyn->n.stack_pop); - MESSAGE(LOG_DEBUG, "\n"); - } - #endif //HAVE_TRACE - #else - dyn->n = dyn->insts[reset_n].n; - #endif + fpu_reset_cache(dyn, ninst, reset_n); dyn->f = dyn->insts[reset_n].f_exit; if(dyn->insts[ninst].x86.barrier&BARRIER_FLOAT) { MESSAGE(LOG_DEBUG, "Apply Barrier Float\n"); @@ -107,21 +70,7 @@ uintptr_t arm_pass(dynarec_arm_t* dyn, uintptr_t addr) } reset_n = -1; } - // propagate ST stack state, especial stack pop that are defered - if(dyn->n.stack_pop) { - for(int j=0; j<24; ++j) - if((dyn->n.neoncache[j].t == NEON_CACHE_ST_D || dyn->n.neoncache[j].t == NEON_CACHE_ST_F)) { - if(dyn->n.neoncache[j].nn.stack_pop) - dyn->n.neoncache[j].v = 0; - else - dyn->n.neoncache[j].n-=dyn->n.stack_pop; - } - dyn->n.stack_pop = 0; - } - dyn->n.stack = dyn->n.stack_next; - dyn->n.news = 0; - dyn->n.stack_push = 0; - dyn->n.swapped = 0; + fpu_propagate_stack(dyn, ninst); NEW_INST; if(!ninst) { GOTEST(x1, x2); @@ -176,13 +125,26 @@ uintptr_t arm_pass(dynarec_arm_t* dyn, uintptr_t addr) dyn->f.dfnone = 0; } } + #ifndef PROT_READ + #define PROT_READ 1 + #endif #if STEP != 0 if(!ok && !need_epilog && (addr < (dyn->start+dyn->isize))) { ok = 1; // we use the 1st predecessor here int ii = ninst+1; - while(iisize && !dyn->insts[ii].pred_sz) - ++ii; + if(iisize && !dyn->insts[ii].pred_sz) { + while(iisize && (!dyn->insts[ii].pred_sz || (dyn->insts[ii].pred_sz==1 && dyn->insts[ii].pred[0]==ii-1))) { + // may need to skip opcodes to advance + ++ninst; + NEW_INST; + MESSAGE(LOG_DEBUG, "Skipping unused opcode\n"); + INST_NAME("Skipped opcode"); + INST_EPILOG; + addr += dyn->insts[ii].x86.size; + ++ii; + } + } if((dyn->insts[ii].x86.barrier&BARRIER_FULL)==BARRIER_FULL) reset_n = -2; // hack to say Barrier! else { @@ -194,20 +156,18 @@ uintptr_t arm_pass(dynarec_arm_t* dyn, uintptr_t addr) } } #else - #ifndef PROT_READ - #define PROT_READ 1 - #endif if(dyn->forward) { - if(dyn->forward_to == addr) { + if(dyn->forward_to == addr && !need_epilog) { // we made it! - if(box86_dynarec_dump) dynarec_log(LOG_NONE, "Forward extend block %p -> %p\n", (void*)dyn->forward, (void*)dyn->forward_to); + if(box86_dynarec_dump) dynarec_log(LOG_NONE, "Forward extend block for %d bytes %p -> %p\n", dyn->forward_to-dyn->forward, (void*)dyn->forward, (void*)dyn->forward_to); dyn->forward = 0; dyn->forward_to = 0; dyn->forward_size = 0; dyn->forward_ninst = 0; + ok = 1; // in case it was 0 } else if ((dyn->forward_to < addr) || !ok) { // something when wrong! rollback - if(box86_dynarec_dump) dynarec_log(LOG_NONE, "Could not forward extend block %p -> %p\n", (void*)dyn->forward, (void*)dyn->forward_to); + if(box86_dynarec_dump) dynarec_log(LOG_NONE, "Could not forward extend block for %d bytes %p -> %p\n", dyn->forward_to-dyn->forward, (void*)dyn->forward, (void*)dyn->forward_to); ok = 0; dyn->size = dyn->forward_size; ninst = dyn->forward_ninst; @@ -218,12 +178,12 @@ uintptr_t arm_pass(dynarec_arm_t* dyn, uintptr_t addr) dyn->forward_ninst = 0; } // else just continue - } else if(!ok && !need_epilog && box86_dynarec_bigblock && (getProtection(addr+3)&PROT_READ)) + } else if(!ok && !need_epilog && box86_dynarec_bigblock && (getProtection(addr+3)&~PROT_READ)) if(*(uint32_t*)addr!=0) { // check if need to continue (but is next 4 bytes are 0, stop) uintptr_t next = get_closest_next(dyn, addr); if(next && ( (((next-addr)<15) && is_nops(dyn, addr, next-addr)) - /*&& box86_dynarec_bigblock*/)) + /*||(((next-addr)<30) && is_instructions(dyn, addr, next-addr))*/ )) { ok = 1; // need to find back that instruction to copy the caches, as previous version cannot be used anymore @@ -234,30 +194,56 @@ uintptr_t arm_pass(dynarec_arm_t* dyn, uintptr_t addr) ii=ninst; } if(box86_dynarec_dump) dynarec_log(LOG_NONE, "Extend block %p, %p -> %p (ninst=%d, jump from %d)\n", dyn, (void*)addr, (void*)next, ninst, reset_n); - } else if(next && (next-addr=forwardblock*/) { - dyn->forward = addr; - dyn->forward_to = next; - dyn->forward_size = dyn->size; - dyn->forward_ninst = ninst; - reset_n = -2; - ok = 1; + } else if(next && (next-addr)=stopblock*/) { + if(!((box86_dynarec_bigblockforward = addr; + dyn->forward_to = next; + dyn->forward_size = dyn->size; + dyn->forward_ninst = ninst; + reset_n = -2; + ok = 1; + } } } #endif - if(ok<0) {ok = 0; need_epilog=1;} + if(ok<0) { + ok = 0; need_epilog=1; + #if STEP == 0 + if(ninst) { + --ninst; + if(!dyn->insts[ninst].x86.barrier) { + BARRIER(BARRIER_FLOAT); + } + dyn->insts[ninst].x86.need_after |= X_PEND; + ++ninst; + } + #endif + } ++ninst; #if STEP == 0 if(ok && (((box86_dynarec_bigblock=box86_nodynarec_start && addrsize >= 2000)*/)) // is this still needed? maybe it should be a parameter? + || (addr>=box86_nodynarec_start && addrsize)) #endif { + #if STEP == 0 + if(dyn->forward) { + // stopping too soon + dyn->size = dyn->forward_size; + ninst = dyn->forward_ninst+1; + addr = dyn->forward; + dyn->forward = 0; + dyn->forward_to = 0; + dyn->forward_size = 0; + dyn->forward_ninst = 0; + } + #endif int j32; MAYUSE(j32); - MESSAGE(LOG_DEBUG, "Stopping block %p (%d / %d)\n",(void*)init_addr, ninst, dyn->size); + MESSAGE(LOG_DEBUG, "Stopping block %p (%d / %d)\n",(void*)init_addr, ninst, dyn->size); + if(!box86_dynarec_dump && addr>=box86_nodynarec_start && addrinsts[ninst].x86.barrier) { BARRIER(BARRIER_FLOAT); diff --git a/src/dynarec/dynarec_arm_pass0.h b/src/dynarec/dynarec_arm_pass0.h index a7a235c0..3dc654f9 100755 --- a/src/dynarec/dynarec_arm_pass0.h +++ b/src/dynarec/dynarec_arm_pass0.h @@ -4,6 +4,7 @@ dyn->isize = addr-sav_addr;\ dyn->insts[ninst].x86.addr = addr;\ if(ninst) dyn->insts[ninst-1].x86.size = dyn->insts[ninst].x86.addr - dyn->insts[ninst-1].x86.addr + #define MESSAGE(A, ...) #define MAYSETFLAGS() dyn->insts[ninst].x86.may_set = 1 #define READFLAGS(A) \ @@ -15,13 +16,13 @@ dyn->f.pending=(B)&SF_SET_PENDING; \ dyn->f.dfnone=((B)&SF_SET)?1:0; #define EMIT(A) -#define JUMP(A, C) if((A)>addr) add_next(dyn, (uintptr_t)(A)); dyn->insts[ninst].x86.jmp = A; dyn->insts[ninst].x86.jmp_cond = C +#define JUMP(A, C) add_next(dyn, (uintptr_t)A); dyn->insts[ninst].x86.jmp = A; dyn->insts[ninst].x86.jmp_cond = C #define BARRIER(A) if(A!=BARRIER_MAYBE) {fpu_purgecache(dyn, ninst, 0, x1, x2, x3); dyn->insts[ninst].x86.barrier = A;} else dyn->insts[ninst].barrier_maybe = 1 #define BARRIER_NEXT(A) dyn->insts[ninst+1].x86.barrier = A #define NEW_INST \ ++dyn->size; \ if(dyn->size+3>=dyn->cap) { \ - dyn->insts = (instruction_arm_t*)box_realloc(dyn->insts, sizeof(instruction_arm_t)*dyn->cap*2); \ + dyn->insts = (instruction_arm_t*)customRealloc(dyn->insts, sizeof(instruction_arm_t)*dyn->cap*2);\ memset(&dyn->insts[dyn->cap], 0, sizeof(instruction_arm_t)*dyn->cap); \ dyn->cap *= 2; \ } \ diff --git a/src/dynarec/dynarec_arm_pass1.h b/src/dynarec/dynarec_arm_pass1.h index f51ca538..6cf92feb 100755 --- a/src/dynarec/dynarec_arm_pass1.h +++ b/src/dynarec/dynarec_arm_pass1.h @@ -2,7 +2,6 @@ #define FINI #define MESSAGE(A, ...) #define EMIT(A) - #define NEW_INST \ dyn->insts[ninst].f_entry = dyn->f; \ dyn->n.combined1 = dyn->n.combined2 = 0;\ diff --git a/src/dynarec/dynarec_arm_pass2.h b/src/dynarec/dynarec_arm_pass2.h index 6d57612f..b942a56d 100755 --- a/src/dynarec/dynarec_arm_pass2.h +++ b/src/dynarec/dynarec_arm_pass2.h @@ -1,11 +1,16 @@ #define INIT dyn->arm_size = 0 -#define FINI if(ninst) {dyn->insts[ninst].address = (dyn->insts[ninst-1].address+dyn->insts[ninst-1].size);} +#define FINI \ + if(ninst) { \ + dyn->insts[ninst].address = (dyn->insts[ninst-1].address+dyn->insts[ninst-1].size); \ + dyn->insts_size += 1+((dyn->insts[ninst].x86.size>dyn->insts[ninst].size)?dyn->insts[ninst].x86.size:dyn->insts[ninst].size)/15; \ + } #define MESSAGE(A, ...) -#define EMIT(A) dyn->insts[ninst].size+=4; dyn->arm_size+=4 +#define EMIT(A) do{dyn->insts[ninst].size+=4; dyn->arm_size+=4;}while(0) #define NEW_INST \ if(ninst) { \ dyn->insts[ninst].address = (dyn->insts[ninst-1].address+dyn->insts[ninst-1].size); \ + dyn->insts_size += 1+((dyn->insts[ninst-1].x86.size>dyn->insts[ninst-1].size)?dyn->insts[ninst-1].x86.size:dyn->insts[ninst-1].size)/15; \ } #define INST_EPILOG dyn->insts[ninst].epilog = dyn->arm_size; #define INST_NAME(name) diff --git a/src/dynarec/dynarec_arm_pass3.h b/src/dynarec/dynarec_arm_pass3.h index 7611229a..7713e738 100755 --- a/src/dynarec/dynarec_arm_pass3.h +++ b/src/dynarec/dynarec_arm_pass3.h @@ -1,10 +1,16 @@ #define INIT -#define FINI -#define EMIT(A) \ - if(box86_dynarec_dump) print_opcode(dyn, ninst, (uint32_t)(A)); \ - *(uint32_t*)(dyn->block) = A; \ - dyn->block += 4; dyn->arm_size += 4; \ - dyn->insts[ninst].size2 += 4 +#define FINI \ + if(ninst) \ + addInst(dyn->instsize, &dyn->insts_size, dyn->insts[ninst].x86.size, dyn->insts[ninst].size/4); \ + addInst(dyn->instsize, &dyn->insts_size, 0, 0); +#define EMIT(A) \ + do{ \ + if(box86_dynarec_dump) print_opcode(dyn, ninst, (uint32_t)(A)); \ + if((uintptr_t)dyn->block<(uintptr_t)dyn->next-sizeof(void*))\ + *(uint32_t*)(dyn->block) = (uint32_t)(A); \ + dyn->block += 4; dyn->arm_size += 4; \ + dyn->insts[ninst].size2 += 4; \ + }while(0) #define MESSAGE(A, ...) if(box86_dynarec_dump) dynarec_log(LOG_NONE, __VA_ARGS__) // warning, there is some logic, handing of sons, in newinst_pass3 diff --git a/src/dynarec/dynarec_arm_private.h b/src/dynarec/dynarec_arm_private.h index 05961dc1..c1775569 100755 --- a/src/dynarec/dynarec_arm_private.h +++ b/src/dynarec/dynarec_arm_private.h @@ -5,6 +5,7 @@ typedef struct x86emu_s x86emu_t; typedef struct dynablock_s dynablock_t; +typedef struct instsize_s instsize_t; #define BARRIER_MAYBE 8 @@ -90,6 +91,7 @@ typedef struct dynarec_arm_s { void* block; // memory pointer where next instruction is emited uintptr_t arm_start; // start of the arm code int arm_size; // size of emitted arm code + 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 @@ -97,12 +99,15 @@ typedef struct dynarec_arm_s { int next_cap; int* predecessor;// single array of all predecessor dynablock_t* dynablock; + instsize_t* instsize; + size_t insts_size; // size of the instruction size array (calculated) uint8_t smread; // for strongmem model emulation uint8_t smwrite; // for strongmem model emulation uintptr_t forward; // address of the last end of code while testing forward 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_arm_t; void add_next(dynarec_arm_t *dyn, uintptr_t addr); @@ -110,4 +115,6 @@ 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); +void CreateJmpNext(void* addr, void* next); + #endif //__DYNAREC_ARM_PRIVATE_H_ \ No newline at end of file diff --git a/src/include/box86context.h b/src/include/box86context.h index 60b9e9c9..2cf51703 100755 --- a/src/include/box86context.h +++ b/src/include/box86context.h @@ -38,6 +38,7 @@ typedef struct kh_dynablocks_s kh_dynablocks_t; #define DYNAMAP_SIZE (1<<(32-DYNAMAP_SHIFT)) #define JMPTABL_SHIFT 16 #define JMPTABL_SIZE (1<<(32-JMPTABL_SHIFT)) +#define JMPTABLE_MASK ((1<jmpbuf, 1); } @@ -728,6 +728,9 @@ void my_sigactionhandler_oldcode(int32_t sig, int simple, int Locks, siginfo_t* } extern void* current_helper; +#ifdef DYNAREC +static uint32_t mutex_dynarec_prot = 0; +#endif void my_box86signalhandler(int32_t sig, siginfo_t* info, void * ucntx) { @@ -759,19 +762,20 @@ void my_box86signalhandler(int32_t sig, siginfo_t* info, void * ucntx) #endif #ifdef DYNAREC if((Locks & is_dyndump_locked) && (sig==SIGSEGV) && current_helper) { - relockMutex(Locks); - CancelBlock(); + CancelBlock(0); cancelFillBlock(); // Segfault inside a Fillblock + relockMutex(Locks); } dynablock_t* db = NULL; int db_searched = 0; if ((sig==SIGSEGV) && (addr) && (info->si_code == SEGV_ACCERR) && (prot&PROT_CUSTOM)) { + mutex_lock(&mutex_dynarec_prot); // 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 // check if SMC inside block db = FindDynablockFromNativeAddress(pc); db_searched = 1; - int db_need_test = db?db->need_test:0; + int db_need_test = (db && !box86_dynarec_fastpage)?getNeedTest((uintptr_t)db->x86_addr):0; dynarec_log(LOG_INFO/*LOG_DEBUG*/, "SIGSEGV with Access error on %p for %p , db=%p(%p)\n", pc, addr, db, db?((void*)db->x86_addr):NULL); static uintptr_t repeated_page = 0; static int repeated_count = 0; @@ -810,41 +814,46 @@ void my_box86signalhandler(int32_t sig, siginfo_t* info, void * ucntx) dynarec_log(LOG_INFO, "Dynablock %p(%p) unprotected, getting out (arm pc=%p, x86_pc=%p, special=%d)!\n", db, db->x86_addr, pc, (void*)ejb->emu->ip.dword[0], special); } //relockMutex(Locks); // do not relock because of he siglongjmp - #ifdef DYNAREC + mutex_unlock(&mutex_dynarec_prot); if(Locks & is_dyndump_locked) - CancelBlock(); + CancelBlock(1); ejb->emu->test.clean = 0; - #endif siglongjmp(ejb->jmpbuf, 2); } dynarec_log(LOG_INFO, "Warning, Auto-SMC (%p for db %p/%p) detected, but jmpbuffer not ready!\n", (void*)addr, db, (void*)db->x86_addr); } // done if(prot&PROT_WRITE) { + mutex_unlock(&mutex_dynarec_prot); // if there is no write permission, don't return and continue to program signal handling relockMutex(Locks); return; } + mutex_unlock(&mutex_dynarec_prot); } else if ((sig==SIGSEGV) && (addr) && (info->si_code == SEGV_ACCERR) && (prot&(PROT_READ|PROT_WRITE))) { + mutex_lock(&mutex_dynarec_prot); db = FindDynablockFromNativeAddress(pc); db_searched = 1; if(db && db->x86_addr>= addr && (db->x86_addr+db->x86_size)si_code == SEGV_ACCERR) && (prot&PROT_DYNAREC_R)) { + // unprotect and continue to signal handler, because Write is not there on purpose + unprotectDB((uintptr_t)addr, 1, 1); // unprotect 1 byte... But then, the whole page will be unprotected } + if(!db_searched) + db = FindDynablockFromNativeAddress(pc); #else void* db = NULL; #endif @@ -940,7 +956,7 @@ exit(-1); emu->init_stack, emu->init_stack+emu->size_stack, emu->stack2free, (void*)R_EBP, addr, info->si_code, prot, db, db?db->block:0, db?(db->block+db->size):0, db?db->x86_addr:0, db?(db->x86_addr+db->x86_size):0, - getAddrFunctionName((uintptr_t)(db?db->x86_addr:0)), (db?db->need_test:0)?"need_stest":"clean", db?db->hash:0, hash); + getAddrFunctionName((uintptr_t)(db?db->x86_addr:0)), (db?getNeedTest((uintptr_t)db->x86_addr):0)?"need_stest":"clean", db?db->hash:0, hash); #if defined(ARM) static const char* reg_name[] = {"EAX", "ECX", "EDX", "EBX", "ESP", "EBP", "ESI", "EDI"}; if(db) @@ -1336,7 +1352,12 @@ EXPORT int my_swapcontext(x86emu_t* emu, void* ucp1, void* ucp2) my_setcontext(emu, ucp2); return 0; } - +#ifdef DYNAREC +static void atfork_child_dynarec_prot(void) +{ + arm_lock_stored(&mutex_dynarec_prot, 0); +} +#endif void init_signal_helper(box86context_t* context) { // setup signal handling @@ -1355,6 +1376,10 @@ void init_signal_helper(box86context_t* context) sigaction(SIGILL, &action, NULL); pthread_once(&sigstack_key_once, sigstack_key_alloc); +#ifdef DYNAREC + atfork_child_dynarec_prot(); + pthread_atfork(NULL, NULL, atfork_child_dynarec_prot); +#endif } void fini_signal_helper() diff --git a/src/libtools/threads.c b/src/libtools/threads.c index d02c4432..1e4e87e9 100755 --- a/src/libtools/threads.c +++ b/src/libtools/threads.c @@ -312,7 +312,7 @@ EXPORT int my_pthread_create(x86emu_t *emu, void* t, void* attr, void* start_rou if(box86_dynarec) { // pre-creation of the JIT code for the entry point of the thread dynablock_t *current = NULL; - DBGetBlock(emu, (uintptr_t)start_routine, 1, ¤t); + DBGetBlock(emu, (uintptr_t)start_routine, 1); } #endif // create thread @@ -336,7 +336,7 @@ void* my_prepare_thread(x86emu_t *emu, void* f, void* arg, int ssize, void** pet if(box86_dynarec) { // pre-creation of the JIT code for the entry point of the thread dynablock_t *current = NULL; - DBGetBlock(emu, (uintptr_t)f, 1, ¤t); + DBGetBlock(emu, (uintptr_t)f, 1); } #endif *pet = et; diff --git a/src/main.c b/src/main.c index 219b56dd..27a21b44 100755 --- a/src/main.c +++ b/src/main.c @@ -65,6 +65,8 @@ int box86_dynarec_fastround = 1; int box86_dynarec_safeflags = 1; int box86_dynarec_hotpage = 16; int box86_dynarec_bleeding_edge = 1; +int box86_dynarec_wait = 1; +int box86_dynarec_fastpage = 0; uintptr_t box86_nodynarec_start = 0; uintptr_t box86_nodynarec_end = 0; int box86_dynarec_test = 0; @@ -416,6 +418,15 @@ void LoadLogEnv() else printf_log(LOG_INFO, "Dynarec will play %s safe with x86 flags\n", (box86_dynarec_safeflags==1)?"moderatly":"it"); } + p = getenv("BOX86_DYNAREC_WAIT"); + if(p) { + if(strlen(p)==1) { + if(p[0]>='0' && p[0]<='1') + box86_dynarec_wait = p[0]-'0'; + } + if(!box86_dynarec_wait) + printf_log(LOG_INFO, "Dynarec will not wait for FillBlock to ready and use Interpreter instead\n"); + } p = getenv("BOX86_DYNAREC_HOTPAGE"); if(p) { int val = -1; @@ -428,7 +439,15 @@ void LoadLogEnv() else printf_log(LOG_INFO, "Dynarec will not tag HotPage\n"); } - p = getenv("BOX86_DYNAREC_BLEEDING_EDGE"); + p = getenv("BOX86_DYNAREC_FASTPAGE"); + if(p) { + if(strlen(p)==1) { + if(p[0]>='0' && p[0]<='1') + box86_dynarec_fastpage = p[0]-'0'; + } + if(box86_dynarec_fastpage) + printf_log(LOG_INFO, "Dynarec will use Fast HotPage\n"); + } p = getenv("BOX86_DYNAREC_BLEEDING_EDGE"); if(p) { if(strlen(p)==1) { if(p[0]>='0' && p[0]<='1') diff --git a/src/tools/rcfile.c b/src/tools/rcfile.c index d0a68bbc..c7da0ad4 100644 --- a/src/tools/rcfile.c +++ b/src/tools/rcfile.c @@ -81,6 +81,8 @@ ENTRYBOOL(BOX86_DYNAREC_FASTNAN, box86_dynarec_fastnan) \ ENTRYBOOL(BOX86_DYNAREC_FASTROUND, box86_dynarec_fastround) \ ENTRYINT(BOX86_DYNAREC_SAFEFLAGS, box86_dynarec_safeflags, 0, 2, 2) \ ENTRYINT(BOX86_DYNAREC_HOTPAGE, box86_dynarec_hotpage, 0, 255, 8) \ +ENTRYBOOL(BOX86_DYNAREC_FASTPAGE, box86_dynarec_fastpage) \ +ENTRYBOOL(BOX86_DYNAREC_WAIT, box86_dynarec_wait) \ ENTRYBOOL(BOX86_DYNAREC_BLEEDING_EDGE, box86_dynarec_bleeding_edge) \ ENTRYSTRING_(BOX86_NODYNAREC, box86_nodynarec) \ ENTRYBOOL(BOX86_DYNAREC_TEST, box86_dynarec_test) \ @@ -91,13 +93,15 @@ IGNORE(BOX86_DYNAREC) \ IGNORE(BOX86_DYNAREC_DUMP) \ IGNORE(BOX86_DYNAREC_LOG) \ IGNORE(BOX86_DYNAREC_BIGBLOCK) \ -IGNORE(BOX64_DYNAREC_FORWARD) \ +IGNORE(BOX86_DYNAREC_FORWARD) \ IGNORE(BOX86_DYNAREC_STRONGMEM) \ IGNORE(BOX86_DYNAREC_X87DOUBLE) \ IGNORE(BOX86_DYNAREC_FASTNAN) \ IGNORE(BOX86_DYNAREC_FASTROUND) \ IGNORE(BOX86_DYNAREC_SAFEFLAGS) \ IGNORE(BOX86_DYNAREC_HOTPAGE) \ +IGNORE(BOX86_DYNAREC_FASTPAGE) \ +IGNORE(BOX86_DYNAREC_WAIT) \ IGNORE(BOX86_DYNAREC_BLEEDING_EDGE) \ IGNORE(BOX86_NODYNAREC) \ IGNORE(BOX86_DYNAREC_TEST) \ diff --git a/src/wrapped/wrappedlibc.c b/src/wrapped/wrappedlibc.c index b6fc3662..683f81fc 100755 --- a/src/wrapped/wrappedlibc.c +++ b/src/wrapped/wrappedlibc.c @@ -3038,7 +3038,7 @@ EXPORT int my_munmap(x86emu_t* emu, void* addr, unsigned long length) } #endif int ret = munmap(addr, length); - if(!ret) + if(!ret && length) freeProtection((uintptr_t)addr, length); return ret; } @@ -3051,14 +3051,14 @@ EXPORT int my_mprotect(x86emu_t* emu, void *addr, unsigned long len, int prot) prot|=PROT_READ; // PROT_READ is implicit with PROT_WRITE on i386 int ret = mprotect(addr, len, prot); #ifdef DYNAREC - if(box86_dynarec) { + if(box86_dynarec && len) { if(prot& PROT_EXEC) addDBFromAddressRange((uintptr_t)addr, len); else cleanDBFromAddressRange((uintptr_t)addr, len, 0); } #endif - if(!ret) + if(!ret && len) updateProtection((uintptr_t)addr, len, prot); return ret; }