Revision 9de5e440 exec-i386.c
b/exec-i386.c | ||
---|---|---|
21 | 21 |
|
22 | 22 |
//#define DEBUG_EXEC |
23 | 23 |
#define DEBUG_FLUSH |
24 |
//#define DEBUG_SIGNAL |
|
24 | 25 |
|
25 | 26 |
/* main execution loop */ |
26 | 27 |
|
... | ... | |
98 | 99 |
global_cpu_lock = 0; |
99 | 100 |
} |
100 | 101 |
|
101 |
#ifdef DEBUG_EXEC |
|
102 |
/* exception support */ |
|
103 |
/* NOTE: not static to force relocation generation by GCC */ |
|
104 |
void raise_exception(int exception_index) |
|
105 |
{ |
|
106 |
/* NOTE: the register at this point must be saved by hand because |
|
107 |
longjmp restore them */ |
|
108 |
#ifdef reg_EAX |
|
109 |
env->regs[R_EAX] = EAX; |
|
110 |
#endif |
|
111 |
#ifdef reg_ECX |
|
112 |
env->regs[R_ECX] = ECX; |
|
113 |
#endif |
|
114 |
#ifdef reg_EDX |
|
115 |
env->regs[R_EDX] = EDX; |
|
116 |
#endif |
|
117 |
#ifdef reg_EBX |
|
118 |
env->regs[R_EBX] = EBX; |
|
119 |
#endif |
|
120 |
#ifdef reg_ESP |
|
121 |
env->regs[R_ESP] = ESP; |
|
122 |
#endif |
|
123 |
#ifdef reg_EBP |
|
124 |
env->regs[R_EBP] = EBP; |
|
125 |
#endif |
|
126 |
#ifdef reg_ESI |
|
127 |
env->regs[R_ESI] = ESI; |
|
128 |
#endif |
|
129 |
#ifdef reg_EDI |
|
130 |
env->regs[R_EDI] = EDI; |
|
131 |
#endif |
|
132 |
env->exception_index = exception_index; |
|
133 |
longjmp(env->jmp_env, 1); |
|
134 |
} |
|
135 |
|
|
136 |
#if defined(DEBUG_EXEC) |
|
102 | 137 |
static const char *cc_op_str[] = { |
103 | 138 |
"DYNAMIC", |
104 | 139 |
"EFLAGS", |
... | ... | |
132 | 167 |
"SARL", |
133 | 168 |
}; |
134 | 169 |
|
135 |
static void cpu_x86_dump_state(void)
|
|
170 |
static void cpu_x86_dump_state(FILE *f)
|
|
136 | 171 |
{ |
137 | 172 |
int eflags; |
138 | 173 |
eflags = cc_table[CC_OP].compute_all(); |
139 | 174 |
eflags |= (DF & DIRECTION_FLAG); |
140 |
fprintf(logfile,
|
|
175 |
fprintf(f,
|
|
141 | 176 |
"EAX=%08x EBX=%08X ECX=%08x EDX=%08x\n" |
142 | 177 |
"ESI=%08x EDI=%08X EBP=%08x ESP=%08x\n" |
143 |
"CCS=%08x CCD=%08x CCO=%-8s EFL=%c%c%c%c%c%c%c\n", |
|
178 |
"CCS=%08x CCD=%08x CCO=%-8s EFL=%c%c%c%c%c%c%c\n" |
|
179 |
"EIP=%08x\n", |
|
144 | 180 |
env->regs[R_EAX], env->regs[R_EBX], env->regs[R_ECX], env->regs[R_EDX], |
145 | 181 |
env->regs[R_ESI], env->regs[R_EDI], env->regs[R_EBP], env->regs[R_ESP], |
146 | 182 |
env->cc_src, env->cc_dst, cc_op_str[env->cc_op], |
... | ... | |
150 | 186 |
eflags & CC_Z ? 'Z' : '-', |
151 | 187 |
eflags & CC_A ? 'A' : '-', |
152 | 188 |
eflags & CC_P ? 'P' : '-', |
153 |
eflags & CC_C ? 'C' : '-' |
|
154 |
); |
|
189 |
eflags & CC_C ? 'C' : '-',
|
|
190 |
env->eip);
|
|
155 | 191 |
#if 1 |
156 |
fprintf(logfile, "ST0=%f ST1=%f ST2=%f ST3=%f\n",
|
|
192 |
fprintf(f, "ST0=%f ST1=%f ST2=%f ST3=%f\n",
|
|
157 | 193 |
(double)ST0, (double)ST1, (double)ST(2), (double)ST(3)); |
158 | 194 |
#endif |
159 | 195 |
} |
... | ... | |
185 | 221 |
} |
186 | 222 |
|
187 | 223 |
/* find a translation block in the translation cache. If not found, |
188 |
allocate a new one */ |
|
189 |
static inline TranslationBlock *tb_find_and_alloc(unsigned long pc, |
|
190 |
unsigned long cs_base, |
|
191 |
unsigned int flags) |
|
224 |
return NULL and the pointer to the last element of the list in pptb */ |
|
225 |
static inline TranslationBlock *tb_find(TranslationBlock ***pptb, |
|
226 |
unsigned long pc, |
|
227 |
unsigned long cs_base, |
|
228 |
unsigned int flags) |
|
192 | 229 |
{ |
193 | 230 |
TranslationBlock **ptb, *tb; |
194 | 231 |
unsigned int h; |
... | ... | |
203 | 240 |
return tb; |
204 | 241 |
ptb = &tb->hash_next; |
205 | 242 |
} |
243 |
*pptb = ptb; |
|
244 |
return NULL; |
|
245 |
} |
|
246 |
|
|
247 |
/* allocate a new translation block. flush the translation buffer if |
|
248 |
too many translation blocks or too much generated code */ |
|
249 |
static inline TranslationBlock *tb_alloc(void) |
|
250 |
{ |
|
251 |
TranslationBlock *tb; |
|
206 | 252 |
if (nb_tbs >= CODE_GEN_MAX_BLOCKS || |
207 | 253 |
(code_gen_ptr - code_gen_buffer) >= CODE_GEN_BUFFER_MAX_SIZE) |
208 | 254 |
tb_flush(); |
209 | 255 |
tb = &tbs[nb_tbs++]; |
210 |
*ptb = tb; |
|
211 |
tb->pc = pc; |
|
212 |
tb->cs_base = cs_base; |
|
213 |
tb->flags = flags; |
|
214 |
tb->tc_ptr = NULL; |
|
215 |
tb->hash_next = NULL; |
|
216 | 256 |
return tb; |
217 | 257 |
} |
218 | 258 |
|
... | ... | |
246 | 286 |
#endif |
247 | 287 |
int code_gen_size, ret; |
248 | 288 |
void (*gen_func)(void); |
249 |
TranslationBlock *tb; |
|
289 |
TranslationBlock *tb, **ptb;
|
|
250 | 290 |
uint8_t *tc_ptr, *cs_base, *pc; |
251 | 291 |
unsigned int flags; |
252 | 292 |
|
... | ... | |
289 | 329 |
EDI = env->regs[R_EDI]; |
290 | 330 |
#endif |
291 | 331 |
|
332 |
/* put eflags in CPU temporary format */ |
|
333 |
T0 = env->eflags; |
|
334 |
op_movl_eflags_T0(); |
|
335 |
CC_OP = CC_OP_EFLAGS; |
|
336 |
env->interrupt_request = 0; |
|
337 |
|
|
292 | 338 |
/* prepare setjmp context for exception handling */ |
293 | 339 |
if (setjmp(env->jmp_env) == 0) { |
294 | 340 |
for(;;) { |
341 |
if (env->interrupt_request) { |
|
342 |
raise_exception(EXCP_INTERRUPT); |
|
343 |
} |
|
295 | 344 |
#ifdef DEBUG_EXEC |
296 | 345 |
if (loglevel) { |
297 |
cpu_x86_dump_state(); |
|
346 |
cpu_x86_dump_state(logfile);
|
|
298 | 347 |
} |
299 | 348 |
#endif |
300 | 349 |
/* we compute the CPU state. We assume it will not |
... | ... | |
307 | 356 |
GEN_FLAG_ADDSEG_SHIFT; |
308 | 357 |
cs_base = env->seg_cache[R_CS].base; |
309 | 358 |
pc = cs_base + env->eip; |
310 |
tb = tb_find_and_alloc((unsigned long)pc, (unsigned long)cs_base, |
|
311 |
flags); |
|
312 |
tc_ptr = tb->tc_ptr; |
|
313 |
if (!tb->tc_ptr) { |
|
359 |
tb = tb_find(&ptb, (unsigned long)pc, (unsigned long)cs_base, |
|
360 |
flags); |
|
361 |
if (!tb) { |
|
314 | 362 |
/* if no translated code available, then translate it now */ |
315 | 363 |
/* XXX: very inefficient: we lock all the cpus when |
316 | 364 |
generating code */ |
317 | 365 |
cpu_lock(); |
318 | 366 |
tc_ptr = code_gen_ptr; |
319 |
cpu_x86_gen_code(code_gen_ptr, CODE_GEN_MAX_SIZE, |
|
320 |
&code_gen_size, pc, cs_base, flags); |
|
367 |
ret = cpu_x86_gen_code(code_gen_ptr, CODE_GEN_MAX_SIZE, |
|
368 |
&code_gen_size, pc, cs_base, flags); |
|
369 |
/* if invalid instruction, signal it */ |
|
370 |
if (ret != 0) { |
|
371 |
cpu_unlock(); |
|
372 |
raise_exception(EXCP06_ILLOP); |
|
373 |
} |
|
374 |
tb = tb_alloc(); |
|
375 |
*ptb = tb; |
|
376 |
tb->pc = (unsigned long)pc; |
|
377 |
tb->cs_base = (unsigned long)cs_base; |
|
378 |
tb->flags = flags; |
|
321 | 379 |
tb->tc_ptr = tc_ptr; |
380 |
tb->hash_next = NULL; |
|
322 | 381 |
code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1)); |
323 | 382 |
cpu_unlock(); |
324 | 383 |
} |
325 | 384 |
/* execute the generated code */ |
385 |
tc_ptr = tb->tc_ptr; |
|
326 | 386 |
gen_func = (void *)tc_ptr; |
327 | 387 |
gen_func(); |
328 | 388 |
} |
329 | 389 |
} |
330 | 390 |
ret = env->exception_index; |
331 | 391 |
|
392 |
/* restore flags in standard format */ |
|
393 |
op_movl_T0_eflags(); |
|
394 |
env->eflags = T0; |
|
395 |
|
|
332 | 396 |
/* restore global registers */ |
333 | 397 |
#ifdef reg_EAX |
334 | 398 |
EAX = saved_EAX; |
... | ... | |
361 | 425 |
return ret; |
362 | 426 |
} |
363 | 427 |
|
428 |
void cpu_x86_interrupt(CPUX86State *s) |
|
429 |
{ |
|
430 |
s->interrupt_request = 1; |
|
431 |
} |
|
432 |
|
|
433 |
|
|
364 | 434 |
void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector) |
365 | 435 |
{ |
366 | 436 |
CPUX86State *saved_env; |
... | ... | |
370 | 440 |
load_seg(seg_reg, selector); |
371 | 441 |
env = saved_env; |
372 | 442 |
} |
443 |
|
|
444 |
#undef EAX |
|
445 |
#undef ECX |
|
446 |
#undef EDX |
|
447 |
#undef EBX |
|
448 |
#undef ESP |
|
449 |
#undef EBP |
|
450 |
#undef ESI |
|
451 |
#undef EDI |
|
452 |
#undef EIP |
|
453 |
#include <signal.h> |
|
454 |
#include <sys/ucontext.h> |
|
455 |
|
|
456 |
static inline int handle_cpu_signal(unsigned long pc, |
|
457 |
sigset_t *old_set) |
|
458 |
{ |
|
459 |
#ifdef DEBUG_SIGNAL |
|
460 |
printf("gemu: SIGSEGV pc=0x%08lx oldset=0x%08lx\n", |
|
461 |
pc, *(unsigned long *)old_set); |
|
462 |
#endif |
|
463 |
if (pc >= (unsigned long)code_gen_buffer && |
|
464 |
pc < (unsigned long)code_gen_buffer + CODE_GEN_BUFFER_SIZE) { |
|
465 |
/* the PC is inside the translated code. It means that we have |
|
466 |
a virtual CPU fault */ |
|
467 |
/* we restore the process signal mask as the sigreturn should |
|
468 |
do it */ |
|
469 |
sigprocmask(SIG_SETMASK, old_set, NULL); |
|
470 |
/* XXX: need to compute virtual pc position by retranslating |
|
471 |
code. The rest of the CPU state should be correct. */ |
|
472 |
raise_exception(EXCP0D_GPF); |
|
473 |
/* never comes here */ |
|
474 |
return 1; |
|
475 |
} else { |
|
476 |
return 0; |
|
477 |
} |
|
478 |
} |
|
479 |
|
|
480 |
int cpu_x86_signal_handler(int host_signum, struct siginfo *info, |
|
481 |
void *puc) |
|
482 |
{ |
|
483 |
#if defined(__i386__) |
|
484 |
struct ucontext *uc = puc; |
|
485 |
unsigned long pc; |
|
486 |
sigset_t *pold_set; |
|
487 |
|
|
488 |
pc = uc->uc_mcontext.gregs[EIP]; |
|
489 |
pold_set = &uc->uc_sigmask; |
|
490 |
return handle_cpu_signal(pc, pold_set); |
|
491 |
#else |
|
492 |
#warning No CPU specific signal handler: cannot handle target SIGSEGV events |
|
493 |
return 0; |
|
494 |
#endif |
|
495 |
} |
Also available in: Unified diff