Commit a513fe19ac4896a09c6c338204d76c39e652451f
1 parent
f4beb510
precise exceptions
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@194 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
5 changed files
with
75 additions
and
33 deletions
dyngen.c
| @@ -451,7 +451,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, | @@ -451,7 +451,7 @@ void gen_code(const char *name, host_ulong offset, host_ulong size, | ||
| 451 | } | 451 | } |
| 452 | 452 | ||
| 453 | if (gen_switch == 2) { | 453 | if (gen_switch == 2) { |
| 454 | - fprintf(outfile, "DEF(%s, %d)\n", name + 3, nb_args); | 454 | + fprintf(outfile, "DEF(%s, %d, %d)\n", name + 3, nb_args, copy_size); |
| 455 | } else if (gen_switch == 1) { | 455 | } else if (gen_switch == 1) { |
| 456 | 456 | ||
| 457 | /* output C code */ | 457 | /* output C code */ |
| @@ -991,7 +991,7 @@ int load_elf(const char *filename, FILE *outfile, int do_print_enum) | @@ -991,7 +991,7 @@ int load_elf(const char *filename, FILE *outfile, int do_print_enum) | ||
| 991 | } | 991 | } |
| 992 | 992 | ||
| 993 | if (do_print_enum) { | 993 | if (do_print_enum) { |
| 994 | - fprintf(outfile, "DEF(end, 0)\n"); | 994 | + fprintf(outfile, "DEF(end, 0, 0)\n"); |
| 995 | for(i = 0, sym = symtab; i < nb_syms; i++, sym++) { | 995 | for(i = 0, sym = symtab; i < nb_syms; i++, sym++) { |
| 996 | const char *name, *p; | 996 | const char *name, *p; |
| 997 | name = strtab + sym->st_name; | 997 | name = strtab + sym->st_name; |
exec-i386.c
| @@ -39,9 +39,7 @@ void cpu_unlock(void) | @@ -39,9 +39,7 @@ void cpu_unlock(void) | ||
| 39 | spin_unlock(&global_cpu_lock); | 39 | spin_unlock(&global_cpu_lock); |
| 40 | } | 40 | } |
| 41 | 41 | ||
| 42 | -/* exception support */ | ||
| 43 | -/* NOTE: not static to force relocation generation by GCC */ | ||
| 44 | -void raise_exception_err(int exception_index, int error_code) | 42 | +void cpu_loop_exit(void) |
| 45 | { | 43 | { |
| 46 | /* NOTE: the register at this point must be saved by hand because | 44 | /* NOTE: the register at this point must be saved by hand because |
| 47 | longjmp restore them */ | 45 | longjmp restore them */ |
| @@ -76,17 +74,9 @@ void raise_exception_err(int exception_index, int error_code) | @@ -76,17 +74,9 @@ void raise_exception_err(int exception_index, int error_code) | ||
| 76 | #ifdef reg_EDI | 74 | #ifdef reg_EDI |
| 77 | env->regs[R_EDI] = EDI; | 75 | env->regs[R_EDI] = EDI; |
| 78 | #endif | 76 | #endif |
| 79 | - env->exception_index = exception_index; | ||
| 80 | - env->error_code = error_code; | ||
| 81 | longjmp(env->jmp_env, 1); | 77 | longjmp(env->jmp_env, 1); |
| 82 | } | 78 | } |
| 83 | 79 | ||
| 84 | -/* short cut if error_code is 0 or not present */ | ||
| 85 | -void raise_exception(int exception_index) | ||
| 86 | -{ | ||
| 87 | - raise_exception_err(exception_index, 0); | ||
| 88 | -} | ||
| 89 | - | ||
| 90 | int cpu_x86_exec(CPUX86State *env1) | 80 | int cpu_x86_exec(CPUX86State *env1) |
| 91 | { | 81 | { |
| 92 | int saved_T0, saved_T1, saved_A0; | 82 | int saved_T0, saved_T1, saved_A0; |
| @@ -115,7 +105,7 @@ int cpu_x86_exec(CPUX86State *env1) | @@ -115,7 +105,7 @@ int cpu_x86_exec(CPUX86State *env1) | ||
| 115 | #ifdef reg_EDI | 105 | #ifdef reg_EDI |
| 116 | int saved_EDI; | 106 | int saved_EDI; |
| 117 | #endif | 107 | #endif |
| 118 | - int code_gen_size, ret, code_size; | 108 | + int code_gen_size, ret; |
| 119 | void (*gen_func)(void); | 109 | void (*gen_func)(void); |
| 120 | TranslationBlock *tb, **ptb; | 110 | TranslationBlock *tb, **ptb; |
| 121 | uint8_t *tc_ptr, *cs_base, *pc; | 111 | uint8_t *tc_ptr, *cs_base, *pc; |
| @@ -172,7 +162,8 @@ int cpu_x86_exec(CPUX86State *env1) | @@ -172,7 +162,8 @@ int cpu_x86_exec(CPUX86State *env1) | ||
| 172 | T0 = 0; /* force lookup of first TB */ | 162 | T0 = 0; /* force lookup of first TB */ |
| 173 | for(;;) { | 163 | for(;;) { |
| 174 | if (env->interrupt_request) { | 164 | if (env->interrupt_request) { |
| 175 | - raise_exception(EXCP_INTERRUPT); | 165 | + env->exception_index = EXCP_INTERRUPT; |
| 166 | + cpu_loop_exit(); | ||
| 176 | } | 167 | } |
| 177 | #ifdef DEBUG_EXEC | 168 | #ifdef DEBUG_EXEC |
| 178 | if (loglevel) { | 169 | if (loglevel) { |
| @@ -226,9 +217,9 @@ int cpu_x86_exec(CPUX86State *env1) | @@ -226,9 +217,9 @@ int cpu_x86_exec(CPUX86State *env1) | ||
| 226 | } | 217 | } |
| 227 | tc_ptr = code_gen_ptr; | 218 | tc_ptr = code_gen_ptr; |
| 228 | tb->tc_ptr = tc_ptr; | 219 | tb->tc_ptr = tc_ptr; |
| 229 | - ret = cpu_x86_gen_code(code_gen_ptr, CODE_GEN_MAX_SIZE, | ||
| 230 | - &code_gen_size, pc, cs_base, flags, | ||
| 231 | - &code_size, tb); | 220 | + tb->cs_base = (unsigned long)cs_base; |
| 221 | + tb->flags = flags; | ||
| 222 | + ret = cpu_x86_gen_code(tb, CODE_GEN_MAX_SIZE, &code_gen_size); | ||
| 232 | /* if invalid instruction, signal it */ | 223 | /* if invalid instruction, signal it */ |
| 233 | if (ret != 0) { | 224 | if (ret != 0) { |
| 234 | /* NOTE: the tb is allocated but not linked, so we | 225 | /* NOTE: the tb is allocated but not linked, so we |
| @@ -237,9 +228,6 @@ int cpu_x86_exec(CPUX86State *env1) | @@ -237,9 +228,6 @@ int cpu_x86_exec(CPUX86State *env1) | ||
| 237 | raise_exception(EXCP06_ILLOP); | 228 | raise_exception(EXCP06_ILLOP); |
| 238 | } | 229 | } |
| 239 | *ptb = tb; | 230 | *ptb = tb; |
| 240 | - tb->size = code_size; | ||
| 241 | - tb->cs_base = (unsigned long)cs_base; | ||
| 242 | - tb->flags = flags; | ||
| 243 | tb->hash_next = NULL; | 231 | tb->hash_next = NULL; |
| 244 | tb_link(tb); | 232 | tb_link(tb); |
| 245 | code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1)); | 233 | 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) | @@ -323,7 +311,19 @@ void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector) | ||
| 323 | 311 | ||
| 324 | saved_env = env; | 312 | saved_env = env; |
| 325 | env = s; | 313 | env = s; |
| 326 | - load_seg(seg_reg, selector); | 314 | + if (env->eflags & VM_MASK) { |
| 315 | + SegmentCache *sc; | ||
| 316 | + selector &= 0xffff; | ||
| 317 | + sc = &env->seg_cache[seg_reg]; | ||
| 318 | + /* NOTE: in VM86 mode, limit and seg_32bit are never reloaded, | ||
| 319 | + so we must load them here */ | ||
| 320 | + sc->base = (void *)(selector << 4); | ||
| 321 | + sc->limit = 0xffff; | ||
| 322 | + sc->seg_32bit = 0; | ||
| 323 | + env->segs[seg_reg] = selector; | ||
| 324 | + } else { | ||
| 325 | + load_seg(seg_reg, selector, 0); | ||
| 326 | + } | ||
| 327 | env = saved_env; | 327 | env = saved_env; |
| 328 | } | 328 | } |
| 329 | 329 | ||
| @@ -346,6 +346,10 @@ void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector) | @@ -346,6 +346,10 @@ void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector) | ||
| 346 | static inline int handle_cpu_signal(unsigned long pc, unsigned long address, | 346 | static inline int handle_cpu_signal(unsigned long pc, unsigned long address, |
| 347 | int is_write, sigset_t *old_set) | 347 | int is_write, sigset_t *old_set) |
| 348 | { | 348 | { |
| 349 | + TranslationBlock *tb; | ||
| 350 | + int ret; | ||
| 351 | + uint32_t found_pc; | ||
| 352 | + | ||
| 349 | #if defined(DEBUG_SIGNAL) | 353 | #if defined(DEBUG_SIGNAL) |
| 350 | printf("qemu: SIGSEGV pc=0x%08lx address=%08lx wr=%d oldset=0x%08lx\n", | 354 | printf("qemu: SIGSEGV pc=0x%08lx address=%08lx wr=%d oldset=0x%08lx\n", |
| 351 | pc, address, is_write, *(unsigned long *)old_set); | 355 | pc, address, is_write, *(unsigned long *)old_set); |
| @@ -354,16 +358,18 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, | @@ -354,16 +358,18 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address, | ||
| 354 | if (is_write && page_unprotect(address)) { | 358 | if (is_write && page_unprotect(address)) { |
| 355 | return 1; | 359 | return 1; |
| 356 | } | 360 | } |
| 357 | - if (pc >= (unsigned long)code_gen_buffer && | ||
| 358 | - pc < (unsigned long)code_gen_buffer + CODE_GEN_BUFFER_SIZE) { | 361 | + tb = tb_find_pc(pc); |
| 362 | + if (tb) { | ||
| 359 | /* the PC is inside the translated code. It means that we have | 363 | /* the PC is inside the translated code. It means that we have |
| 360 | a virtual CPU fault */ | 364 | a virtual CPU fault */ |
| 365 | + ret = cpu_x86_search_pc(tb, &found_pc, pc); | ||
| 366 | + if (ret < 0) | ||
| 367 | + return 0; | ||
| 368 | + env->eip = found_pc - tb->cs_base; | ||
| 369 | + env->cr2 = address; | ||
| 361 | /* we restore the process signal mask as the sigreturn should | 370 | /* we restore the process signal mask as the sigreturn should |
| 362 | - do it */ | 371 | + do it (XXX: use sigsetjmp) */ |
| 363 | sigprocmask(SIG_SETMASK, old_set, NULL); | 372 | sigprocmask(SIG_SETMASK, old_set, NULL); |
| 364 | - /* XXX: need to compute virtual pc position by retranslating | ||
| 365 | - code. The rest of the CPU state should be correct. */ | ||
| 366 | - env->cr2 = address; | ||
| 367 | raise_exception_err(EXCP0E_PAGE, 4 | (is_write << 1)); | 373 | raise_exception_err(EXCP0E_PAGE, 4 | (is_write << 1)); |
| 368 | /* never comes here */ | 374 | /* never comes here */ |
| 369 | return 1; | 375 | return 1; |
exec-i386.h
| @@ -217,11 +217,14 @@ typedef struct CCTable { | @@ -217,11 +217,14 @@ typedef struct CCTable { | ||
| 217 | 217 | ||
| 218 | extern CCTable cc_table[]; | 218 | extern CCTable cc_table[]; |
| 219 | 219 | ||
| 220 | -void load_seg(int seg_reg, int selector); | 220 | +void load_seg(int seg_reg, int selector, unsigned cur_eip); |
| 221 | void cpu_lock(void); | 221 | void cpu_lock(void); |
| 222 | void cpu_unlock(void); | 222 | void cpu_unlock(void); |
| 223 | +void raise_interrupt(int intno, int is_int, int error_code, | ||
| 224 | + unsigned int next_eip); | ||
| 223 | void raise_exception_err(int exception_index, int error_code); | 225 | void raise_exception_err(int exception_index, int error_code); |
| 224 | void raise_exception(int exception_index); | 226 | void raise_exception(int exception_index); |
| 227 | +void cpu_loop_exit(void); | ||
| 225 | 228 | ||
| 226 | void OPPROTO op_movl_eflags_T0(void); | 229 | void OPPROTO op_movl_eflags_T0(void); |
| 227 | void OPPROTO op_movl_T0_eflags(void); | 230 | void OPPROTO op_movl_T0_eflags(void); |
exec.c
| @@ -531,3 +531,34 @@ void page_unprotect_range(uint8_t *data, unsigned long data_size) | @@ -531,3 +531,34 @@ void page_unprotect_range(uint8_t *data, unsigned long data_size) | ||
| 531 | page_unprotect(addr); | 531 | page_unprotect(addr); |
| 532 | } | 532 | } |
| 533 | } | 533 | } |
| 534 | + | ||
| 535 | +/* find the TB 'tb' such that tb[0].tc_ptr <= tc_ptr < | ||
| 536 | + tb[1].tc_ptr. Return NULL if not found */ | ||
| 537 | +TranslationBlock *tb_find_pc(unsigned long tc_ptr) | ||
| 538 | +{ | ||
| 539 | + int m_min, m_max, m; | ||
| 540 | + unsigned long v; | ||
| 541 | + TranslationBlock *tb; | ||
| 542 | + | ||
| 543 | + if (nb_tbs <= 0) | ||
| 544 | + return NULL; | ||
| 545 | + if (tc_ptr < (unsigned long)code_gen_buffer || | ||
| 546 | + tc_ptr >= (unsigned long)code_gen_ptr) | ||
| 547 | + return NULL; | ||
| 548 | + /* binary search (cf Knuth) */ | ||
| 549 | + m_min = 0; | ||
| 550 | + m_max = nb_tbs - 1; | ||
| 551 | + while (m_min <= m_max) { | ||
| 552 | + m = (m_min + m_max) >> 1; | ||
| 553 | + tb = &tbs[m]; | ||
| 554 | + v = (unsigned long)tb->tc_ptr; | ||
| 555 | + if (v == tc_ptr) | ||
| 556 | + return tb; | ||
| 557 | + else if (tc_ptr < v) { | ||
| 558 | + m_max = m - 1; | ||
| 559 | + } else { | ||
| 560 | + m_min = m + 1; | ||
| 561 | + } | ||
| 562 | + } | ||
| 563 | + return &tbs[m_max]; | ||
| 564 | +} |
exec.h
| @@ -28,10 +28,10 @@ | @@ -28,10 +28,10 @@ | ||
| 28 | #define GEN_FLAG_IOPL_SHIFT 12 /* same position as eflags */ | 28 | #define GEN_FLAG_IOPL_SHIFT 12 /* same position as eflags */ |
| 29 | 29 | ||
| 30 | struct TranslationBlock; | 30 | struct TranslationBlock; |
| 31 | -int cpu_x86_gen_code(uint8_t *gen_code_buf, int max_code_size, | ||
| 32 | - int *gen_code_size_ptr, | ||
| 33 | - uint8_t *pc_start, uint8_t *cs_base, int flags, | ||
| 34 | - int *code_size_ptr, struct TranslationBlock *tb); | 31 | +int cpu_x86_gen_code(struct TranslationBlock *tb, |
| 32 | + int max_code_size, int *gen_code_size_ptr); | ||
| 33 | +int cpu_x86_search_pc(struct TranslationBlock *tb, | ||
| 34 | + uint32_t *found_pc, unsigned long searched_pc); | ||
| 35 | void cpu_x86_tblocks_init(void); | 35 | void cpu_x86_tblocks_init(void); |
| 36 | void page_init(void); | 36 | void page_init(void); |
| 37 | int page_unprotect(unsigned long address); | 37 | int page_unprotect(unsigned long address); |
| @@ -161,6 +161,8 @@ static inline void tb_add_jump(TranslationBlock *tb, int n, | @@ -161,6 +161,8 @@ static inline void tb_add_jump(TranslationBlock *tb, int n, | ||
| 161 | } | 161 | } |
| 162 | } | 162 | } |
| 163 | 163 | ||
| 164 | +TranslationBlock *tb_find_pc(unsigned long pc_ptr); | ||
| 165 | + | ||
| 164 | #ifndef offsetof | 166 | #ifndef offsetof |
| 165 | #define offsetof(type, field) ((size_t) &((type *)0)->field) | 167 | #define offsetof(type, field) ((size_t) &((type *)0)->field) |
| 166 | #endif | 168 | #endif |