mirror of
https://github.com/ptitSeb/box86.git
synced 2026-11-07 17:08:19 -10:00
Compare commits
11
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9c6f99f583 | ||
|
|
5eb76327ff | ||
|
|
795dd3b305 | ||
|
|
3b389b979a | ||
|
|
ff92ae2db5 | ||
|
|
20cae21475 | ||
|
|
dfc63d3e46 | ||
|
|
af78a2e58b | ||
|
|
babbcab3da | ||
|
|
363851f9d2 | ||
|
|
905043012e |
No files matched your search
@@ -516,6 +516,7 @@ if(ARM_DYNAREC)
|
||||
"${BOX86_ROOT}/src/dynarec/dynarec_arm.c"
|
||||
"${BOX86_ROOT}/src/dynarec/dynarec_arm_functions.c"
|
||||
"${BOX86_ROOT}/src/dynarec/arm_printer.c"
|
||||
"${BOX86_ROOT}/src/dynarec/arm_jmpnext.c"
|
||||
|
||||
"${BOX86_ROOT}/src/dynarec/arm_prolog.S"
|
||||
"${BOX86_ROOT}/src/dynarec/arm_epilog.S"
|
||||
|
||||
+232
-91
@@ -25,6 +25,7 @@
|
||||
#ifdef DYNAREC
|
||||
#include "dynablock.h"
|
||||
#include "dynarec/arm_lock_helper.h"
|
||||
#include "dynarec/dynarec_next.h"
|
||||
#include "khash.h"
|
||||
|
||||
#define USE_MMAP
|
||||
@@ -32,7 +33,6 @@
|
||||
|
||||
// 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;
|
||||
static int mmapsize = 0;
|
||||
static int mmapcap = 0;
|
||||
@@ -45,7 +45,12 @@ static kh_lockaddress_t *lockaddress = NULL;
|
||||
#endif
|
||||
#define MEMPROT_SHIFT 12
|
||||
#define MEMPROT_SIZE (1<<(32-MEMPROT_SHIFT))
|
||||
static uint8_t memprot[MEMPROT_SIZE] = {0}; // protection flags by 4K block
|
||||
typedef struct memprot_s
|
||||
{
|
||||
uint8_t prot;
|
||||
uint8_t hot;
|
||||
} memprot_t;
|
||||
static memprot_t memprot[MEMPROT_SIZE] = {0}; // protection flags by 4K block
|
||||
static int inited = 0;
|
||||
|
||||
typedef struct mapmem_s {
|
||||
@@ -59,13 +64,15 @@ typedef struct blocklist_s {
|
||||
void* block;
|
||||
int maxfree;
|
||||
size_t size;
|
||||
void* first;
|
||||
} blocklist_t;
|
||||
|
||||
#define MMAPSIZE (256*1024) // allocate 256kb sized blocks
|
||||
|
||||
static pthread_mutex_t mutex_blocks;
|
||||
static int n_blocks = 0; // number of blocks for custom malloc
|
||||
static blocklist_t* p_blocks = NULL; // actual blocks for custom malloc
|
||||
static int n_blocks = 0; // number of blocks for custom malloc
|
||||
static int c_blocks = 0; // capacity of blocks for custom malloc
|
||||
static blocklist_t* p_blocks = NULL; // actual blocks for custom malloc
|
||||
|
||||
typedef union mark_s {
|
||||
struct {
|
||||
@@ -109,6 +116,23 @@ 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
|
||||
@@ -239,19 +263,37 @@ 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<THRESHOLD)
|
||||
size = THRESHOLD;
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
void* customMalloc(size_t size)
|
||||
{
|
||||
size = roundSize(size);
|
||||
// look for free space
|
||||
void* sub = NULL;
|
||||
size_t fullsize = size+2*sizeof(blockmark_t);
|
||||
pthread_mutex_lock(&mutex_blocks);
|
||||
for(int i=0; i<n_blocks; ++i) {
|
||||
if(p_blocks[i].maxfree>=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-size<THRESHOLD)
|
||||
size = rsize;
|
||||
void* ret = allocBlock(p_blocks[i].block, sub, size, NULL);
|
||||
if(rsize==p_blocks[i].maxfree)
|
||||
p_blocks[i].maxfree = getMaxFreeBlock(p_blocks[i].block, p_blocks[i].size, NULL);
|
||||
p_blocks[i].maxfree = getMaxFreeBlock(p_blocks[i].block, p_blocks[i].size, p_blocks[i].first);
|
||||
pthread_mutex_unlock(&mutex_blocks);
|
||||
return ret;
|
||||
}
|
||||
@@ -259,10 +301,11 @@ void* customMalloc(size_t size)
|
||||
}
|
||||
// add a new block
|
||||
int i = n_blocks++;
|
||||
p_blocks = (blocklist_t*)box_realloc(p_blocks, n_blocks*sizeof(blocklist_t));
|
||||
size_t allocsize = MMAPSIZE;
|
||||
if(size+2*sizeof(blockmark_t)>allocsize)
|
||||
allocsize = size+2*sizeof(blockmark_t);
|
||||
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_MORE
|
||||
void* p = mmap(NULL, allocsize, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_PRIVATE, -1, 0);
|
||||
memset(p, 0, allocsize);
|
||||
@@ -271,6 +314,7 @@ void* customMalloc(size_t size)
|
||||
void* p = box_calloc(1, 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;
|
||||
@@ -289,7 +333,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;
|
||||
@@ -298,6 +342,7 @@ void* customRealloc(void* p, size_t size)
|
||||
{
|
||||
if(!p)
|
||||
return customMalloc(size);
|
||||
size = roundSize(size);
|
||||
uintptr_t addr = (uintptr_t)p;
|
||||
pthread_mutex_lock(&mutex_blocks);
|
||||
for(int i=0; i<n_blocks; ++i) {
|
||||
@@ -305,7 +350,9 @@ void* customRealloc(void* p, size_t size)
|
||||
&& (addr<((uintptr_t)p_blocks[i].block+p_blocks[i].size))) {
|
||||
void* sub = (void*)(addr-sizeof(blockmark_t));
|
||||
if(expandBlock(p_blocks[i].block, sub, size)) {
|
||||
p_blocks[i].maxfree = getMaxFreeBlock(p_blocks[i].block, p_blocks[i].size, NULL);
|
||||
if(sub<p_blocks[i].first && p+size<p_blocks[i].first)
|
||||
p_blocks[i].first = getNextFreeBlock(sub);
|
||||
p_blocks[i].maxfree = getMaxFreeBlock(p_blocks[i].block, p_blocks[i].size, p_blocks[i].first);
|
||||
pthread_mutex_unlock(&mutex_blocks);
|
||||
return p;
|
||||
}
|
||||
@@ -331,7 +378,10 @@ void customFree(void* p)
|
||||
if ((addr>(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;
|
||||
pthread_mutex_unlock(&mutex_blocks);
|
||||
return;
|
||||
@@ -358,35 +408,40 @@ uintptr_t FindFreeDynarecMap(dynablock_t* db, int size)
|
||||
// look for free space
|
||||
void* sub = NULL;
|
||||
for(int i=0; i<mmapsize; ++i) {
|
||||
if(mmaplist[i].maxfree>=size+sizeof(blockmark_t) && !mmaplist[i].locked) {
|
||||
mmaplist[i].locked = 1;
|
||||
size_t rsize = 0;
|
||||
sub = getFirstBlock(mmaplist[i].block, size, &rsize, mmaplist[i].first);
|
||||
if(sub) {
|
||||
uintptr_t ret = (uintptr_t)allocBlock(mmaplist[i].block, sub, size, &mmaplist[i].first);
|
||||
if(rsize==mmaplist[i].maxfree) {
|
||||
mmaplist[i].maxfree = getMaxFreeBlock(mmaplist[i].block, mmaplist[i].size, mmaplist[i].first);
|
||||
if(mmaplist[i].maxfree>=size+sizeof(blockmark_t)) {
|
||||
if(!arm_lock_xchg(&mmaplist[i].locked, 1)) {
|
||||
size_t rsize = 0;
|
||||
sub = getFirstBlock(mmaplist[i].block, size, &rsize, mmaplist[i].first);
|
||||
if(sub) {
|
||||
uintptr_t ret = (uintptr_t)allocBlock(mmaplist[i].block, sub, size, &mmaplist[i].first);
|
||||
if(rsize==mmaplist[i].maxfree) {
|
||||
mmaplist[i].maxfree = getMaxFreeBlock(mmaplist[i].block, mmaplist[i].size, mmaplist[i].first);
|
||||
}
|
||||
kh_dynablocks_t *blocks = mmaplist[i].dblist;
|
||||
if(!blocks) {
|
||||
blocks = mmaplist[i].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; j<size255; ++j)
|
||||
mmaplist[i].helper[(uintptr_t)ret-(uintptr_t)mmaplist[i].block+j] = j;
|
||||
if(size!=size255)
|
||||
memset(&mmaplist[i].helper[(uintptr_t)ret-(uintptr_t)mmaplist[i].block+256], -1, size-255);
|
||||
arm_lock_store(&mmaplist[i].locked, 0);
|
||||
return ret;
|
||||
} else {
|
||||
printf_log(LOG_INFO, "BOX86: Warning, sub not found, corrupted mmaplist[%d] info (requested size=%d)?\n", i, size);
|
||||
if(box86_log >= LOG_DEBUG)
|
||||
printBlock(mmaplist[i].block, mmaplist[i].first);
|
||||
// reset block meta info
|
||||
mmaplist[i].first = getFirstBlock(mmaplist[i].block, 1, &rsize, NULL);
|
||||
mmaplist[i].maxfree = getMaxFreeBlock(mmaplist[i].block, mmaplist[i].size, NULL);
|
||||
arm_lock_store(&mmaplist[i].locked, 0);
|
||||
}
|
||||
kh_dynablocks_t *blocks = mmaplist[i].dblist;
|
||||
if(!blocks) {
|
||||
blocks = mmaplist[i].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; j<size255; ++j)
|
||||
mmaplist[i].helper[(uintptr_t)ret-(uintptr_t)mmaplist[i].block+j] = j;
|
||||
if(size!=size255)
|
||||
memset(&mmaplist[i].helper[(uintptr_t)ret-(uintptr_t)mmaplist[i].block+256], -1, size-255);
|
||||
mmaplist[i].locked = 0;
|
||||
return ret;
|
||||
} else {
|
||||
printf_log(LOG_INFO, "BOX86: Warning, sub not found, corrupted mmaplist[%d] info?\n", i);
|
||||
if(box86_log >= LOG_DEBUG)
|
||||
printBlock(mmaplist[i].block, mmaplist[i].first);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -419,7 +474,7 @@ uintptr_t AddNewDynarecMap(dynablock_t* db, int size)
|
||||
#endif
|
||||
setProtection((uintptr_t)p, MMAPSIZE, PROT_READ | PROT_WRITE | PROT_EXEC);
|
||||
|
||||
mmaplist[i].locked = 1;
|
||||
arm_lock_store(&mmaplist[i].locked, 1);
|
||||
mmaplist[i].block = p;
|
||||
mmaplist[i].size = MMAPSIZE;
|
||||
mmaplist[i].helper = (uint8_t*)box_calloc(1, MMAPSIZE);
|
||||
@@ -444,7 +499,7 @@ uintptr_t AddNewDynarecMap(dynablock_t* db, int size)
|
||||
kh_value(blocks, k) = db;
|
||||
for(int j=0; j<size; ++j)
|
||||
mmaplist[i].helper[(uintptr_t)sub-(uintptr_t)mmaplist[i].block + j] = (j<256)?j:255;
|
||||
mmaplist[i].locked = 0;
|
||||
arm_lock_store(&mmaplist[i].locked, 0);
|
||||
return sub;
|
||||
}
|
||||
|
||||
@@ -455,6 +510,12 @@ void ActuallyFreeDynarecMap(dynablock_t* db, uintptr_t addr, int size)
|
||||
for(int i=0; i<mmapsize; ++i) {
|
||||
if ((addr>(uintptr_t)mmaplist[i].block)
|
||||
&& (addr<((uintptr_t)mmaplist[i].block+mmaplist[i].size))) {
|
||||
// wait the map is free
|
||||
int cnt = 100;
|
||||
while(my_context && cnt && arm_lock_store_xchg(&mmaplist[i].locked, (void*)1)) {
|
||||
--cnt;
|
||||
sched_yield();
|
||||
}
|
||||
void* sub = (void*)(addr-sizeof(blockmark_t));
|
||||
size_t newfree = freeBlock(mmaplist[i].block, sub, &mmaplist[i].first);
|
||||
if(mmaplist[i].maxfree < newfree) mmaplist[i].maxfree = newfree;
|
||||
@@ -465,10 +526,7 @@ void ActuallyFreeDynarecMap(dynablock_t* db, uintptr_t addr, int size)
|
||||
kh_del(dynablocks, blocks, k);
|
||||
memset(&mmaplist[i].helper[(uintptr_t)sub-(uintptr_t)mmaplist[i].block], 0, size);
|
||||
}
|
||||
if(mmaplist[i].locked) {
|
||||
printf_log(LOG_INFO, "BOX86: Warning, Free a chunk in a locked mmaplist[%d]\n", i);
|
||||
++mmaplist[i].locked;
|
||||
}
|
||||
arm_lock_store(&mmaplist[i].locked, 0);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -558,9 +616,23 @@ void FreeDynarecMap(dynablock_t* db, uintptr_t addr, uint32_t size)
|
||||
ActuallyFreeDynarecMap(db, addr, size);
|
||||
}
|
||||
|
||||
dynablocklist_t* getDB(uintptr_t idx)
|
||||
dynablock_t* getDB(uintptr_t addr)
|
||||
{
|
||||
return dynmap[idx];
|
||||
if(isJumpTableDefault((void*)addr))
|
||||
return NULL;
|
||||
uintptr_t ret = getJumpAddress(addr);
|
||||
return *(dynablock_t**)(ret-sizeof(void*));
|
||||
}
|
||||
|
||||
uintptr_t getDefaultSize(uintptr_t addr)
|
||||
{
|
||||
uintptr_t idx = ((uintptr_t)addr>>JMPTABL_SHIFT);
|
||||
if(box86_jumptable[idx] == box86_jmptbl_default)
|
||||
return (addr&~((1<<JMPTABL_SHIFT)-1)|0xffff)-addr + 1;
|
||||
uintptr_t idx0 = addr&0xffff;
|
||||
while(box86_jumptable[idx][idx0]==(uintptr_t)arm_next)
|
||||
++idx0;
|
||||
return idx0 - (addr&0xffff);
|
||||
}
|
||||
|
||||
// each dynmap is 64k of size
|
||||
@@ -568,38 +640,30 @@ dynablocklist_t* getDB(uintptr_t idx)
|
||||
void addDBFromAddressRange(uintptr_t addr, uintptr_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<<DYNAMAP_SHIFT, 1<<DYNAMAP_SHIFT, 0);
|
||||
if(arm_lock_storeifnull(&dynmap[i], p)!=p)
|
||||
FreeDynablockList(&p);
|
||||
}
|
||||
}
|
||||
// do nothing, dynablock are allowed based on memory protection flags
|
||||
}
|
||||
|
||||
void cleanDBFromAddressRange(uintptr_t addr, uintptr_t size, int destroy)
|
||||
{
|
||||
dynarec_log(LOG_DEBUG, "cleanDBFromAddressRange %p -> %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) {
|
||||
dynablocklist_t* dblist = dynmap[i];
|
||||
if(dblist) {
|
||||
uintptr_t start_addr = my_context?((addr<my_context->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");
|
||||
for (uintptr_t i=start_addr; i<addr+size; ++i) {
|
||||
dynablock_t* db = getDB(i);
|
||||
if(db) {
|
||||
if(destroy)
|
||||
FreeRangeDynablock(dblist, addr, size);
|
||||
FreeRangeDynablock(db, addr, size);
|
||||
else
|
||||
MarkRangeDynablock(dblist, addr, size);
|
||||
MarkRangeDynablock(db, addr, size);
|
||||
} else {
|
||||
uintptr_t next = getDefaultSize(i);
|
||||
if(next)
|
||||
i+=next-1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef ARM
|
||||
void arm_next(void);
|
||||
#endif
|
||||
|
||||
void addJumpTableIfDefault(void* addr, void* jmp)
|
||||
int addJumpTableIfDefault(void* addr, void* jmp)
|
||||
{
|
||||
const uintptr_t idx = ((uintptr_t)addr>>JMPTABL_SHIFT);
|
||||
if(box86_jumptable[idx] == box86_jmptbl_default) {
|
||||
@@ -610,7 +674,7 @@ void addJumpTableIfDefault(void* addr, void* jmp)
|
||||
box_free(tbl);
|
||||
}
|
||||
const uintptr_t off = (uintptr_t)addr&((1<<JMPTABL_SHIFT)-1);
|
||||
arm_lock_storeifref(&box86_jumptable[idx][off], jmp, arm_next);
|
||||
return (arm_lock_storeifref(&box86_jumptable[idx][off], jmp, arm_next)==jmp)?1:0;
|
||||
}
|
||||
void setJumpTableDefault(void* addr)
|
||||
{
|
||||
@@ -621,6 +685,28 @@ void setJumpTableDefault(void* addr)
|
||||
const uintptr_t off = (uintptr_t)addr&((1<<JMPTABL_SHIFT)-1);
|
||||
box86_jumptable[idx][off] = (uintptr_t)arm_next;
|
||||
}
|
||||
void setJumpTableDefaultRef(void* addr, void* jmp)
|
||||
{
|
||||
const uintptr_t idx = ((uintptr_t)addr>>JMPTABL_SHIFT);
|
||||
if(box86_jumptable[idx] == box86_jmptbl_default) {
|
||||
return;
|
||||
}
|
||||
const uintptr_t off = (uintptr_t)addr&((1<<JMPTABL_SHIFT)-1);
|
||||
arm_lock_storeifref(&box86_jumptable[idx][off], arm_next, jmp);
|
||||
}
|
||||
void setJumpTableIfRef(void* addr, void* jmp, void* ref)
|
||||
{
|
||||
const uintptr_t idx = ((uintptr_t)addr>>JMPTABL_SHIFT);
|
||||
if(box86_jumptable[idx] == box86_jmptbl_default) {
|
||||
uintptr_t* tbl = (uintptr_t*)box_malloc((1<<JMPTABL_SHIFT)*sizeof(uintptr_t));
|
||||
for(int i=0; i<(1<<JMPTABL_SHIFT); ++i)
|
||||
tbl[i] = (uintptr_t)arm_next;
|
||||
if(arm_lock_storeifref(&box86_jumptable[idx], tbl, box86_jmptbl_default)!=tbl)
|
||||
box_free(tbl);
|
||||
}
|
||||
const uintptr_t off = (uintptr_t)addr&((1<<JMPTABL_SHIFT)-1);
|
||||
arm_lock_storeifref(&box86_jumptable[idx][off], jmp, ref);
|
||||
}
|
||||
int isJumpTableDefault(void* addr)
|
||||
{
|
||||
const uintptr_t idx = ((uintptr_t)addr>>JMPTABL_SHIFT);
|
||||
@@ -649,6 +735,20 @@ uintptr_t getJumpTableAddress(uintptr_t addr)
|
||||
return (uintptr_t)&box86_jumptable[idx][off];
|
||||
}
|
||||
|
||||
uintptr_t getJumpAddress(uintptr_t addr)
|
||||
{
|
||||
const uintptr_t idx = ((uintptr_t)addr>>JMPTABL_SHIFT);
|
||||
if(box86_jumptable[idx] == box86_jmptbl_default) {
|
||||
uintptr_t* tbl = (uintptr_t*)box_malloc((1<<JMPTABL_SHIFT)*sizeof(uintptr_t));
|
||||
for(int i=0; i<(1<<JMPTABL_SHIFT); ++i)
|
||||
tbl[i] = (uintptr_t)arm_next;
|
||||
if(arm_lock_storeifref(&box86_jumptable[idx], tbl, box86_jmptbl_default)!=tbl)
|
||||
box_free(tbl);
|
||||
}
|
||||
const uintptr_t off = (uintptr_t)addr&((1<<JMPTABL_SHIFT)-1);
|
||||
return (uintptr_t)box86_jumptable[idx][off];
|
||||
}
|
||||
|
||||
// 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)
|
||||
@@ -657,16 +757,16 @@ void protectDB(uintptr_t addr, uintptr_t size)
|
||||
uintptr_t idx = (addr>>MEMPROT_SHIFT);
|
||||
uintptr_t end = ((addr+size-1)>>MEMPROT_SHIFT);
|
||||
for (uintptr_t i=idx; i<=end; ++i) {
|
||||
uint32_t prot = memprot[i];
|
||||
uint32_t prot = memprot[i].prot;
|
||||
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
|
||||
if(prot&PROT_WRITE) {
|
||||
memprot[i] = prot|PROT_DYNAREC;
|
||||
memprot[i].prot = prot|PROT_DYNAREC;
|
||||
if(!dyn) mprotect((void*)(i<<MEMPROT_SHIFT), 1<<MEMPROT_SHIFT, prot&~PROT_WRITE);
|
||||
} else
|
||||
memprot[i] = prot|PROT_DYNAREC_R;
|
||||
memprot[i].prot = prot|PROT_DYNAREC_R;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -678,17 +778,52 @@ void unprotectDB(uintptr_t addr, uintptr_t size, int mark)
|
||||
uintptr_t idx = (addr>>MEMPROT_SHIFT);
|
||||
uintptr_t end = ((addr+size-1)>>MEMPROT_SHIFT);
|
||||
for (uintptr_t i=idx; i<=end; ++i) {
|
||||
uint32_t prot = memprot[i];
|
||||
uint32_t prot = memprot[i].prot;
|
||||
if(prot&PROT_DYNAREC) {
|
||||
memprot[i] = prot&~PROT_DYNAREC;
|
||||
memprot[i].prot = prot&~PROT_DYNAREC;
|
||||
mprotect((void*)(i<<MEMPROT_SHIFT), 1<<MEMPROT_SHIFT, prot&~PROT_DYNAREC);
|
||||
if(mark)
|
||||
cleanDBFromAddressRange((i<<MEMPROT_SHIFT), 1<<MEMPROT_SHIFT, 0);
|
||||
} else if(prot&PROT_DYNAREC_R)
|
||||
memprot[i] = prot&~(PROT_CUSTOM);
|
||||
memprot[i].prot = prot&~(PROT_CUSTOM);
|
||||
}
|
||||
}
|
||||
|
||||
#define HOTPAGE_STEP 16
|
||||
int IsInHotPage(uintptr_t addr) {
|
||||
uintptr_t idx = (addr>>MEMPROT_SHIFT);
|
||||
if(!memprot[idx].hot)
|
||||
return 0;
|
||||
// decrement hot
|
||||
arm_lock_dec_b(&memprot[idx].hot);
|
||||
return 1;
|
||||
}
|
||||
|
||||
int AreaInHotPage(uintptr_t start, uintptr_t end_) {
|
||||
//dynarec_log(LOG_DEBUG, "AreaInHotPage %p -> %p => ", (void*)start, (void*)end_);
|
||||
uintptr_t idx = (start>>MEMPROT_SHIFT);
|
||||
uintptr_t end = (end_>>MEMPROT_SHIFT);
|
||||
if(end<idx) { // memory addresses higher than 48bits are not tracked
|
||||
//dynarec_log(LOG_DEBUG, "00\n");
|
||||
return 0;
|
||||
}
|
||||
for (uintptr_t i=idx; i<=end; ++i) {
|
||||
if(memprot[i].hot) {
|
||||
// decrement hot
|
||||
arm_lock_dec_b(&memprot[i].hot);
|
||||
//dynarec_log(LOG_DEBUG, "1\n");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
//dynarec_log(LOG_DEBUG, "0\n");
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
||||
void AddHotPage(uintptr_t addr) {
|
||||
int idx = (addr>>MEMPROT_SHIFT);
|
||||
arm_lock_store_b(&memprot[idx].hot, HOTPAGE_STEP);
|
||||
}
|
||||
#endif
|
||||
|
||||
void printMapMem()
|
||||
@@ -788,15 +923,18 @@ void updateProtection(uintptr_t addr, uintptr_t size, uint32_t prot)
|
||||
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=(memprot[i]&(PROT_DYNAREC|PROT_DYNAREC_R));
|
||||
uint32_t dyn=(memprot[i].prot&(PROT_DYNAREC|PROT_DYNAREC_R));
|
||||
if(dyn && (prot&PROT_WRITE)) { // need to remove the write protection from this block
|
||||
dyn = PROT_DYNAREC;
|
||||
mprotect((void*)(i<<MEMPROT_SHIFT), 1<<MEMPROT_SHIFT, prot&~PROT_WRITE);
|
||||
} else if(dyn && !(prot&PROT_WRITE)) {
|
||||
dyn = PROT_DYNAREC_R;
|
||||
}
|
||||
|
||||
memprot[i] = prot|dyn;
|
||||
#ifdef DYNAREC
|
||||
arm_lock_store_b(&memprot[i].prot, prot|dyn);
|
||||
#else
|
||||
memprot[i].prot = prot|dyn;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -808,7 +946,11 @@ void forceProtection(uintptr_t addr, uintptr_t size, uint32_t prot)
|
||||
const uintptr_t end = ((addr+size-1)>>MEMPROT_SHIFT);
|
||||
for (uintptr_t i=idx; i<=end; ++i) {
|
||||
mprotect((void*)(i<<MEMPROT_SHIFT), 1<<MEMPROT_SHIFT, prot&~PROT_CUSTOM);
|
||||
memprot[i] = prot;
|
||||
#ifdef DYNAREC
|
||||
arm_lock_store_b(&memprot[i].prot, prot);
|
||||
#else
|
||||
memprot[i].prot=prot;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -821,7 +963,11 @@ void setProtection(uintptr_t addr, uintptr_t size, uint32_t prot)
|
||||
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] = prot;
|
||||
#ifdef DYNAREC
|
||||
arm_lock_store_b(&memprot[i].prot, prot);
|
||||
#else
|
||||
memprot[i].prot=prot;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
@@ -831,14 +977,15 @@ void freeProtection(uintptr_t addr, uintptr_t size)
|
||||
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;
|
||||
memprot[i].prot = 0;
|
||||
memprot[i].hot = 0;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t getProtection(uintptr_t addr)
|
||||
{
|
||||
const uintptr_t idx = (addr>>MEMPROT_SHIFT);
|
||||
uint32_t ret = memprot[idx];
|
||||
uint32_t ret = memprot[idx].prot;
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -848,8 +995,8 @@ void allocProtection(uintptr_t addr, uintptr_t size, uint32_t prot)
|
||||
const uintptr_t idx = (addr>>MEMPROT_SHIFT);
|
||||
const uintptr_t end = ((addr+size-1)>>MEMPROT_SHIFT);
|
||||
for (uintptr_t i=idx; i<=end; ++i) {
|
||||
if(!memprot[i])
|
||||
memprot[i] = prot;
|
||||
if(!memprot[i].prot)
|
||||
memprot[i].prot = prot;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1013,12 +1160,6 @@ void fini_custommem_helper(box86context_t *ctx)
|
||||
}
|
||||
mmapsize = 0;
|
||||
mmapcap = 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<DYNAMAP_SIZE; ++i)
|
||||
if(box86_jumptable[i]!=box86_jmptbl_default)
|
||||
|
||||
@@ -391,6 +391,8 @@ Op is 20-27
|
||||
// ldrd reg, reg+1, [addr, +rm], reg must be even, reg+1 is implicit
|
||||
#define LDRD_REG(reg, addr, rm) EMIT(c__ | 0b000<<25 | 1<<24 | 1<<23 | 0<<22 | 0<<21 | 0<<20 | ((reg) << 12) | ((addr) << 16) | 0b1101<<4 | (rm) )
|
||||
|
||||
#define LDR_litteral(reg, imm12) EMIT(c__ | 0b010<<25 | 0<<24 | ((imm12<0)?0:1)<<23 | 0<<22 | 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) )
|
||||
// str with cond reg, [addr, #+/-imm9]
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "arm_emitter.h"
|
||||
|
||||
#define EMIT(A) *block = (A); ++block
|
||||
void CreateJmpNextTo(void* addr, void* tonext)
|
||||
{
|
||||
uint32_t* block = (uint32_t*)addr;
|
||||
MOV32(x3, (uintptr_t)tonext);
|
||||
BX(x3);
|
||||
}
|
||||
@@ -16,6 +16,11 @@
|
||||
.global arm_lock_xchg
|
||||
.global arm_lock_storeifnull
|
||||
.global arm_lock_storeifref
|
||||
.global arm_lock_store_xchg
|
||||
.global arm_lock_dec
|
||||
.global arm_lock_dec_b
|
||||
.global arm_lock_store
|
||||
.global arm_lock_store_b
|
||||
|
||||
|
||||
arm_lock_read_b:
|
||||
@@ -113,3 +118,46 @@ arm_lock_storeifref_exit:
|
||||
mov r0, r3
|
||||
pop {r4}
|
||||
bx lr
|
||||
|
||||
arm_lock_store_xchg:
|
||||
// address is r0, value is r1, r1 store to r0 only if [r0] is 0. return new [r0] value (so r1 or old value)
|
||||
// r0 needs to be aligned
|
||||
ldrex r2, [r0]
|
||||
cmp r2, #0
|
||||
bne arm_lock_store_xchg_exit
|
||||
mov r2, r1
|
||||
strex r3, r2, [r0]
|
||||
cmp r3, #1
|
||||
beq arm_lock_store_xchg
|
||||
mov r2, #0
|
||||
arm_lock_store_xchg_exit:
|
||||
mov r0, r2
|
||||
bx lr
|
||||
|
||||
arm_lock_dec:
|
||||
dmb ish
|
||||
ldrex r1, [r0]
|
||||
sub r1, r1, #1
|
||||
strex r2, r1, [r0]
|
||||
cmp r2, #1
|
||||
beq arm_lock_dec
|
||||
bx lr
|
||||
|
||||
arm_lock_dec_b:
|
||||
dmb ish
|
||||
ldrexb r1, [r0]
|
||||
sub r1, r1, #1
|
||||
strexb r2, r1, [r0]
|
||||
cmp r2, #1
|
||||
beq arm_lock_dec_b
|
||||
bx lr
|
||||
|
||||
arm_lock_store:
|
||||
str r1, [r0]
|
||||
dmb ish
|
||||
bx lr
|
||||
|
||||
arm_lock_store_b:
|
||||
strb r1, [r0]
|
||||
dmb ish
|
||||
bx lr
|
||||
@@ -31,4 +31,19 @@ extern void* arm_lock_storeifnull(void* p, void* val);
|
||||
// Atomically store value to [p] only if [p] is ref. Return new [p] value (so val or old)
|
||||
extern void* arm_lock_storeifref(void* p, void* val, void* ref);
|
||||
|
||||
// Atomically store value to [p] only if [p] is NULL. Return old [p] value
|
||||
extern void* arm_lock_store_xchg(void* p, void* val);
|
||||
|
||||
// will decrease *p atomicaly
|
||||
extern void arm_lock_dec_b(uint8_t* p);
|
||||
|
||||
// will decrease *p atomicaly
|
||||
extern void arm_lock_dec(int* p);
|
||||
|
||||
// store value, with data memory barrier
|
||||
extern void arm_lock_store_b(uint8_t* p, uint8_t val);
|
||||
|
||||
// store value, with data memory barrier
|
||||
extern void arm_lock_store(int* p, int val);
|
||||
|
||||
#endif //__ARM_LOCK_HELPER__H__
|
||||
+96
-280
@@ -4,6 +4,7 @@
|
||||
#include <errno.h>
|
||||
#include <sys/mman.h>
|
||||
#include <setjmp.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
#include "debug.h"
|
||||
#include "box86context.h"
|
||||
@@ -20,6 +21,7 @@
|
||||
#include "dynablock_private.h"
|
||||
#include "dynarec_private.h"
|
||||
#include "elfloader.h"
|
||||
#include "bridge.h"
|
||||
#ifdef ARM
|
||||
#include "dynarec_arm.h"
|
||||
#include "arm_lock_helper.h"
|
||||
@@ -40,108 +42,36 @@ uint32_t X31_hash_code(void* addr, int len)
|
||||
return (uint32_t)h;
|
||||
}
|
||||
|
||||
dynablocklist_t* NewDynablockList(uintptr_t text, int textsz, int direct)
|
||||
{
|
||||
if(!textsz) {
|
||||
printf_log(LOG_NONE, "Error, creating a NULL sized Dynablock\n");
|
||||
return NULL;
|
||||
}
|
||||
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);}
|
||||
}
|
||||
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)
|
||||
{
|
||||
if(db) {
|
||||
if(db->gone)
|
||||
return; // already in the process of deletion!
|
||||
dynarec_log(LOG_DEBUG, "FreeDynablock(%p), db->block=%p x86=%p:%p father=%p, with %d son(s) already gone=%d\n", db, db->block, db->x86_addr, db->x86_addr+db->x86_size, db->father, db->sons_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, db->gone);
|
||||
if(need_lock)
|
||||
pthread_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 && addr<enddb)
|
||||
db->parent->direct[addr-startdb] = NULL;
|
||||
}
|
||||
// remove jumptable
|
||||
setJumpTableDefault(db->x86_addr);
|
||||
// remove and free the sons
|
||||
for (int i=0; i<db->sons_size; ++i) {
|
||||
dynablock_t *son = (dynablock_t*)arm_lock_xchg(&db->sons[i], 0);
|
||||
FreeDynablock(son, 0);
|
||||
}
|
||||
// only the father free the DynarecMap
|
||||
if(!db->father) {
|
||||
dynarec_log(LOG_DEBUG, " -- FreeDyrecMap(%p, %d)\n", db->block, db->size);
|
||||
FreeDynarecMap(db, (uintptr_t)db->block, db->size);
|
||||
box_free(db->sons);
|
||||
box_free(db->instsize);
|
||||
}
|
||||
dynarec_log(LOG_DEBUG, " -- FreeDyrecMap(%p, %d)\n", db->actual_block, db->size);
|
||||
db->done = 0;
|
||||
db->gone = 1;
|
||||
FreeDynarecMap(db, (uintptr_t)db->actual_block, db->size);
|
||||
box_free(db);
|
||||
if(need_lock)
|
||||
pthread_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] && !(*dynablocks)->direct[i]->father)
|
||||
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->father)
|
||||
db = db->father; // mark only father
|
||||
if(db->need_test)
|
||||
return; // already done
|
||||
db->need_test = 1;
|
||||
setJumpTableDefault(db->x86_addr);
|
||||
for(int i=0; i<db->sons_size; ++i)
|
||||
setJumpTableDefault(db->sons[i]->x86_addr);
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if(start1 > end2 || start2 > end1)
|
||||
@@ -149,81 +79,27 @@ int IntervalIntersects(uintptr_t start1, uintptr_t end1, uintptr_t start2, uintp
|
||||
return 1;
|
||||
}
|
||||
|
||||
void MarkDirectDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size)
|
||||
void MarkRangeDynablock(dynablock_t* db, uintptr_t addr, uintptr_t size)
|
||||
{
|
||||
if(!dynablocks)
|
||||
if(!db)
|
||||
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(start<startdb)
|
||||
start = startdb;
|
||||
if(end>enddb)
|
||||
end = enddb;
|
||||
dynablock_t *db;
|
||||
if(end>startdb && start<enddb)
|
||||
for(uintptr_t i = start; i<end; ++i)
|
||||
if((db=dynablocks->direct[i-startdb]))
|
||||
if(IntervalIntersects((uintptr_t)db->x86_addr, (uintptr_t)db->x86_addr+db->x86_size-1, addr, addr+size+1))
|
||||
MarkDynablock(db);
|
||||
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(!db->need_test)
|
||||
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)
|
||||
int FreeRangeDynablock(dynablock_t* db, uintptr_t addr, uintptr_t size)
|
||||
{
|
||||
if(!dynablocks)
|
||||
return;
|
||||
if(!db)
|
||||
return 1;
|
||||
|
||||
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(start<startdb)
|
||||
start = startdb;
|
||||
if(end>enddb)
|
||||
end = enddb;
|
||||
if(end>startdb && start<enddb)
|
||||
for(uintptr_t i = start; i<end; ++i) {
|
||||
db = (dynablock_t*)arm_lock_xchg(&dynablocks->direct[i-startdb], 0);
|
||||
if(db) {
|
||||
if(db->father)
|
||||
db = db->father;
|
||||
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);
|
||||
}
|
||||
}
|
||||
void MarkRangeDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size)
|
||||
{
|
||||
if(!dynablocks)
|
||||
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);
|
||||
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)
|
||||
@@ -235,66 +111,27 @@ dynablock_t* FindDynablockDynablocklist(void* addr, kh_dynablocks_t* dynablocks)
|
||||
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<e)
|
||||
return db->father?db->father:db;
|
||||
return db;
|
||||
)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static dynablocklist_t* getDBFromAddress(uintptr_t addr)
|
||||
dynablock_t *AddNewDynablock(uintptr_t addr)
|
||||
{
|
||||
const int idx = (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((addr<dynablocks->text) || (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;
|
||||
|
||||
#endif
|
||||
pthread_mutex_lock(&my_context->mutex_dyndump);
|
||||
if(!dynablocks->direct) {
|
||||
dynablock_t** p = (dynablock_t**)box_calloc(dynablocks->textsz, sizeof(dynablock_t*));
|
||||
if(arm_lock_storeifnull(&dynablocks->direct, p)!=p)
|
||||
box_free(p); // someone already create the direct array, too late...
|
||||
}
|
||||
|
||||
// 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_storeifnull(&dynablocks->direct[addr-dynablocks->text], block);
|
||||
pthread_mutex_unlock(&my_context->mutex_dyndump);
|
||||
if(tmp != block) {
|
||||
// a block appeard!
|
||||
box_free(block);
|
||||
*created = 0;
|
||||
return tmp;
|
||||
}
|
||||
*created = 1;
|
||||
return block;
|
||||
}
|
||||
|
||||
@@ -310,39 +147,28 @@ 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)
|
||||
{
|
||||
// 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)
|
||||
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;
|
||||
if(hasAlternate((void*)addr))
|
||||
return NULL;
|
||||
dynablock_t* block = getDB(addr);
|
||||
if(block || !create)
|
||||
return block;
|
||||
|
||||
int created = create;
|
||||
block = AddNewDynablock(dynablocks, addr, &created);
|
||||
if(!created)
|
||||
return block; // existing block...
|
||||
if(need_lock)
|
||||
pthread_mutex_lock(&my_context->mutex_dyndump);
|
||||
|
||||
block = getDB(addr); // just in case
|
||||
if(block) {
|
||||
if(need_lock)
|
||||
pthread_mutex_unlock(&my_context->mutex_dyndump);
|
||||
return block;
|
||||
}
|
||||
|
||||
block = AddNewDynablock(addr);
|
||||
|
||||
// fill the block
|
||||
block->x86_addr = (void*)addr;
|
||||
if(need_lock)
|
||||
pthread_mutex_lock(&my_context->mutex_dyndump);
|
||||
if(sigsetjmp(&dynarec_jmpbuf, 1)) {
|
||||
printf_log(LOG_INFO, "FillBlock at %p triggered a segfault, cancelling\n", (void*)addr);
|
||||
if(need_lock)
|
||||
@@ -354,68 +180,60 @@ static dynablock_t* internalDBGetBlock(x86emu_t* emu, uintptr_t addr, uintptr_t
|
||||
pthread_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);
|
||||
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->maxsz<blocksz) {
|
||||
dynablocks->maxsz = blocksz;
|
||||
for(int idx=(addr>>DYNAMAP_SHIFT)+1; idx<=((addr+blocksz)>>DYNAMAP_SHIFT); ++idx) {
|
||||
dynablocklist_t* dblist;
|
||||
if((dblist = getDB(idx)))
|
||||
if(dblist->maxsz<blocksz)
|
||||
dblist->maxsz = 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 || (block->father && block->father->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);
|
||||
for(int i=0; i<block->sons_size; ++i)
|
||||
addJumpTableIfDefault(block->sons[i]->x86_addr, block->sons[i]->block);
|
||||
if(!addJumpTableIfDefault(block->x86_addr, block->block)) {
|
||||
FreeDynablock(block, 1);
|
||||
block = getDB(addr);
|
||||
} 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)
|
||||
pthread_mutex_unlock(&my_context->mutex_dyndump);
|
||||
|
||||
dynarec_log(LOG_DEBUG, " --- DynaRec Block %s @%p:%p (%p, 0x%x bytes, with %d son(s))\n", created?"created":"recycled", (void*)addr, (void*)(addr+((block)?block->x86_size:0)), (block)?block->block:0, (block)?block->size:0, (block)?block->sons_size:0);
|
||||
dynarec_log(LOG_DEBUG, " --- DynaRec Block created @%p:%p (%p, 0x%x bytes)\n", (void*)addr, (void*)(addr+((block)?block->x86_size:0)), (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 || (db->father && db->father->need_test))) {
|
||||
if(pthread_mutex_trylock(&my_context->mutex_dyndump))
|
||||
dynablock_t *db = internalDBGetBlock(emu, addr, addr, create, 1);
|
||||
if(db && db->done && db->block && db->need_test) {
|
||||
if(AreaInHotPage((uintptr_t)db->x86_addr, (uintptr_t)db->x86_addr + db->x86_size - 1)) {
|
||||
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;
|
||||
dynablock_t *father = db->father?db->father:db;
|
||||
uint32_t hash = (getProtection((uintptr_t)father->x86_addr)&PROT_READ)?X31_hash_code(father->x86_addr, father->x86_size):0;
|
||||
if(hash!=father->hash) {
|
||||
dynarec_log(LOG_DEBUG, "Invalidating block %p from %p:%p (hash:%X/%X) with %d son(s) for %p\n", father, father->x86_addr, father->x86_addr+father->x86_size, hash, father->hash, father->sons_size, (void*)addr);
|
||||
// no more current if it gets invalidated too
|
||||
if(*current && father->x86_addr>=(*current)->x86_addr && (father->x86_addr+father->x86_size)<(*current)->x86_addr)
|
||||
*current = NULL;
|
||||
// Free father, it's now invalid!
|
||||
FreeDynablock(father, 0);
|
||||
}
|
||||
uint32_t hash = X31_hash_code(db->x86_addr, db->x86_size);
|
||||
if(pthread_mutex_trylock(&my_context->mutex_dyndump)) {
|
||||
dynarec_log(LOG_DEBUG, "mutex_dyndump not available when trying to validate block %p from %p:%p (hash:%X) for %p\n", db, db->x86_addr, db->x86_addr+db->x86_size-1, db->hash, (void*)addr);
|
||||
return NULL;
|
||||
}
|
||||
if(hash!=db->hash) {
|
||||
db->done = 0; // invalidating the block
|
||||
dynarec_log(LOG_DEBUG, "Invalidating block %p from %p:%p (hash:%X/%X) for %p\n", db, db->x86_addr, db->x86_addr+db->x86_size-1, hash, db->hash, (void*)addr);
|
||||
// Free db, it's now invalid!
|
||||
FreeDynablock(db, 0);
|
||||
// start again... (will create a new block)
|
||||
db = internalDBGetBlock(emu, addr, addr, create, *current, 0);
|
||||
db = internalDBGetBlock(emu, addr, addr, create, 0);
|
||||
} else {
|
||||
father->need_test = 0;
|
||||
protectDB((uintptr_t)father->x86_addr, father->x86_size);
|
||||
// fill back jumptable
|
||||
addJumpTableIfDefault(father->x86_addr, father->block);
|
||||
for(int i=0; i<father->sons_size; ++i)
|
||||
addJumpTableIfDefault(father->sons[i]->x86_addr, father->sons[i]->block);
|
||||
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
|
||||
setJumpTableIfRef(db->x86_addr, db->block, db->jmpnext);
|
||||
}
|
||||
pthread_mutex_unlock(&my_context->mutex_dyndump);
|
||||
}
|
||||
}
|
||||
return db;
|
||||
}
|
||||
|
||||
@@ -423,27 +241,25 @@ 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 || (db->father && db->father->need_test))) {
|
||||
dynablock_t *db = internalDBGetBlock(emu, addr, filladdr, create, 1);
|
||||
if(db && db->done && db->block && db->need_test) {
|
||||
if(pthread_mutex_trylock(&my_context->mutex_dyndump))
|
||||
return NULL;
|
||||
dynablock_t *father = db->father?db->father:db;
|
||||
uint32_t hash = (getProtection((uintptr_t)father->x86_addr)&PROT_READ)?X31_hash_code(father->x86_addr, father->x86_size):0;
|
||||
if(hash!=father->hash) {
|
||||
dynarec_log(LOG_DEBUG, "Invalidating alt block %p from %p:%p (hash:%X/%X) with %d son(s) for %p\n", father, father->x86_addr, father->x86_addr+father->x86_size, hash, father->hash, father->sons_size, (void*)addr);
|
||||
// Free father, it's now invalid!
|
||||
FreeDynablock(father, 0);
|
||||
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);
|
||||
// start again... (will create a new block)
|
||||
db = internalDBGetBlock(emu, addr, filladdr, create, NULL, 0);
|
||||
db = internalDBGetBlock(emu, addr, filladdr, create, 0);
|
||||
} else {
|
||||
father->need_test = 0;
|
||||
protectDB((uintptr_t)father->x86_addr, father->x86_size);
|
||||
db->need_test = 0;
|
||||
protectDB((uintptr_t)db->x86_addr, db->x86_size);
|
||||
// fill back jumptable
|
||||
addJumpTableIfDefault(father->x86_addr, father->block);
|
||||
for(int i=0; i<father->sons_size; ++i)
|
||||
addJumpTableIfDefault(father->sons[i]->x86_addr, father->sons[i]->block);
|
||||
addJumpTableIfDefault(db->x86_addr, db->block);
|
||||
}
|
||||
pthread_mutex_unlock(&my_context->mutex_dyndump);
|
||||
}
|
||||
return db;
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,15 @@
|
||||
#ifndef __DYNABLOCK_PRIVATE_H_
|
||||
#define __DYNABLOCK_PRIVATE_H_
|
||||
|
||||
typedef struct dynablocklist_s dynablocklist_t;
|
||||
|
||||
typedef struct instsize_s {
|
||||
unsigned int x86:4;
|
||||
unsigned int nat:4;
|
||||
unsigned char x86:4;
|
||||
unsigned char nat:4;
|
||||
} 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*))
|
||||
int size;
|
||||
void* x86_addr;
|
||||
uintptr_t x86_size;
|
||||
@@ -20,17 +19,8 @@ typedef struct dynablock_s {
|
||||
uint8_t gone;
|
||||
uint8_t dummy;
|
||||
int isize;
|
||||
dynablock_t** sons; // sons (kind-of dummy dynablock...)
|
||||
int sons_size;
|
||||
dynablock_t* father; // set only in the case of a son
|
||||
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_
|
||||
+7
-18
@@ -20,12 +20,7 @@
|
||||
#include "dynablock.h"
|
||||
#include "dynablock_private.h"
|
||||
#include "bridge.h"
|
||||
#endif
|
||||
|
||||
#ifdef ARM
|
||||
void arm_prolog(x86emu_t* emu, void* addr) EXPORTDYN;
|
||||
void arm_epilog() EXPORTDYN;
|
||||
void arm_epilog_fast() EXPORTDYN;
|
||||
#include "dynarec_next.h"
|
||||
#endif
|
||||
|
||||
#ifdef DYNAREC
|
||||
@@ -44,9 +39,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)) {
|
||||
@@ -54,7 +48,7 @@ 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
|
||||
@@ -114,18 +108,15 @@ void DynaCall(x86emu_t* emu, uintptr_t addr)
|
||||
PushExit(emu);
|
||||
R_EIP = addr;
|
||||
emu->df = d_none;
|
||||
dynablock_t* block = NULL;
|
||||
dynablock_t* current = NULL;
|
||||
while(!emu->quit) {
|
||||
block = DBGetBlock(emu, R_EIP, 1, ¤t);
|
||||
current = block;
|
||||
dynablock_t* block = DBGetBlock(emu, R_EIP, 1);
|
||||
if(!block || !block->block || !block->done) {
|
||||
// no block, of block doesn't have DynaRec content (yet, temp is not null)
|
||||
// Use interpreter (should use single instruction step...)
|
||||
dynarec_log(LOG_DEBUG, "%04d|Calling Interpretor @%p, emu=%p\n", GetTID(), (void*)R_EIP, emu);
|
||||
Run(emu, 1);
|
||||
} else {
|
||||
dynarec_log(LOG_DEBUG, "%04d|Calling DynaRec Block @%p (%p) of %d x86 instructions (father=%p) emu=%p\n", GetTID(), (void*)R_EIP, block->block, block->isize ,block->father, emu);
|
||||
dynarec_log(LOG_DEBUG, "%04d|Calling DynaRec Block @%p (%p) of %d x86 instructions emu=%p\n", GetTID(), (void*)R_EIP, block->block, block->isize ,emu);
|
||||
CHECK_FLAGS(emu);
|
||||
// block is here, let's run it!
|
||||
#ifdef ARM
|
||||
@@ -200,17 +191,15 @@ int DynaRun(x86emu_t* emu)
|
||||
#ifdef DYNAREC
|
||||
else {
|
||||
dynablock_t* block = NULL;
|
||||
dynablock_t* current = NULL;
|
||||
while(!emu->quit) {
|
||||
block = DBGetBlock(emu, R_EIP, 1, ¤t);
|
||||
current = block;
|
||||
block = DBGetBlock(emu, R_EIP, 1);
|
||||
if(!block || !block->block || !block->done) {
|
||||
// no block, of block doesn't have DynaRec content (yet, temp is not null)
|
||||
// Use interpreter (should use single instruction step...)
|
||||
dynarec_log(LOG_DEBUG, "%04d|Running Interpretor @%p, emu=%p\n", GetTID(), (void*)R_EIP, emu);
|
||||
Run(emu, 1);
|
||||
} else {
|
||||
dynarec_log(LOG_DEBUG, "%04d|Running DynaRec Block @%p (%p) of %d x86 insts (father=%p) emu=%p\n", GetTID(), (void*)R_EIP, block->block, block->isize, block->father, emu);
|
||||
dynarec_log(LOG_DEBUG, "%04d|Running DynaRec Block @%p (%p) of %d x86 insts emu=%p\n", GetTID(), (void*)R_EIP, block->block, block->isize, emu);
|
||||
// block is here, let's run it!
|
||||
#ifdef ARM
|
||||
arm_prolog(emu, block->block);
|
||||
|
||||
+73
-92
@@ -23,6 +23,7 @@
|
||||
#include "dynarec_arm_private.h"
|
||||
#include "dynarec_arm_functions.h"
|
||||
#include "elfloader.h"
|
||||
#include "dynarec_next.h"
|
||||
|
||||
void printf_x86_instruction(zydis_dec_t* dec, instruction_x86_t* inst, const char* name) {
|
||||
uint8_t *ip = (uint8_t*)inst->addr;
|
||||
@@ -368,17 +369,47 @@ void CancelBlock()
|
||||
return;
|
||||
box_free(helper->next);
|
||||
box_free(helper->insts);
|
||||
box_free(helper->instsize);
|
||||
box_free(helper->predecessor);
|
||||
if(helper->dynablock && helper->dynablock->block)
|
||||
FreeDynarecMap(helper->dynablock, (uintptr_t)helper->dynablock->block, helper->dynablock->size);
|
||||
if(helper->dynablock && helper->dynablock->actual_block)
|
||||
FreeDynarecMap(helper->dynablock, (uintptr_t)helper->dynablock->actual_block, helper->dynablock->size);
|
||||
else if(helper->dynablock && helper->block)
|
||||
FreeDynarecMap(helper->dynablock, (uintptr_t)helper->block-sizeof(void*), helper->dynablock->size);
|
||||
}
|
||||
|
||||
void* CreateEmptyBlock(dynablock_t* block, uintptr_t addr) {
|
||||
block->isize = 0;
|
||||
block->done = 0;
|
||||
size_t sz = 4*sizeof(void*);
|
||||
void* actual_p = (void*)AllocDynarecMap(block, 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();
|
||||
return NULL;
|
||||
}
|
||||
block->size = sz;
|
||||
block->actual_block = actual_p;
|
||||
block->block = p;
|
||||
block->jmpnext = p;
|
||||
*(dynablock_t**)actual_p = block;
|
||||
CreateJmpNextTo(block->jmpnext, arm_epilog);
|
||||
block->need_test = 0;
|
||||
// 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) {
|
||||
dynarec_log(LOG_DEBUG, "Asked to Fill block %p with %p\n", block, (void*)addr);
|
||||
if(addr>=box86_nodynarec_start && addr<box86_nodynarec_end) {
|
||||
dynarec_log(LOG_DEBUG, "Asked to fill a block in fobidden zone\n");
|
||||
if(IsInHotPage(addr)) {
|
||||
dynarec_log(LOG_DEBUG, "Cancelling dynarec FillBlock on hotpage for %p\n", (void*)addr);
|
||||
return NULL;
|
||||
}
|
||||
if(addr>=box86_nodynarec_start && addr<box86_nodynarec_end) {
|
||||
dynarec_log(LOG_INFO, "Create empty block in no-dynarec 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;
|
||||
@@ -401,7 +432,7 @@ dynarec_log(LOG_DEBUG, "Asked to Fill block %p with %p\n", block, (void*)addr);
|
||||
if(!helper.size) {
|
||||
dynarec_log(LOG_DEBUG, "Warning, null-sized dynarec block (%p)\n", (void*)addr);
|
||||
CancelBlock();
|
||||
return (void*)block;
|
||||
return CreateEmptyBlock(block, addr);
|
||||
}
|
||||
// already protect the block and compute hash signature
|
||||
protectDB(addr, end-addr); //end is 1byte after actual end
|
||||
@@ -427,44 +458,7 @@ dynarec_log(LOG_DEBUG, "Asked to Fill block %p with %p\n", block, (void*)addr);
|
||||
}
|
||||
// fill predecessors with the jump address
|
||||
fillPredecessors(&helper);
|
||||
// check for the optionnal barriers now
|
||||
/*for(int i=helper.size-1; i>=0; --i) {
|
||||
if(helper.insts[i].barrier_maybe) {
|
||||
// out-of-block jump
|
||||
if(helper.insts[i].x86.jmp_insts == -1) {
|
||||
// nothing for now
|
||||
} else {
|
||||
// inside block jump
|
||||
int k = helper.insts[i].x86.jmp_insts;
|
||||
if(k>i) {
|
||||
// jump in the future
|
||||
if(helper.insts[k].pred_sz>1) {
|
||||
// with multiple flow, put a barrier
|
||||
helper.insts[k].x86.barrier|=BARRIER_FLAGS;
|
||||
}
|
||||
} else {
|
||||
// jump back
|
||||
helper.insts[k].x86.barrier|=BARRIER_FLAGS;
|
||||
}
|
||||
}
|
||||
}
|
||||
}*/
|
||||
// check to remove useless barrier, in case of jump when destination doesn't needs flags
|
||||
/*for(int i=helper.size-1; i>=0; --i) {
|
||||
int k;
|
||||
if(helper.insts[i].x86.jmp
|
||||
&& ((k=helper.insts[i].x86.jmp_insts)>=0)
|
||||
&& helper.insts[k].x86.barrier&BARRIER_FLAGS) {
|
||||
//TODO: optimize FPU barrier too
|
||||
if((!helper.insts[k].x86.need_flags)
|
||||
||(helper.insts[k].x86.set_flags==X_ALL
|
||||
&& helper.insts[k].x86.state_flags==SF_SET)
|
||||
||(helper.insts[k].x86.state_flags==SF_SET_PENDING)) {
|
||||
//if(box86_dynarec_dump) dynarec_log(LOG_NONE, "Removed barrier for inst %d\n", k);
|
||||
helper.insts[k].x86.barrier &= ~BARRIER_FLAGS; // remove flag barrier
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
int pos = helper.size;
|
||||
while (pos>=0)
|
||||
pos = updateNeed(&helper, pos, 0);
|
||||
@@ -474,29 +468,44 @@ 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) {
|
||||
// keep size of instructions for signal handling
|
||||
size_t insts_ursize = 0;
|
||||
{
|
||||
size_t insts_size = 0;
|
||||
size_t cap = 1;
|
||||
for(int i=0; i<helper.size; ++i)
|
||||
cap += 1 + ((helper.insts[i].x86.size>helper.insts[i].size)?helper.insts[i].x86.size:helper.insts[i].size)/15;
|
||||
helper.instsize = (instsize_t*)box_calloc(cap, sizeof(instsize_t));
|
||||
for(int i=0; i<helper.size; ++i)
|
||||
helper.instsize = addInst(helper.instsize, &insts_size, &cap, helper.insts[i].x86.size, helper.insts[i].size/4);
|
||||
helper.instsize = addInst(helper.instsize, &insts_size, &cap, 0, 0); // add a "end of block" mark, just in case
|
||||
insts_ursize = insts_size*sizeof(instsize_t);
|
||||
}
|
||||
size_t insts_rsize = (insts_ursize+7)&~7; // round the size...
|
||||
size_t sz = sizeof(void*) + helper.arm_size + 4*sizeof(void*) + insts_rsize;
|
||||
// dynablock_t* block (arm insts) jmpnext code instsize
|
||||
void* actual_p = (void*)AllocDynarecMap(block, sz);
|
||||
void* p = actual_p + sizeof(void*);
|
||||
void* next = p + helper.arm_size;
|
||||
void* instsize = next + 4*sizeof(void*);
|
||||
if(actual_p==NULL) {
|
||||
dynarec_log(LOG_DEBUG, "AllocDynarecMap(%p, %d) failed, cancelling block\n", block, sz);
|
||||
CancelBlock();
|
||||
return NULL;
|
||||
}
|
||||
helper.block = p;
|
||||
helper.arm_start = (uintptr_t)p;
|
||||
if(helper.sons_size) {
|
||||
helper.sons_x86 = (uintptr_t*)alloca(helper.sons_size*sizeof(uintptr_t));
|
||||
helper.sons_arm = (void**)alloca(helper.sons_size*sizeof(void*));
|
||||
}
|
||||
*(dynablock_t**)actual_p = block;
|
||||
// pass 3, emit (log emit arm 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) {
|
||||
if(oldarmsize!=helper.arm_size) {
|
||||
printf_log(LOG_NONE, "BOX86: Warning, size difference in block between pass2 (%d) & pass3 (%d)!\n", sz, helper.arm_size);
|
||||
uint8_t *dump = (uint8_t*)helper.start;
|
||||
printf_log(LOG_NONE, "Dump of %d x86 opcodes:\n", helper.size);
|
||||
@@ -508,32 +517,32 @@ dynarec_log(LOG_DEBUG, "Asked to Fill block %p with %p\n", block, (void*)addr);
|
||||
}
|
||||
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; i<helper.size; ++i)
|
||||
cap += 1 + ((helper.insts[i].x86.size>helper.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; i<helper.size; ++i)
|
||||
block->instsize = 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
|
||||
}
|
||||
memcpy(instsize, helper.instsize, insts_ursize);
|
||||
block->instsize = instsize;
|
||||
// ok, free the helper now
|
||||
box_free(helper.insts);
|
||||
helper.insts = NULL;
|
||||
box_free(helper.next);
|
||||
helper.next = NULL;
|
||||
box_free(helper.instsize);
|
||||
helper.instsize = NULL;
|
||||
box_free(helper.predecessor);
|
||||
helper.predecessor = NULL;
|
||||
block->size = sz;
|
||||
block->isize = helper.size;
|
||||
block->actual_block = actual_p;
|
||||
block->block = p;
|
||||
block->jmpnext = next+sizeof(void*);
|
||||
*(dynablock_t**)next = block;
|
||||
CreateJmpNextTo(block->jmpnext, arm_next);
|
||||
block->need_test = 0;
|
||||
//block->x86_addr = (void*)start;
|
||||
block->x86_size = end-start;
|
||||
if(box86_dynarec_largest<block->x86_size)
|
||||
box86_dynarec_largest = block->x86_size;
|
||||
// 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) {
|
||||
@@ -541,34 +550,6 @@ dynarec_log(LOG_DEBUG, "Asked to Fill block %p with %p\n", block, (void*)addr);
|
||||
CancelBlock();
|
||||
return NULL;
|
||||
}
|
||||
// fill sons if any
|
||||
dynablock_t** sons = NULL;
|
||||
int sons_size = 0;
|
||||
if(helper.sons_size) {
|
||||
sons = (dynablock_t**)box_calloc(helper.sons_size, sizeof(dynablock_t*));
|
||||
for (int i=0; i<helper.sons_size; ++i) {
|
||||
int created = 1;
|
||||
dynablock_t *son = AddNewDynablock(block->parent, helper.sons_x86[i], &created);
|
||||
if(created) { // avoid breaking a working block!
|
||||
son->block = helper.sons_arm[i];
|
||||
son->x86_addr = (void*)helper.sons_x86[i];
|
||||
son->x86_size = end-helper.sons_x86[i];
|
||||
if(!son->x86_size) {printf_log(LOG_NONE, "Warning, son with null x86 size! (@%p / ARM=%p)", son->x86_addr, son->block);}
|
||||
son->father = block;
|
||||
son->done = 1;
|
||||
sons[sons_size++] = son;
|
||||
if(!son->parent)
|
||||
son->parent = block->parent;
|
||||
}
|
||||
}
|
||||
if(sons_size) {
|
||||
block->sons = sons;
|
||||
block->sons_size = sons_size;
|
||||
} else
|
||||
box_free(sons);
|
||||
}
|
||||
box_free(helper.predecessor);
|
||||
helper.predecessor = NULL;
|
||||
current_helper = NULL;
|
||||
block->done = 1;
|
||||
return (void*)block;
|
||||
|
||||
@@ -35,7 +35,6 @@ uintptr_t arm_pass(dynarec_arm_t* dyn, uintptr_t addr)
|
||||
uintptr_t init_addr = addr;
|
||||
MAYUSE(init_addr);
|
||||
int need_epilog = 1;
|
||||
dyn->sons_size = 0;
|
||||
// Clean up (because there are multiple passes)
|
||||
dyn->f.pending = 0;
|
||||
dyn->f.dfnone = 0;
|
||||
@@ -229,6 +228,6 @@ uintptr_t arm_pass(dynarec_arm_t* dyn, uintptr_t addr)
|
||||
jump_to_epilog(dyn, ip, 0, ninst); // no linker here, it's an unknow instruction
|
||||
}
|
||||
FINI;
|
||||
MESSAGE(LOG_DUMP, "---- END OF BLOCK ---- (%d, %d sons)\n", dyn->size, dyn->sons_size);
|
||||
MESSAGE(LOG_DUMP, "---- END OF BLOCK ---- (%d)\n", dyn->size);
|
||||
return addr;
|
||||
}
|
||||
@@ -6,8 +6,6 @@
|
||||
#define NEW_INST \
|
||||
if(ninst) { \
|
||||
dyn->insts[ninst].address = (dyn->insts[ninst-1].address+dyn->insts[ninst-1].size); \
|
||||
if(ninst && isInstClean(dyn, ninst)) \
|
||||
++dyn->sons_size; \
|
||||
}
|
||||
#define INST_EPILOG dyn->insts[ninst].epilog = dyn->arm_size;
|
||||
#define INST_NAME(name)
|
||||
@@ -8,12 +8,6 @@
|
||||
|
||||
#define MESSAGE(A, ...) if(box86_dynarec_dump) dynarec_log(LOG_NONE, __VA_ARGS__)
|
||||
#define NEW_INST \
|
||||
if(ninst && isInstClean(dyn, ninst)) { \
|
||||
dyn->sons_x86[dyn->sons_size] = (uintptr_t)ip; \
|
||||
dyn->sons_arm[dyn->sons_size] = dyn->block; \
|
||||
MESSAGE(LOG_DUMP, "----> potential Son here %p/%p\n", (void*)ip, dyn->block); \
|
||||
++dyn->sons_size; \
|
||||
}
|
||||
|
||||
#define INST_EPILOG
|
||||
#define INST_NAME(name) \
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -95,16 +96,15 @@ typedef struct dynarec_arm_s {
|
||||
uintptr_t* next; // variable array of "next" jump address
|
||||
int next_sz;
|
||||
int next_cap;
|
||||
uintptr_t* sons_x86; // the x86 address of potential dynablock sons
|
||||
void** sons_arm; // the arm address of potential dynablock sons
|
||||
int sons_size; // number of potential dynablock sons
|
||||
int* predecessor;// single array of all predecessor
|
||||
dynablock_t* dynablock;
|
||||
instsize_t* instsize;
|
||||
} dynarec_arm_t;
|
||||
|
||||
void add_next(dynarec_arm_t *dyn, uintptr_t addr);
|
||||
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 CreateJmpNextTo(void* addr, void* tonext);
|
||||
|
||||
#endif //__DYNAREC_ARM_PRIVATE_H_
|
||||
@@ -0,0 +1,8 @@
|
||||
#ifndef __DYNAREC_NEXT_H__
|
||||
#define __DYNAREC_NEXT_H__
|
||||
|
||||
void arm_next(void) EXPORTDYN;
|
||||
void arm_prolog(x86emu_t* emu, void* addr) EXPORTDYN;
|
||||
void arm_epilog() EXPORTDYN;
|
||||
|
||||
#endif //__DYNAREC_NEXT_H__
|
||||
@@ -1558,7 +1558,7 @@ void* ElfSetBrk(void* newbrk)
|
||||
}
|
||||
|
||||
#ifdef DYNAREC
|
||||
dynablocklist_t* GetDynablocksFromAddress(box86context_t *context, uintptr_t addr)
|
||||
dynablock_t* GetDynablocksFromAddress(box86context_t *context, uintptr_t addr)
|
||||
{
|
||||
// if we are here, the there is not block in standard "space"
|
||||
/*dynablocklist_t* ret = getDBFromAddress(addr);
|
||||
@@ -1567,7 +1567,7 @@ dynablocklist_t* GetDynablocksFromAddress(box86context_t *context, uintptr_t add
|
||||
}*/
|
||||
if(box86_dynarec_forced) {
|
||||
addDBFromAddressRange(addr, 1);
|
||||
return getDB(addr>>DYNAMAP_SHIFT);
|
||||
return getDB(addr);
|
||||
}
|
||||
//check if address is in an elf... if yes, grant a block (should I warn)
|
||||
Dl_info info;
|
||||
|
||||
@@ -1,10 +1,6 @@
|
||||
#ifndef __ELFLOADER_PRIVATE_H_
|
||||
#define __ELFLOADER_PRIVATE_H_
|
||||
|
||||
#ifdef DYNAREC
|
||||
typedef struct dynablocklist_s dynablocklist_t;
|
||||
#endif
|
||||
|
||||
typedef struct library_s library_t;
|
||||
typedef struct needed_libs_s needed_libs_t;
|
||||
typedef struct kh_mapsymbols_s kh_mapsymbols_t;
|
||||
|
||||
@@ -27,7 +27,6 @@ typedef struct atfork_fnc_s {
|
||||
} atfork_fnc_t;
|
||||
#ifdef DYNAREC
|
||||
typedef struct dynablock_s dynablock_t;
|
||||
typedef struct dynablocklist_s dynablocklist_t;
|
||||
typedef struct mmaplist_s mmaplist_t;
|
||||
typedef struct kh_dynablocks_s kh_dynablocks_t;
|
||||
#endif
|
||||
@@ -131,6 +130,7 @@ typedef struct box86context_s {
|
||||
pthread_mutex_t mutex_lock; // dynarec build will use their own mecanism
|
||||
#else
|
||||
pthread_mutex_t mutex_dyndump;
|
||||
uintptr_t max_db_size; // the biggest (in x86_64 instructions bytes) built dynablock
|
||||
int trace_dynarec;
|
||||
#endif
|
||||
pthread_mutex_t mutex_tls;
|
||||
|
||||
@@ -18,7 +18,6 @@ void customFree(void* p);
|
||||
|
||||
#ifdef DYNAREC
|
||||
typedef struct dynablock_s dynablock_t;
|
||||
typedef struct dynablocklist_s dynablocklist_t;
|
||||
// custom protection flag to mark Page that are Write protected for Dynarec purpose
|
||||
uintptr_t AllocDynarecMap(dynablock_t* db, int size);
|
||||
void FreeDynarecMap(dynablock_t* db, uintptr_t addr, uint32_t size);
|
||||
@@ -26,12 +25,15 @@ void FreeDynarecMap(dynablock_t* db, uintptr_t addr, uint32_t size);
|
||||
void addDBFromAddressRange(uintptr_t addr, uintptr_t size);
|
||||
void cleanDBFromAddressRange(uintptr_t addr, uintptr_t size, int destroy);
|
||||
|
||||
dynablocklist_t* getDB(uintptr_t idx);
|
||||
void addJumpTableIfDefault(void* addr, void* jmp);
|
||||
dynablock_t* getDB(uintptr_t addr);
|
||||
int addJumpTableIfDefault(void* addr, void* jmp); // return 1 if write was succesfull
|
||||
void setJumpTableIfRef(void* addr, void* jmp, void* ref); // return 1 if write was succesfull
|
||||
void setJumpTableDefault(void* addr);
|
||||
void setJumpTableDefaultRef(void* addr, void* jmp);
|
||||
int isJumpTableDefault(void* addr);
|
||||
uintptr_t getJumpTable();
|
||||
uintptr_t getJumpTableAddress(uintptr_t addr);
|
||||
uintptr_t getJumpAddress(uintptr_t addr);
|
||||
#endif
|
||||
|
||||
#define PROT_DYNAREC 0x80
|
||||
@@ -47,6 +49,9 @@ void loadProtectionFromMap();
|
||||
#ifdef DYNAREC
|
||||
void protectDB(uintptr_t addr, uintptr_t size);
|
||||
void unprotectDB(uintptr_t addr, uintptr_t size, int mark); // if mark==0, the blocks are not marked as potentially dirty
|
||||
int IsInHotPage(uintptr_t addr);
|
||||
int AreaInHotPage(uintptr_t start, uintptr_t end);
|
||||
void AddHotPage(uintptr_t addr);
|
||||
#endif
|
||||
void* find32bitBlock(size_t size);
|
||||
void* findBlockNearHint(void* hint, size_t size);
|
||||
|
||||
+3
-13
@@ -3,31 +3,21 @@
|
||||
|
||||
typedef struct x86emu_s x86emu_t;
|
||||
typedef struct dynablock_s dynablock_t;
|
||||
typedef struct dynablocklist_s dynablocklist_t;
|
||||
typedef struct kh_dynablocks_s kh_dynablocks_t;
|
||||
|
||||
uint32_t X31_hash_code(void* addr, int len);
|
||||
dynablocklist_t* NewDynablockList(uintptr_t text, int textsz, int direct);
|
||||
void FreeDynablockList(dynablocklist_t** dynablocks);
|
||||
void FreeDynablock(dynablock_t* db, int need_lock);
|
||||
void MarkDynablock(dynablock_t* db);
|
||||
void FreeRangeDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size);
|
||||
void MarkRangeDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size);
|
||||
void MarkRangeDynablock(dynablock_t* db, uintptr_t addr, uintptr_t size);
|
||||
int FreeRangeDynablock(dynablock_t* db, uintptr_t addr, uintptr_t size);
|
||||
|
||||
dynablock_t* FindDynablockFromNativeAddress(void* addr); // defined in box86context.h
|
||||
dynablock_t* FindDynablockDynablocklist(void* addr, kh_dynablocks_t* dynablocks);
|
||||
|
||||
uintptr_t StartDynablockList(dynablocklist_t* db);
|
||||
uintptr_t EndDynablockList(dynablocklist_t* db);
|
||||
void MarkDirectDynablock(dynablocklist_t* dynablocks, uintptr_t addr, uintptr_t size);
|
||||
|
||||
// Handling of Dynarec block (i.e. an exectable chunk of x86 translated code)
|
||||
dynablock_t* DBGetBlock(x86emu_t* emu, uintptr_t addr, int create, dynablock_t** current); // return NULL if block is not found / cannot be created. Don't create if create==0
|
||||
dynablock_t* DBGetBlock(x86emu_t* emu, uintptr_t addr, int create); // return NULL if block is not found / cannot be created. Don't create if create==0
|
||||
dynablock_t* DBAlternateBlock(x86emu_t* emu, uintptr_t addr, uintptr_t filladdr);
|
||||
|
||||
// Create and Add an new dynablock in the list, handling direct/map
|
||||
dynablock_t *AddNewDynablock(dynablocklist_t* dynablocks, uintptr_t addr, int* created);
|
||||
|
||||
// for use in signal handler
|
||||
void cancelFillBlock();
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ typedef struct box86context_s box86context_t;
|
||||
typedef struct x86emu_s x86emu_t;
|
||||
typedef struct needed_libs_s needed_libs_t;
|
||||
#ifdef DYNAREC
|
||||
typedef struct dynablocklist_s dynablocklist_t;
|
||||
typedef struct dynablock_s dynablock_t;
|
||||
#endif
|
||||
|
||||
elfheader_t* LoadAndCheckElfHeader(FILE* f, const char* name, int exec); // exec : 0 = lib, 1 = exec
|
||||
@@ -49,8 +49,7 @@ uint32_t GetTLSSize(elfheader_t* h);
|
||||
void* GetTLSPointer(box86context_t* context, elfheader_t* h);
|
||||
void* GetDTatOffset(box86context_t* context, int index, int offset);
|
||||
#ifdef DYNAREC
|
||||
dynablocklist_t* GetDynablocksFromAddress(box86context_t* context, uintptr_t addr);
|
||||
dynablocklist_t* GetDynablocksFromElf(elfheader_t* h);
|
||||
dynablock_t* GetDynablocksFromAddress(box86context_t *context, uintptr_t addr);
|
||||
#endif
|
||||
void ResetSpecialCaseMainElf(elfheader_t* h);
|
||||
void CreateMemorymapFile(box86context_t* context, int fd);
|
||||
|
||||
+13
-3
@@ -744,12 +744,22 @@ void my_box86signalhandler(int32_t sig, siginfo_t* info, void * ucntx)
|
||||
dynablock_t* db = NULL;
|
||||
int db_searched = 0;
|
||||
if ((sig==SIGSEGV) && (addr) && (info->si_code == SEGV_ACCERR) && (prot&PROT_CUSTOM)) {
|
||||
// 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;
|
||||
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;
|
||||
dynarec_log(LOG_DEBUG, "SIGSEGV with Access error on %p for %p , db=%p(%p), prot=0x%x (old page=%p)\n", pc, addr, db, db?((void*)db->x86_addr):NULL, prot, (void*)repeated_page);
|
||||
static int repeated_count = 0;
|
||||
if(repeated_page == ((uintptr_t)addr&~0xfff)) {
|
||||
++repeated_count; // Access eoor multiple time on same page, disable dynarec on this page a few time...
|
||||
dynarec_log(LOG_DEBUG, "Detecting a Hotpage at %p (%d)\n", (void*)repeated_page, repeated_count);
|
||||
AddHotPage(repeated_page);
|
||||
} else {
|
||||
repeated_page = (uintptr_t)addr&~0xfff;
|
||||
repeated_count = 0;
|
||||
}
|
||||
// access error, unprotect the block (and mark them dirty)
|
||||
unprotectDB((uintptr_t)addr, 1, 1); // unprotect 1 byte... But then, the whole page will be unprotected
|
||||
if(db && ((addr>=db->x86_addr && addr<(db->x86_addr+db->x86_size)) || db->need_test)) {
|
||||
// dynablock got auto-dirty! need to get out of it!!!
|
||||
emu_jmpbuf_t* ejb = GetJmpBuf();
|
||||
|
||||
@@ -322,8 +322,7 @@ EXPORT int my_pthread_create(x86emu_t *emu, void* t, void* attr, void* start_rou
|
||||
#ifdef DYNAREC
|
||||
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
|
||||
@@ -346,8 +345,7 @@ void* my_prepare_thread(x86emu_t *emu, void* f, void* arg, int ssize, void** pet
|
||||
#ifdef DYNAREC
|
||||
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;
|
||||
|
||||
Reference in new issue
Block a user