Commit b56dad1c7bde3bdf53895fe6eff13bfb47e3ae9e
1 parent
9ba5695c
added raise_exception_err() - added cr2 update
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@126 c046a42c-6fe2-441c-8c8c-71466251a162
Showing
1 changed file
with
34 additions
and
11 deletions
exec-i386.c
... | ... | @@ -149,7 +149,7 @@ void cpu_unlock(void) |
149 | 149 | |
150 | 150 | /* exception support */ |
151 | 151 | /* NOTE: not static to force relocation generation by GCC */ |
152 | -void raise_exception(int exception_index) | |
152 | +void raise_exception_err(int exception_index, int error_code) | |
153 | 153 | { |
154 | 154 | /* NOTE: the register at this point must be saved by hand because |
155 | 155 | longjmp restore them */ |
... | ... | @@ -178,9 +178,16 @@ void raise_exception(int exception_index) |
178 | 178 | env->regs[R_EDI] = EDI; |
179 | 179 | #endif |
180 | 180 | env->exception_index = exception_index; |
181 | + env->error_code = error_code; | |
181 | 182 | longjmp(env->jmp_env, 1); |
182 | 183 | } |
183 | 184 | |
185 | +/* short cut if error_code is 0 or not present */ | |
186 | +void raise_exception(int exception_index) | |
187 | +{ | |
188 | + raise_exception_err(exception_index, 0); | |
189 | +} | |
190 | + | |
184 | 191 | #if defined(DEBUG_EXEC) |
185 | 192 | static const char *cc_op_str[] = { |
186 | 193 | "DYNAMIC", |
... | ... | @@ -218,8 +225,13 @@ static const char *cc_op_str[] = { |
218 | 225 | static void cpu_x86_dump_state(FILE *f) |
219 | 226 | { |
220 | 227 | int eflags; |
228 | + char cc_op_name[32]; | |
221 | 229 | eflags = cc_table[CC_OP].compute_all(); |
222 | 230 | eflags |= (DF & DF_MASK); |
231 | + if ((unsigned)env->cc_op < CC_OP_NB) | |
232 | + strcpy(cc_op_name, cc_op_str[env->cc_op]); | |
233 | + else | |
234 | + snprintf(cc_op_name, sizeof(cc_op_name), "[%d]", env->cc_op); | |
223 | 235 | fprintf(f, |
224 | 236 | "EAX=%08x EBX=%08X ECX=%08x EDX=%08x\n" |
225 | 237 | "ESI=%08x EDI=%08X EBP=%08x ESP=%08x\n" |
... | ... | @@ -227,7 +239,7 @@ static void cpu_x86_dump_state(FILE *f) |
227 | 239 | "EIP=%08x\n", |
228 | 240 | env->regs[R_EAX], env->regs[R_EBX], env->regs[R_ECX], env->regs[R_EDX], |
229 | 241 | env->regs[R_ESI], env->regs[R_EDI], env->regs[R_EBP], env->regs[R_ESP], |
230 | - env->cc_src, env->cc_dst, cc_op_str[env->cc_op], | |
242 | + env->cc_src, env->cc_dst, cc_op_name, | |
231 | 243 | eflags & DF_MASK ? 'D' : '-', |
232 | 244 | eflags & CC_O ? 'O' : '-', |
233 | 245 | eflags & CC_S ? 'S' : '-', |
... | ... | @@ -280,14 +292,18 @@ static inline TranslationBlock *tb_find(TranslationBlock ***pptb, |
280 | 292 | |
281 | 293 | h = pc & (CODE_GEN_HASH_SIZE - 1); |
282 | 294 | ptb = &tb_hash[h]; |
283 | - for(;;) { | |
284 | - tb = *ptb; | |
285 | - if (!tb) | |
286 | - break; | |
287 | - if (tb->pc == pc && tb->cs_base == cs_base && tb->flags == flags) | |
295 | +#if 0 | |
296 | + /* XXX: hack to handle 16 bit modyfing code */ | |
297 | + if (flags & (1 << GEN_FLAG_CODE32_SHIFT)) | |
298 | +#endif | |
299 | + for(;;) { | |
300 | + tb = *ptb; | |
301 | + if (!tb) | |
302 | + break; | |
303 | + if (tb->pc == pc && tb->cs_base == cs_base && tb->flags == flags) | |
288 | 304 | return tb; |
289 | - ptb = &tb->hash_next; | |
290 | - } | |
305 | + ptb = &tb->hash_next; | |
306 | + } | |
291 | 307 | *pptb = ptb; |
292 | 308 | return NULL; |
293 | 309 | } |
... | ... | @@ -404,6 +420,8 @@ int cpu_x86_exec(CPUX86State *env1) |
404 | 420 | (unsigned long)env->seg_cache[R_SS].base) != 0) << |
405 | 421 | GEN_FLAG_ADDSEG_SHIFT; |
406 | 422 | flags |= (env->eflags & VM_MASK) >> (17 - GEN_FLAG_VM_SHIFT); |
423 | + flags |= (env->eflags & IOPL_MASK) >> (12 - GEN_FLAG_IOPL_SHIFT); | |
424 | + flags |= (env->segs[R_CS] & 3) << GEN_FLAG_CPL_SHIFT; | |
407 | 425 | cs_base = env->seg_cache[R_CS].base; |
408 | 426 | pc = cs_base + env->eip; |
409 | 427 | tb = tb_find(&ptb, (unsigned long)pc, (unsigned long)cs_base, |
... | ... | @@ -508,7 +526,10 @@ void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector) |
508 | 526 | #include <signal.h> |
509 | 527 | #include <sys/ucontext.h> |
510 | 528 | |
529 | +/* 'pc' is the host PC at which the exception was raised. 'address' is | |
530 | + the effective address of the memory exception */ | |
511 | 531 | static inline int handle_cpu_signal(unsigned long pc, |
532 | + unsigned long address, | |
512 | 533 | sigset_t *old_set) |
513 | 534 | { |
514 | 535 | #ifdef DEBUG_SIGNAL |
... | ... | @@ -524,7 +545,9 @@ static inline int handle_cpu_signal(unsigned long pc, |
524 | 545 | sigprocmask(SIG_SETMASK, old_set, NULL); |
525 | 546 | /* XXX: need to compute virtual pc position by retranslating |
526 | 547 | code. The rest of the CPU state should be correct. */ |
527 | - raise_exception(EXCP0D_GPF); | |
548 | + env->cr2 = address; | |
549 | + /* XXX: more precise exception code */ | |
550 | + raise_exception_err(EXCP0E_PAGE, 4); | |
528 | 551 | /* never comes here */ |
529 | 552 | return 1; |
530 | 553 | } else { |
... | ... | @@ -546,7 +569,7 @@ int cpu_x86_signal_handler(int host_signum, struct siginfo *info, |
546 | 569 | #endif |
547 | 570 | pc = uc->uc_mcontext.gregs[REG_EIP]; |
548 | 571 | pold_set = &uc->uc_sigmask; |
549 | - return handle_cpu_signal(pc, pold_set); | |
572 | + return handle_cpu_signal(pc, (unsigned long)info->si_addr, pold_set); | |
550 | 573 | #else |
551 | 574 | #warning No CPU specific signal handler: cannot handle target SIGSEGV events |
552 | 575 | return 0; | ... | ... |