Commit a513fe19ac4896a09c6c338204d76c39e652451f

Authored by bellard
1 parent f4beb510

precise exceptions


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@194 c046a42c-6fe2-441c-8c8c-71466251a162
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);
... ...
... ... @@ -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 +}
... ...
... ... @@ -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
... ...