precise exceptions
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@194 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
parent
f4beb510a4
commit
a513fe19ac
4
dyngen.c
4
dyngen.c
@ -451,7 +451,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size,
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (gen_switch == 2) {
|
if (gen_switch == 2) {
|
||||||
fprintf(outfile, "DEF(%s, %d)\n", name + 3, nb_args);
|
fprintf(outfile, "DEF(%s, %d, %d)\n", name + 3, nb_args, copy_size);
|
||||||
} else if (gen_switch == 1) {
|
} else if (gen_switch == 1) {
|
||||||
|
|
||||||
/* output C code */
|
/* output C code */
|
||||||
@ -991,7 +991,7 @@ int load_elf(const char *filename, FILE *outfile, int do_print_enum)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (do_print_enum) {
|
if (do_print_enum) {
|
||||||
fprintf(outfile, "DEF(end, 0)\n");
|
fprintf(outfile, "DEF(end, 0, 0)\n");
|
||||||
for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
|
for(i = 0, sym = symtab; i < nb_syms; i++, sym++) {
|
||||||
const char *name, *p;
|
const char *name, *p;
|
||||||
name = strtab + sym->st_name;
|
name = strtab + sym->st_name;
|
||||||
|
60
exec-i386.c
60
exec-i386.c
@ -39,9 +39,7 @@ void cpu_unlock(void)
|
|||||||
spin_unlock(&global_cpu_lock);
|
spin_unlock(&global_cpu_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* exception support */
|
void cpu_loop_exit(void)
|
||||||
/* NOTE: not static to force relocation generation by GCC */
|
|
||||||
void raise_exception_err(int exception_index, int error_code)
|
|
||||||
{
|
{
|
||||||
/* NOTE: the register at this point must be saved by hand because
|
/* NOTE: the register at this point must be saved by hand because
|
||||||
longjmp restore them */
|
longjmp restore them */
|
||||||
@ -76,17 +74,9 @@ void raise_exception_err(int exception_index, int error_code)
|
|||||||
#ifdef reg_EDI
|
#ifdef reg_EDI
|
||||||
env->regs[R_EDI] = EDI;
|
env->regs[R_EDI] = EDI;
|
||||||
#endif
|
#endif
|
||||||
env->exception_index = exception_index;
|
|
||||||
env->error_code = error_code;
|
|
||||||
longjmp(env->jmp_env, 1);
|
longjmp(env->jmp_env, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* short cut if error_code is 0 or not present */
|
|
||||||
void raise_exception(int exception_index)
|
|
||||||
{
|
|
||||||
raise_exception_err(exception_index, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
int cpu_x86_exec(CPUX86State *env1)
|
int cpu_x86_exec(CPUX86State *env1)
|
||||||
{
|
{
|
||||||
int saved_T0, saved_T1, saved_A0;
|
int saved_T0, saved_T1, saved_A0;
|
||||||
@ -115,7 +105,7 @@ int cpu_x86_exec(CPUX86State *env1)
|
|||||||
#ifdef reg_EDI
|
#ifdef reg_EDI
|
||||||
int saved_EDI;
|
int saved_EDI;
|
||||||
#endif
|
#endif
|
||||||
int code_gen_size, ret, code_size;
|
int code_gen_size, ret;
|
||||||
void (*gen_func)(void);
|
void (*gen_func)(void);
|
||||||
TranslationBlock *tb, **ptb;
|
TranslationBlock *tb, **ptb;
|
||||||
uint8_t *tc_ptr, *cs_base, *pc;
|
uint8_t *tc_ptr, *cs_base, *pc;
|
||||||
@ -172,7 +162,8 @@ int cpu_x86_exec(CPUX86State *env1)
|
|||||||
T0 = 0; /* force lookup of first TB */
|
T0 = 0; /* force lookup of first TB */
|
||||||
for(;;) {
|
for(;;) {
|
||||||
if (env->interrupt_request) {
|
if (env->interrupt_request) {
|
||||||
raise_exception(EXCP_INTERRUPT);
|
env->exception_index = EXCP_INTERRUPT;
|
||||||
|
cpu_loop_exit();
|
||||||
}
|
}
|
||||||
#ifdef DEBUG_EXEC
|
#ifdef DEBUG_EXEC
|
||||||
if (loglevel) {
|
if (loglevel) {
|
||||||
@ -226,9 +217,9 @@ int cpu_x86_exec(CPUX86State *env1)
|
|||||||
}
|
}
|
||||||
tc_ptr = code_gen_ptr;
|
tc_ptr = code_gen_ptr;
|
||||||
tb->tc_ptr = tc_ptr;
|
tb->tc_ptr = tc_ptr;
|
||||||
ret = cpu_x86_gen_code(code_gen_ptr, CODE_GEN_MAX_SIZE,
|
tb->cs_base = (unsigned long)cs_base;
|
||||||
&code_gen_size, pc, cs_base, flags,
|
tb->flags = flags;
|
||||||
&code_size, tb);
|
ret = cpu_x86_gen_code(tb, CODE_GEN_MAX_SIZE, &code_gen_size);
|
||||||
/* if invalid instruction, signal it */
|
/* if invalid instruction, signal it */
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
/* NOTE: the tb is allocated but not linked, so we
|
/* NOTE: the tb is allocated but not linked, so we
|
||||||
@ -237,9 +228,6 @@ int cpu_x86_exec(CPUX86State *env1)
|
|||||||
raise_exception(EXCP06_ILLOP);
|
raise_exception(EXCP06_ILLOP);
|
||||||
}
|
}
|
||||||
*ptb = tb;
|
*ptb = tb;
|
||||||
tb->size = code_size;
|
|
||||||
tb->cs_base = (unsigned long)cs_base;
|
|
||||||
tb->flags = flags;
|
|
||||||
tb->hash_next = NULL;
|
tb->hash_next = NULL;
|
||||||
tb_link(tb);
|
tb_link(tb);
|
||||||
code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
|
code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1));
|
||||||
@ -323,7 +311,19 @@ void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
|
|||||||
|
|
||||||
saved_env = env;
|
saved_env = env;
|
||||||
env = s;
|
env = s;
|
||||||
load_seg(seg_reg, selector);
|
if (env->eflags & VM_MASK) {
|
||||||
|
SegmentCache *sc;
|
||||||
|
selector &= 0xffff;
|
||||||
|
sc = &env->seg_cache[seg_reg];
|
||||||
|
/* NOTE: in VM86 mode, limit and seg_32bit are never reloaded,
|
||||||
|
so we must load them here */
|
||||||
|
sc->base = (void *)(selector << 4);
|
||||||
|
sc->limit = 0xffff;
|
||||||
|
sc->seg_32bit = 0;
|
||||||
|
env->segs[seg_reg] = selector;
|
||||||
|
} else {
|
||||||
|
load_seg(seg_reg, selector, 0);
|
||||||
|
}
|
||||||
env = saved_env;
|
env = saved_env;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -346,6 +346,10 @@ void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
|
|||||||
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
|
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
|
||||||
int is_write, sigset_t *old_set)
|
int is_write, sigset_t *old_set)
|
||||||
{
|
{
|
||||||
|
TranslationBlock *tb;
|
||||||
|
int ret;
|
||||||
|
uint32_t found_pc;
|
||||||
|
|
||||||
#if defined(DEBUG_SIGNAL)
|
#if defined(DEBUG_SIGNAL)
|
||||||
printf("qemu: SIGSEGV pc=0x%08lx address=%08lx wr=%d oldset=0x%08lx\n",
|
printf("qemu: SIGSEGV pc=0x%08lx address=%08lx wr=%d oldset=0x%08lx\n",
|
||||||
pc, address, is_write, *(unsigned long *)old_set);
|
pc, address, is_write, *(unsigned long *)old_set);
|
||||||
@ -354,16 +358,18 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
|
|||||||
if (is_write && page_unprotect(address)) {
|
if (is_write && page_unprotect(address)) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
if (pc >= (unsigned long)code_gen_buffer &&
|
tb = tb_find_pc(pc);
|
||||||
pc < (unsigned long)code_gen_buffer + CODE_GEN_BUFFER_SIZE) {
|
if (tb) {
|
||||||
/* the PC is inside the translated code. It means that we have
|
/* the PC is inside the translated code. It means that we have
|
||||||
a virtual CPU fault */
|
a virtual CPU fault */
|
||||||
/* we restore the process signal mask as the sigreturn should
|
ret = cpu_x86_search_pc(tb, &found_pc, pc);
|
||||||
do it */
|
if (ret < 0)
|
||||||
sigprocmask(SIG_SETMASK, old_set, NULL);
|
return 0;
|
||||||
/* XXX: need to compute virtual pc position by retranslating
|
env->eip = found_pc - tb->cs_base;
|
||||||
code. The rest of the CPU state should be correct. */
|
|
||||||
env->cr2 = address;
|
env->cr2 = address;
|
||||||
|
/* we restore the process signal mask as the sigreturn should
|
||||||
|
do it (XXX: use sigsetjmp) */
|
||||||
|
sigprocmask(SIG_SETMASK, old_set, NULL);
|
||||||
raise_exception_err(EXCP0E_PAGE, 4 | (is_write << 1));
|
raise_exception_err(EXCP0E_PAGE, 4 | (is_write << 1));
|
||||||
/* never comes here */
|
/* never comes here */
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -217,11 +217,14 @@ typedef struct CCTable {
|
|||||||
|
|
||||||
extern CCTable cc_table[];
|
extern CCTable cc_table[];
|
||||||
|
|
||||||
void load_seg(int seg_reg, int selector);
|
void load_seg(int seg_reg, int selector, unsigned cur_eip);
|
||||||
void cpu_lock(void);
|
void cpu_lock(void);
|
||||||
void cpu_unlock(void);
|
void cpu_unlock(void);
|
||||||
|
void raise_interrupt(int intno, int is_int, int error_code,
|
||||||
|
unsigned int next_eip);
|
||||||
void raise_exception_err(int exception_index, int error_code);
|
void raise_exception_err(int exception_index, int error_code);
|
||||||
void raise_exception(int exception_index);
|
void raise_exception(int exception_index);
|
||||||
|
void cpu_loop_exit(void);
|
||||||
|
|
||||||
void OPPROTO op_movl_eflags_T0(void);
|
void OPPROTO op_movl_eflags_T0(void);
|
||||||
void OPPROTO op_movl_T0_eflags(void);
|
void OPPROTO op_movl_T0_eflags(void);
|
||||||
|
31
exec.c
31
exec.c
@ -531,3 +531,34 @@ void page_unprotect_range(uint8_t *data, unsigned long data_size)
|
|||||||
page_unprotect(addr);
|
page_unprotect(addr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* find the TB 'tb' such that tb[0].tc_ptr <= tc_ptr <
|
||||||
|
tb[1].tc_ptr. Return NULL if not found */
|
||||||
|
TranslationBlock *tb_find_pc(unsigned long tc_ptr)
|
||||||
|
{
|
||||||
|
int m_min, m_max, m;
|
||||||
|
unsigned long v;
|
||||||
|
TranslationBlock *tb;
|
||||||
|
|
||||||
|
if (nb_tbs <= 0)
|
||||||
|
return NULL;
|
||||||
|
if (tc_ptr < (unsigned long)code_gen_buffer ||
|
||||||
|
tc_ptr >= (unsigned long)code_gen_ptr)
|
||||||
|
return NULL;
|
||||||
|
/* binary search (cf Knuth) */
|
||||||
|
m_min = 0;
|
||||||
|
m_max = nb_tbs - 1;
|
||||||
|
while (m_min <= m_max) {
|
||||||
|
m = (m_min + m_max) >> 1;
|
||||||
|
tb = &tbs[m];
|
||||||
|
v = (unsigned long)tb->tc_ptr;
|
||||||
|
if (v == tc_ptr)
|
||||||
|
return tb;
|
||||||
|
else if (tc_ptr < v) {
|
||||||
|
m_max = m - 1;
|
||||||
|
} else {
|
||||||
|
m_min = m + 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return &tbs[m_max];
|
||||||
|
}
|
||||||
|
10
exec.h
10
exec.h
@ -28,10 +28,10 @@
|
|||||||
#define GEN_FLAG_IOPL_SHIFT 12 /* same position as eflags */
|
#define GEN_FLAG_IOPL_SHIFT 12 /* same position as eflags */
|
||||||
|
|
||||||
struct TranslationBlock;
|
struct TranslationBlock;
|
||||||
int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size,
|
int cpu_x86_gen_code(struct TranslationBlock *tb,
|
||||||
int *gen_code_size_ptr,
|
int max_code_size, int *gen_code_size_ptr);
|
||||||
uint8_t *pc_start, uint8_t *cs_base, int flags,
|
int cpu_x86_search_pc(struct TranslationBlock *tb,
|
||||||
int *code_size_ptr, struct TranslationBlock *tb);
|
uint32_t *found_pc, unsigned long searched_pc);
|
||||||
void cpu_x86_tblocks_init(void);
|
void cpu_x86_tblocks_init(void);
|
||||||
void page_init(void);
|
void page_init(void);
|
||||||
int page_unprotect(unsigned long address);
|
int page_unprotect(unsigned long address);
|
||||||
@ -161,6 +161,8 @@ static inline void tb_add_jump(TranslationBlock *tb, int n,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TranslationBlock *tb_find_pc(unsigned long pc_ptr);
|
||||||
|
|
||||||
#ifndef offsetof
|
#ifndef offsetof
|
||||||
#define offsetof(type, field) ((size_t) &((type *)0)->field)
|
#define offsetof(type, field) ((size_t) &((type *)0)->field)
|
||||||
#endif
|
#endif
|
||||||
|
Loading…
Reference in New Issue
Block a user