21 |
#include "disas.h" |
#include "disas.h" |
22 |
|
|
23 |
//#define DEBUG_EXEC |
//#define DEBUG_EXEC |
|
#define DEBUG_FLUSH |
|
24 |
//#define DEBUG_SIGNAL |
//#define DEBUG_SIGNAL |
25 |
|
|
26 |
/* main execution loop */ |
/* main execution loop */ |
27 |
|
|
|
/* maximum total translate dcode allocated */ |
|
|
#define CODE_GEN_BUFFER_SIZE (2048 * 1024) |
|
|
//#define CODE_GEN_BUFFER_SIZE (128 * 1024) |
|
|
#define CODE_GEN_MAX_SIZE 65536 |
|
|
#define CODE_GEN_ALIGN 16 /* must be >= of the size of a icache line */ |
|
|
|
|
|
/* threshold to flush the translated code buffer */ |
|
|
#define CODE_GEN_BUFFER_MAX_SIZE (CODE_GEN_BUFFER_SIZE - CODE_GEN_MAX_SIZE) |
|
|
|
|
|
#define CODE_GEN_MAX_BLOCKS (CODE_GEN_BUFFER_SIZE / 64) |
|
|
#define CODE_GEN_HASH_BITS 15 |
|
|
#define CODE_GEN_HASH_SIZE (1 << CODE_GEN_HASH_BITS) |
|
|
|
|
|
typedef struct TranslationBlock { |
|
|
unsigned long pc; /* simulated PC corresponding to this block (EIP + CS base) */ |
|
|
unsigned long cs_base; /* CS base for this block */ |
|
|
unsigned int flags; /* flags defining in which context the code was generated */ |
|
|
uint8_t *tc_ptr; /* pointer to the translated code */ |
|
|
struct TranslationBlock *hash_next; /* next matching block */ |
|
|
} TranslationBlock; |
|
|
|
|
|
TranslationBlock tbs[CODE_GEN_MAX_BLOCKS]; |
|
|
TranslationBlock *tb_hash[CODE_GEN_HASH_SIZE]; |
|
|
int nb_tbs; |
|
|
|
|
|
uint8_t code_gen_buffer[CODE_GEN_BUFFER_SIZE]; |
|
|
uint8_t *code_gen_ptr; |
|
|
|
|
28 |
/* thread support */ |
/* thread support */ |
29 |
|
|
30 |
#ifdef __powerpc__ |
#ifdef __powerpc__ |
166 |
raise_exception_err(exception_index, 0); |
raise_exception_err(exception_index, 0); |
167 |
} |
} |
168 |
|
|
|
void cpu_x86_tblocks_init(void) |
|
|
{ |
|
|
if (!code_gen_ptr) { |
|
|
code_gen_ptr = code_gen_buffer; |
|
|
} |
|
|
} |
|
|
|
|
|
/* flush all the translation blocks */ |
|
|
static void tb_flush(void) |
|
|
{ |
|
|
int i; |
|
|
#ifdef DEBUG_FLUSH |
|
|
printf("gemu: flush code_size=%d nb_tbs=%d avg_tb_size=%d\n", |
|
|
code_gen_ptr - code_gen_buffer, |
|
|
nb_tbs, |
|
|
(code_gen_ptr - code_gen_buffer) / nb_tbs); |
|
|
#endif |
|
|
nb_tbs = 0; |
|
|
for(i = 0;i < CODE_GEN_HASH_SIZE; i++) |
|
|
tb_hash[i] = NULL; |
|
|
code_gen_ptr = code_gen_buffer; |
|
|
/* XXX: flush processor icache at this point */ |
|
|
} |
|
|
|
|
|
/* find a translation block in the translation cache. If not found, |
|
|
return NULL and the pointer to the last element of the list in pptb */ |
|
|
static inline TranslationBlock *tb_find(TranslationBlock ***pptb, |
|
|
unsigned long pc, |
|
|
unsigned long cs_base, |
|
|
unsigned int flags) |
|
|
{ |
|
|
TranslationBlock **ptb, *tb; |
|
|
unsigned int h; |
|
|
|
|
|
h = pc & (CODE_GEN_HASH_SIZE - 1); |
|
|
ptb = &tb_hash[h]; |
|
|
#if 0 |
|
|
/* XXX: hack to handle 16 bit modyfing code */ |
|
|
if (flags & (1 << GEN_FLAG_CODE32_SHIFT)) |
|
|
#endif |
|
|
for(;;) { |
|
|
tb = *ptb; |
|
|
if (!tb) |
|
|
break; |
|
|
if (tb->pc == pc && tb->cs_base == cs_base && tb->flags == flags) |
|
|
return tb; |
|
|
ptb = &tb->hash_next; |
|
|
} |
|
|
*pptb = ptb; |
|
|
return NULL; |
|
|
} |
|
|
|
|
|
/* allocate a new translation block. flush the translation buffer if |
|
|
too many translation blocks or too much generated code */ |
|
|
static inline TranslationBlock *tb_alloc(void) |
|
|
{ |
|
|
TranslationBlock *tb; |
|
|
if (nb_tbs >= CODE_GEN_MAX_BLOCKS || |
|
|
(code_gen_ptr - code_gen_buffer) >= CODE_GEN_BUFFER_MAX_SIZE) |
|
|
tb_flush(); |
|
|
tb = &tbs[nb_tbs++]; |
|
|
return tb; |
|
|
} |
|
|
|
|
169 |
int cpu_x86_exec(CPUX86State *env1) |
int cpu_x86_exec(CPUX86State *env1) |
170 |
{ |
{ |
171 |
int saved_T0, saved_T1, saved_A0; |
int saved_T0, saved_T1, saved_A0; |
194 |
#ifdef reg_EDI |
#ifdef reg_EDI |
195 |
int saved_EDI; |
int saved_EDI; |
196 |
#endif |
#endif |
197 |
int code_gen_size, ret; |
int code_gen_size, ret, code_size; |
198 |
void (*gen_func)(void); |
void (*gen_func)(void); |
199 |
TranslationBlock *tb, **ptb; |
TranslationBlock *tb, **ptb; |
200 |
uint8_t *tc_ptr, *cs_base, *pc; |
uint8_t *tc_ptr, *cs_base, *pc; |
297 |
cpu_lock(); |
cpu_lock(); |
298 |
tc_ptr = code_gen_ptr; |
tc_ptr = code_gen_ptr; |
299 |
ret = cpu_x86_gen_code(code_gen_ptr, CODE_GEN_MAX_SIZE, |
ret = cpu_x86_gen_code(code_gen_ptr, CODE_GEN_MAX_SIZE, |
300 |
&code_gen_size, pc, cs_base, flags); |
&code_gen_size, pc, cs_base, flags, |
301 |
|
&code_size); |
302 |
/* if invalid instruction, signal it */ |
/* if invalid instruction, signal it */ |
303 |
if (ret != 0) { |
if (ret != 0) { |
304 |
cpu_unlock(); |
cpu_unlock(); |
305 |
raise_exception(EXCP06_ILLOP); |
raise_exception(EXCP06_ILLOP); |
306 |
} |
} |
307 |
tb = tb_alloc(); |
tb = tb_alloc((unsigned long)pc, code_size); |
308 |
*ptb = tb; |
*ptb = tb; |
|
tb->pc = (unsigned long)pc; |
|
309 |
tb->cs_base = (unsigned long)cs_base; |
tb->cs_base = (unsigned long)cs_base; |
310 |
tb->flags = flags; |
tb->flags = flags; |
311 |
tb->tc_ptr = tc_ptr; |
tb->tc_ptr = tc_ptr; |
400 |
#include <sys/ucontext.h> |
#include <sys/ucontext.h> |
401 |
|
|
402 |
/* 'pc' is the host PC at which the exception was raised. 'address' is |
/* 'pc' is the host PC at which the exception was raised. 'address' is |
403 |
the effective address of the memory exception */ |
the effective address of the memory exception. 'is_write' is 1 if a |
404 |
|
write caused the exception and otherwise 0'. 'old_set' is the |
405 |
|
signal set which should be restored */ |
406 |
static inline int handle_cpu_signal(unsigned long pc, |
static inline int handle_cpu_signal(unsigned long pc, |
407 |
unsigned long address, |
unsigned long address, |
408 |
|
int is_write, |
409 |
sigset_t *old_set) |
sigset_t *old_set) |
410 |
{ |
{ |
411 |
#ifdef DEBUG_SIGNAL |
#if defined(DEBUG_SIGNAL) |
412 |
printf("gemu: SIGSEGV pc=0x%08lx oldset=0x%08lx\n", |
printf("qemu: SIGSEGV pc=0x%08lx address=%08lx wr=%d oldset=0x%08lx\n", |
413 |
pc, *(unsigned long *)old_set); |
pc, address, is_write, *(unsigned long *)old_set); |
414 |
#endif |
#endif |
415 |
|
if (is_write && page_unprotect(address)) { |
416 |
|
sigprocmask(SIG_SETMASK, old_set, NULL); |
417 |
|
return 1; |
418 |
|
} |
419 |
if (pc >= (unsigned long)code_gen_buffer && |
if (pc >= (unsigned long)code_gen_buffer && |
420 |
pc < (unsigned long)code_gen_buffer + CODE_GEN_BUFFER_SIZE) { |
pc < (unsigned long)code_gen_buffer + CODE_GEN_BUFFER_SIZE) { |
421 |
/* the PC is inside the translated code. It means that we have |
/* the PC is inside the translated code. It means that we have |
426 |
/* XXX: need to compute virtual pc position by retranslating |
/* XXX: need to compute virtual pc position by retranslating |
427 |
code. The rest of the CPU state should be correct. */ |
code. The rest of the CPU state should be correct. */ |
428 |
env->cr2 = address; |
env->cr2 = address; |
429 |
/* XXX: more precise exception code */ |
raise_exception_err(EXCP0E_PAGE, 4 | (is_write << 1)); |
|
raise_exception_err(EXCP0E_PAGE, 4); |
|
430 |
/* never comes here */ |
/* never comes here */ |
431 |
return 1; |
return 1; |
432 |
} else { |
} else { |
444 |
|
|
445 |
#ifndef REG_EIP |
#ifndef REG_EIP |
446 |
/* for glibc 2.1 */ |
/* for glibc 2.1 */ |
447 |
#define REG_EIP EIP |
#define REG_EIP EIP |
448 |
|
#define REG_ERR ERR |
449 |
|
#define REG_TRAPNO TRAPNO |
450 |
#endif |
#endif |
451 |
pc = uc->uc_mcontext.gregs[REG_EIP]; |
pc = uc->uc_mcontext.gregs[REG_EIP]; |
452 |
pold_set = &uc->uc_sigmask; |
pold_set = &uc->uc_sigmask; |
453 |
return handle_cpu_signal(pc, (unsigned long)info->si_addr, pold_set); |
return handle_cpu_signal(pc, (unsigned long)info->si_addr, |
454 |
|
uc->uc_mcontext.gregs[REG_TRAPNO] == 0xe ? |
455 |
|
(uc->uc_mcontext.gregs[REG_ERR] >> 1) & 1 : 0, |
456 |
|
pold_set); |
457 |
#else |
#else |
458 |
#warning No CPU specific signal handler: cannot handle target SIGSEGV events |
#warning No CPU specific signal handler: cannot handle target SIGSEGV events |
459 |
return 0; |
return 0; |