39 |
spin_unlock(&global_cpu_lock); |
spin_unlock(&global_cpu_lock); |
40 |
} |
} |
41 |
|
|
42 |
/* exception support */ |
void cpu_loop_exit(void) |
|
/* NOTE: not static to force relocation generation by GCC */ |
|
|
void raise_exception_err(int exception_index, int error_code) |
|
43 |
{ |
{ |
44 |
/* NOTE: the register at this point must be saved by hand because |
/* NOTE: the register at this point must be saved by hand because |
45 |
longjmp restore them */ |
longjmp restore them */ |
74 |
#ifdef reg_EDI |
#ifdef reg_EDI |
75 |
env->regs[R_EDI] = EDI; |
env->regs[R_EDI] = EDI; |
76 |
#endif |
#endif |
|
env->exception_index = exception_index; |
|
|
env->error_code = error_code; |
|
77 |
longjmp(env->jmp_env, 1); |
longjmp(env->jmp_env, 1); |
78 |
} |
} |
79 |
|
|
|
/* short cut if error_code is 0 or not present */ |
|
|
void raise_exception(int exception_index) |
|
|
{ |
|
|
raise_exception_err(exception_index, 0); |
|
|
} |
|
|
|
|
80 |
int cpu_x86_exec(CPUX86State *env1) |
int cpu_x86_exec(CPUX86State *env1) |
81 |
{ |
{ |
82 |
int saved_T0, saved_T1, saved_A0; |
int saved_T0, saved_T1, saved_A0; |
105 |
#ifdef reg_EDI |
#ifdef reg_EDI |
106 |
int saved_EDI; |
int saved_EDI; |
107 |
#endif |
#endif |
108 |
int code_gen_size, ret, code_size; |
int code_gen_size, ret; |
109 |
void (*gen_func)(void); |
void (*gen_func)(void); |
110 |
TranslationBlock *tb, **ptb; |
TranslationBlock *tb, **ptb; |
111 |
uint8_t *tc_ptr, *cs_base, *pc; |
uint8_t *tc_ptr, *cs_base, *pc; |
162 |
T0 = 0; /* force lookup of first TB */ |
T0 = 0; /* force lookup of first TB */ |
163 |
for(;;) { |
for(;;) { |
164 |
if (env->interrupt_request) { |
if (env->interrupt_request) { |
165 |
raise_exception(EXCP_INTERRUPT); |
env->exception_index = EXCP_INTERRUPT; |
166 |
|
cpu_loop_exit(); |
167 |
} |
} |
168 |
#ifdef DEBUG_EXEC |
#ifdef DEBUG_EXEC |
169 |
if (loglevel) { |
if (loglevel) { |
217 |
} |
} |
218 |
tc_ptr = code_gen_ptr; |
tc_ptr = code_gen_ptr; |
219 |
tb->tc_ptr = tc_ptr; |
tb->tc_ptr = tc_ptr; |
220 |
ret = cpu_x86_gen_code(code_gen_ptr, CODE_GEN_MAX_SIZE, |
tb->cs_base = (unsigned long)cs_base; |
221 |
&code_gen_size, pc, cs_base, flags, |
tb->flags = flags; |
222 |
&code_size, tb); |
ret = cpu_x86_gen_code(tb, CODE_GEN_MAX_SIZE, &code_gen_size); |
223 |
/* if invalid instruction, signal it */ |
/* if invalid instruction, signal it */ |
224 |
if (ret != 0) { |
if (ret != 0) { |
225 |
/* NOTE: the tb is allocated but not linked, so we |
/* NOTE: the tb is allocated but not linked, so we |
228 |
raise_exception(EXCP06_ILLOP); |
raise_exception(EXCP06_ILLOP); |
229 |
} |
} |
230 |
*ptb = tb; |
*ptb = tb; |
|
tb->size = code_size; |
|
|
tb->cs_base = (unsigned long)cs_base; |
|
|
tb->flags = flags; |
|
231 |
tb->hash_next = NULL; |
tb->hash_next = NULL; |
232 |
tb_link(tb); |
tb_link(tb); |
233 |
code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1)); |
code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1)); |
311 |
|
|
312 |
saved_env = env; |
saved_env = env; |
313 |
env = s; |
env = s; |
314 |
load_seg(seg_reg, selector); |
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; |
env = saved_env; |
328 |
} |
} |
329 |
|
|
346 |
static inline int handle_cpu_signal(unsigned long pc, unsigned long address, |
static inline int handle_cpu_signal(unsigned long pc, unsigned long address, |
347 |
int is_write, sigset_t *old_set) |
int is_write, sigset_t *old_set) |
348 |
{ |
{ |
349 |
|
TranslationBlock *tb; |
350 |
|
int ret; |
351 |
|
uint32_t found_pc; |
352 |
|
|
353 |
#if defined(DEBUG_SIGNAL) |
#if defined(DEBUG_SIGNAL) |
354 |
printf("qemu: SIGSEGV pc=0x%08lx address=%08lx wr=%d oldset=0x%08lx\n", |
printf("qemu: SIGSEGV pc=0x%08lx address=%08lx wr=%d oldset=0x%08lx\n", |
355 |
pc, address, is_write, *(unsigned long *)old_set); |
pc, address, is_write, *(unsigned long *)old_set); |
358 |
if (is_write && page_unprotect(address)) { |
if (is_write && page_unprotect(address)) { |
359 |
return 1; |
return 1; |
360 |
} |
} |
361 |
if (pc >= (unsigned long)code_gen_buffer && |
tb = tb_find_pc(pc); |
362 |
pc < (unsigned long)code_gen_buffer + CODE_GEN_BUFFER_SIZE) { |
if (tb) { |
363 |
/* the PC is inside the translated code. It means that we have |
/* the PC is inside the translated code. It means that we have |
364 |
a virtual CPU fault */ |
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; |
370 |
/* we restore the process signal mask as the sigreturn should |
/* we restore the process signal mask as the sigreturn should |
371 |
do it */ |
do it (XXX: use sigsetjmp) */ |
372 |
sigprocmask(SIG_SETMASK, old_set, NULL); |
sigprocmask(SIG_SETMASK, old_set, NULL); |
|
/* XXX: need to compute virtual pc position by retranslating |
|
|
code. The rest of the CPU state should be correct. */ |
|
|
env->cr2 = address; |
|
373 |
raise_exception_err(EXCP0E_PAGE, 4 | (is_write << 1)); |
raise_exception_err(EXCP0E_PAGE, 4 | (is_write << 1)); |
374 |
/* never comes here */ |
/* never comes here */ |
375 |
return 1; |
return 1; |