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 | 451 | } |
| 452 | 452 | |
| 453 | 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 | 455 | } else if (gen_switch == 1) { |
| 456 | 456 | |
| 457 | 457 | /* output C code */ |
| ... | ... | @@ -991,7 +991,7 @@ int load_elf(const char *filename, FILE *outfile, int do_print_enum) |
| 991 | 991 | } |
| 992 | 992 | |
| 993 | 993 | if (do_print_enum) { |
| 994 | - fprintf(outfile, "DEF(end, 0)\n"); | |
| 994 | + fprintf(outfile, "DEF(end, 0, 0)\n"); | |
| 995 | 995 | for(i = 0, sym = symtab; i < nb_syms; i++, sym++) { |
| 996 | 996 | const char *name, *p; |
| 997 | 997 | name = strtab + sym->st_name; | ... | ... |
exec-i386.c
| ... | ... | @@ -39,9 +39,7 @@ void cpu_unlock(void) |
| 39 | 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 | 44 | /* NOTE: the register at this point must be saved by hand because |
| 47 | 45 | longjmp restore them */ |
| ... | ... | @@ -76,17 +74,9 @@ void raise_exception_err(int exception_index, int error_code) |
| 76 | 74 | #ifdef reg_EDI |
| 77 | 75 | env->regs[R_EDI] = EDI; |
| 78 | 76 | #endif |
| 79 | - env->exception_index = exception_index; | |
| 80 | - env->error_code = error_code; | |
| 81 | 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 | 80 | int cpu_x86_exec(CPUX86State *env1) |
| 91 | 81 | { |
| 92 | 82 | int saved_T0, saved_T1, saved_A0; |
| ... | ... | @@ -115,7 +105,7 @@ int cpu_x86_exec(CPUX86State *env1) |
| 115 | 105 | #ifdef reg_EDI |
| 116 | 106 | int saved_EDI; |
| 117 | 107 | #endif |
| 118 | - int code_gen_size, ret, code_size; | |
| 108 | + int code_gen_size, ret; | |
| 119 | 109 | void (*gen_func)(void); |
| 120 | 110 | TranslationBlock *tb, **ptb; |
| 121 | 111 | uint8_t *tc_ptr, *cs_base, *pc; |
| ... | ... | @@ -172,7 +162,8 @@ int cpu_x86_exec(CPUX86State *env1) |
| 172 | 162 | T0 = 0; /* force lookup of first TB */ |
| 173 | 163 | for(;;) { |
| 174 | 164 | if (env->interrupt_request) { |
| 175 | - raise_exception(EXCP_INTERRUPT); | |
| 165 | + env->exception_index = EXCP_INTERRUPT; | |
| 166 | + cpu_loop_exit(); | |
| 176 | 167 | } |
| 177 | 168 | #ifdef DEBUG_EXEC |
| 178 | 169 | if (loglevel) { |
| ... | ... | @@ -226,9 +217,9 @@ int cpu_x86_exec(CPUX86State *env1) |
| 226 | 217 | } |
| 227 | 218 | tc_ptr = code_gen_ptr; |
| 228 | 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 | 223 | /* if invalid instruction, signal it */ |
| 233 | 224 | if (ret != 0) { |
| 234 | 225 | /* NOTE: the tb is allocated but not linked, so we |
| ... | ... | @@ -237,9 +228,6 @@ int cpu_x86_exec(CPUX86State *env1) |
| 237 | 228 | raise_exception(EXCP06_ILLOP); |
| 238 | 229 | } |
| 239 | 230 | *ptb = tb; |
| 240 | - tb->size = code_size; | |
| 241 | - tb->cs_base = (unsigned long)cs_base; | |
| 242 | - tb->flags = flags; | |
| 243 | 231 | tb->hash_next = NULL; |
| 244 | 232 | tb_link(tb); |
| 245 | 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 | 311 | |
| 324 | 312 | saved_env = env; |
| 325 | 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 | 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 | 346 | static inline int handle_cpu_signal(unsigned long pc, unsigned long address, |
| 347 | 347 | int is_write, sigset_t *old_set) |
| 348 | 348 | { |
| 349 | + TranslationBlock *tb; | |
| 350 | + int ret; | |
| 351 | + uint32_t found_pc; | |
| 352 | + | |
| 349 | 353 | #if defined(DEBUG_SIGNAL) |
| 350 | 354 | printf("qemu: SIGSEGV pc=0x%08lx address=%08lx wr=%d oldset=0x%08lx\n", |
| 351 | 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 | 358 | if (is_write && page_unprotect(address)) { |
| 355 | 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 | 363 | /* the PC is inside the translated code. It means that we have |
| 360 | 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 | 370 | /* we restore the process signal mask as the sigreturn should |
| 362 | - do it */ | |
| 371 | + do it (XXX: use sigsetjmp) */ | |
| 363 | 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 | 373 | raise_exception_err(EXCP0E_PAGE, 4 | (is_write << 1)); |
| 368 | 374 | /* never comes here */ |
| 369 | 375 | return 1; | ... | ... |
exec-i386.h
| ... | ... | @@ -217,11 +217,14 @@ typedef struct CCTable { |
| 217 | 217 | |
| 218 | 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 | 221 | void cpu_lock(void); |
| 222 | 222 | void cpu_unlock(void); |
| 223 | +void raise_interrupt(int intno, int is_int, int error_code, | |
| 224 | + unsigned int next_eip); | |
| 223 | 225 | void raise_exception_err(int exception_index, int error_code); |
| 224 | 226 | void raise_exception(int exception_index); |
| 227 | +void cpu_loop_exit(void); | |
| 225 | 228 | |
| 226 | 229 | void OPPROTO op_movl_eflags_T0(void); |
| 227 | 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 | 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 | 28 | #define GEN_FLAG_IOPL_SHIFT 12 /* same position as eflags */ |
| 29 | 29 | |
| 30 | 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 | 35 | void cpu_x86_tblocks_init(void); |
| 36 | 36 | void page_init(void); |
| 37 | 37 | int page_unprotect(unsigned long address); |
| ... | ... | @@ -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 | 166 | #ifndef offsetof |
| 165 | 167 | #define offsetof(type, field) ((size_t) &((type *)0)->field) |
| 166 | 168 | #endif | ... | ... |