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,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);
@@ -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 +}
@@ -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