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 | ... | ... |