29 |
|
|
30 |
//#define DEBUG_EXEC |
//#define DEBUG_EXEC |
31 |
//#define DEBUG_SIGNAL |
//#define DEBUG_SIGNAL |
32 |
|
/* enable it to have a fully working x86 emulator for ring 0 */ |
33 |
|
//#define RING0_HACKS |
34 |
|
|
35 |
#if defined(TARGET_ARM) |
#if defined(TARGET_ARM) |
36 |
/* XXX: unify with i386 target */ |
/* XXX: unify with i386 target */ |
142 |
#error unsupported target CPU |
#error unsupported target CPU |
143 |
#endif |
#endif |
144 |
env->interrupt_request = 0; |
env->interrupt_request = 0; |
145 |
|
env->exception_index = -1; |
146 |
|
|
147 |
/* prepare setjmp context for exception handling */ |
/* prepare setjmp context for exception handling */ |
148 |
if (setjmp(env->jmp_env) == 0) { |
for(;;) { |
149 |
T0 = 0; /* force lookup of first TB */ |
if (setjmp(env->jmp_env) == 0) { |
150 |
for(;;) { |
/* if an exception is pending, we execute it here */ |
151 |
|
if (env->exception_index >= 0) { |
152 |
|
if (env->exception_index >= EXCP_INTERRUPT) { |
153 |
|
/* exit request from the cpu execution loop */ |
154 |
|
ret = env->exception_index; |
155 |
|
break; |
156 |
|
} else if (env->user_mode_only) { |
157 |
|
/* if user mode only, we simulate a fake exception |
158 |
|
which will be hanlded outside the cpu execution |
159 |
|
loop */ |
160 |
|
do_interrupt_user(env->exception_index, |
161 |
|
env->exception_is_int, |
162 |
|
env->error_code, |
163 |
|
env->exception_next_eip); |
164 |
|
ret = env->exception_index; |
165 |
|
break; |
166 |
|
} else { |
167 |
|
/* simulate a real cpu exception. On i386, it can |
168 |
|
trigger new exceptions, but we do not handle |
169 |
|
double or triple faults yet. */ |
170 |
|
do_interrupt(env->exception_index, |
171 |
|
env->exception_is_int, |
172 |
|
env->error_code, |
173 |
|
env->exception_next_eip); |
174 |
|
} |
175 |
|
env->exception_index = -1; |
176 |
|
} |
177 |
|
#if defined(TARGET_I386) |
178 |
|
/* if hardware interrupt pending, we execute it */ |
179 |
|
if (env->hard_interrupt_request && |
180 |
|
(env->eflags & IF_MASK)) { |
181 |
|
int intno; |
182 |
|
intno = cpu_x86_get_pic_interrupt(env); |
183 |
|
if (loglevel) { |
184 |
|
fprintf(logfile, "Servicing hardware INT=0x%02x\n", intno); |
185 |
|
} |
186 |
|
do_interrupt(intno, 0, 0, 0); |
187 |
|
env->hard_interrupt_request = 0; |
188 |
|
} |
189 |
|
#endif |
190 |
|
T0 = 0; /* force lookup of first TB */ |
191 |
|
for(;;) { |
192 |
#ifdef __sparc__ |
#ifdef __sparc__ |
193 |
/* g1 can be modified by some libc? functions */ |
/* g1 can be modified by some libc? functions */ |
194 |
tmp_T0 = T0; |
tmp_T0 = T0; |
195 |
#endif |
#endif |
196 |
if (env->interrupt_request) { |
if (env->interrupt_request) { |
197 |
env->exception_index = EXCP_INTERRUPT; |
env->exception_index = EXCP_INTERRUPT; |
198 |
cpu_loop_exit(); |
cpu_loop_exit(); |
199 |
} |
} |
200 |
#ifdef DEBUG_EXEC |
#ifdef DEBUG_EXEC |
201 |
if (loglevel) { |
if (loglevel) { |
202 |
#if defined(TARGET_I386) |
#if defined(TARGET_I386) |
203 |
/* restore flags in standard format */ |
/* restore flags in standard format */ |
204 |
env->regs[R_EAX] = EAX; |
env->regs[R_EAX] = EAX; |
205 |
env->regs[R_EBX] = EBX; |
env->regs[R_EBX] = EBX; |
206 |
env->regs[R_ECX] = ECX; |
env->regs[R_ECX] = ECX; |
207 |
env->regs[R_EDX] = EDX; |
env->regs[R_EDX] = EDX; |
208 |
env->regs[R_ESI] = ESI; |
env->regs[R_ESI] = ESI; |
209 |
env->regs[R_EDI] = EDI; |
env->regs[R_EDI] = EDI; |
210 |
env->regs[R_EBP] = EBP; |
env->regs[R_EBP] = EBP; |
211 |
env->regs[R_ESP] = ESP; |
env->regs[R_ESP] = ESP; |
212 |
env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK); |
env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK); |
213 |
cpu_x86_dump_state(env, logfile, 0); |
cpu_x86_dump_state(env, logfile, 0); |
214 |
env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); |
env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); |
215 |
#elif defined(TARGET_ARM) |
#elif defined(TARGET_ARM) |
216 |
cpu_arm_dump_state(env, logfile, 0); |
cpu_arm_dump_state(env, logfile, 0); |
217 |
#else |
#else |
218 |
#error unsupported target CPU |
#error unsupported target CPU |
219 |
#endif |
#endif |
220 |
} |
} |
221 |
#endif |
#endif |
222 |
/* we compute the CPU state. We assume it will not |
/* we compute the CPU state. We assume it will not |
223 |
change during the whole generated block. */ |
change during the whole generated block. */ |
224 |
#if defined(TARGET_I386) |
#if defined(TARGET_I386) |
225 |
flags = env->segs[R_CS].seg_32bit << GEN_FLAG_CODE32_SHIFT; |
flags = (env->segs[R_CS].flags & DESC_B_MASK) |
226 |
flags |= env->segs[R_SS].seg_32bit << GEN_FLAG_SS32_SHIFT; |
>> (DESC_B_SHIFT - GEN_FLAG_CODE32_SHIFT); |
227 |
flags |= (((unsigned long)env->segs[R_DS].base | |
flags |= (env->segs[R_SS].flags & DESC_B_MASK) |
228 |
(unsigned long)env->segs[R_ES].base | |
>> (DESC_B_SHIFT - GEN_FLAG_SS32_SHIFT); |
229 |
(unsigned long)env->segs[R_SS].base) != 0) << |
flags |= (((unsigned long)env->segs[R_DS].base | |
230 |
GEN_FLAG_ADDSEG_SHIFT; |
(unsigned long)env->segs[R_ES].base | |
231 |
if (!(env->eflags & VM_MASK)) { |
(unsigned long)env->segs[R_SS].base) != 0) << |
232 |
flags |= (env->segs[R_CS].selector & 3) << GEN_FLAG_CPL_SHIFT; |
GEN_FLAG_ADDSEG_SHIFT; |
233 |
} else { |
if (!(env->eflags & VM_MASK)) { |
234 |
/* NOTE: a dummy CPL is kept */ |
flags |= (env->segs[R_CS].selector & 3) << GEN_FLAG_CPL_SHIFT; |
235 |
flags |= (1 << GEN_FLAG_VM_SHIFT); |
} else { |
236 |
flags |= (3 << GEN_FLAG_CPL_SHIFT); |
/* NOTE: a dummy CPL is kept */ |
237 |
} |
flags |= (1 << GEN_FLAG_VM_SHIFT); |
238 |
flags |= (env->eflags & (IOPL_MASK | TF_MASK)); |
flags |= (3 << GEN_FLAG_CPL_SHIFT); |
239 |
cs_base = env->segs[R_CS].base; |
} |
240 |
pc = cs_base + env->eip; |
flags |= (env->eflags & (IOPL_MASK | TF_MASK)); |
241 |
|
cs_base = env->segs[R_CS].base; |
242 |
|
pc = cs_base + env->eip; |
243 |
#elif defined(TARGET_ARM) |
#elif defined(TARGET_ARM) |
244 |
flags = 0; |
flags = 0; |
245 |
cs_base = 0; |
cs_base = 0; |
246 |
pc = (uint8_t *)env->regs[15]; |
pc = (uint8_t *)env->regs[15]; |
247 |
#else |
#else |
248 |
#error unsupported CPU |
#error unsupported CPU |
249 |
#endif |
#endif |
250 |
tb = tb_find(&ptb, (unsigned long)pc, (unsigned long)cs_base, |
tb = tb_find(&ptb, (unsigned long)pc, (unsigned long)cs_base, |
251 |
flags); |
flags); |
|
if (!tb) { |
|
|
spin_lock(&tb_lock); |
|
|
/* if no translated code available, then translate it now */ |
|
|
tb = tb_alloc((unsigned long)pc); |
|
252 |
if (!tb) { |
if (!tb) { |
253 |
/* flush must be done */ |
spin_lock(&tb_lock); |
254 |
tb_flush(); |
/* if no translated code available, then translate it now */ |
|
/* cannot fail at this point */ |
|
255 |
tb = tb_alloc((unsigned long)pc); |
tb = tb_alloc((unsigned long)pc); |
256 |
/* don't forget to invalidate previous TB info */ |
if (!tb) { |
257 |
ptb = &tb_hash[tb_hash_func((unsigned long)pc)]; |
/* flush must be done */ |
258 |
T0 = 0; |
tb_flush(); |
259 |
} |
/* cannot fail at this point */ |
260 |
tc_ptr = code_gen_ptr; |
tb = tb_alloc((unsigned long)pc); |
261 |
tb->tc_ptr = tc_ptr; |
/* don't forget to invalidate previous TB info */ |
262 |
tb->cs_base = (unsigned long)cs_base; |
ptb = &tb_hash[tb_hash_func((unsigned long)pc)]; |
263 |
tb->flags = flags; |
T0 = 0; |
264 |
ret = cpu_gen_code(tb, CODE_GEN_MAX_SIZE, &code_gen_size); |
} |
265 |
|
tc_ptr = code_gen_ptr; |
266 |
|
tb->tc_ptr = tc_ptr; |
267 |
|
tb->cs_base = (unsigned long)cs_base; |
268 |
|
tb->flags = flags; |
269 |
|
ret = cpu_gen_code(tb, CODE_GEN_MAX_SIZE, &code_gen_size); |
270 |
#if defined(TARGET_I386) |
#if defined(TARGET_I386) |
271 |
/* XXX: suppress that, this is incorrect */ |
/* XXX: suppress that, this is incorrect */ |
272 |
/* if invalid instruction, signal it */ |
/* if invalid instruction, signal it */ |
273 |
if (ret != 0) { |
if (ret != 0) { |
274 |
/* NOTE: the tb is allocated but not linked, so we |
/* NOTE: the tb is allocated but not linked, so we |
275 |
can leave it */ |
can leave it */ |
276 |
|
spin_unlock(&tb_lock); |
277 |
|
raise_exception(EXCP06_ILLOP); |
278 |
|
} |
279 |
|
#endif |
280 |
|
*ptb = tb; |
281 |
|
tb->hash_next = NULL; |
282 |
|
tb_link(tb); |
283 |
|
code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1)); |
284 |
spin_unlock(&tb_lock); |
spin_unlock(&tb_lock); |
|
raise_exception(EXCP06_ILLOP); |
|
285 |
} |
} |
|
#endif |
|
|
*ptb = tb; |
|
|
tb->hash_next = NULL; |
|
|
tb_link(tb); |
|
|
code_gen_ptr = (void *)(((unsigned long)code_gen_ptr + code_gen_size + CODE_GEN_ALIGN - 1) & ~(CODE_GEN_ALIGN - 1)); |
|
|
spin_unlock(&tb_lock); |
|
|
} |
|
286 |
#ifdef DEBUG_EXEC |
#ifdef DEBUG_EXEC |
287 |
if (loglevel) { |
if (loglevel) { |
288 |
fprintf(logfile, "Trace 0x%08lx [0x%08lx] %s\n", |
fprintf(logfile, "Trace 0x%08lx [0x%08lx] %s\n", |
289 |
(long)tb->tc_ptr, (long)tb->pc, |
(long)tb->tc_ptr, (long)tb->pc, |
290 |
lookup_symbol((void *)tb->pc)); |
lookup_symbol((void *)tb->pc)); |
291 |
} |
} |
292 |
#endif |
#endif |
293 |
#ifdef __sparc__ |
#ifdef __sparc__ |
294 |
T0 = tmp_T0; |
T0 = tmp_T0; |
295 |
#endif |
#endif |
296 |
/* see if we can patch the calling TB. XXX: remove TF test */ |
/* see if we can patch the calling TB. XXX: remove TF test */ |
297 |
if (T0 != 0 |
#ifndef RING0_HACKS |
298 |
|
|
299 |
|
if (T0 != 0 |
300 |
#if defined(TARGET_I386) |
#if defined(TARGET_I386) |
301 |
&& !(env->eflags & TF_MASK) |
&& !(env->eflags & TF_MASK) |
302 |
#endif |
#endif |
303 |
) { |
) { |
304 |
spin_lock(&tb_lock); |
spin_lock(&tb_lock); |
305 |
tb_add_jump((TranslationBlock *)(T0 & ~3), T0 & 3, tb); |
tb_add_jump((TranslationBlock *)(T0 & ~3), T0 & 3, tb); |
306 |
spin_unlock(&tb_lock); |
spin_unlock(&tb_lock); |
307 |
} |
} |
308 |
tc_ptr = tb->tc_ptr; |
#endif |
309 |
|
tc_ptr = tb->tc_ptr; |
310 |
/* execute the generated code */ |
|
311 |
gen_func = (void *)tc_ptr; |
/* execute the generated code */ |
312 |
|
gen_func = (void *)tc_ptr; |
313 |
#if defined(__sparc__) |
#if defined(__sparc__) |
314 |
__asm__ __volatile__("call %0\n\t" |
__asm__ __volatile__("call %0\n\t" |
315 |
"mov %%o7,%%i0" |
"mov %%o7,%%i0" |
316 |
: /* no outputs */ |
: /* no outputs */ |
317 |
: "r" (gen_func) |
: "r" (gen_func) |
318 |
: "i0", "i1", "i2", "i3", "i4", "i5"); |
: "i0", "i1", "i2", "i3", "i4", "i5"); |
319 |
#elif defined(__arm__) |
#elif defined(__arm__) |
320 |
asm volatile ("mov pc, %0\n\t" |
asm volatile ("mov pc, %0\n\t" |
321 |
".global exec_loop\n\t" |
".global exec_loop\n\t" |
322 |
"exec_loop:\n\t" |
"exec_loop:\n\t" |
323 |
: /* no outputs */ |
: /* no outputs */ |
324 |
: "r" (gen_func) |
: "r" (gen_func) |
325 |
: "r1", "r2", "r3", "r8", "r9", "r10", "r12", "r14"); |
: "r1", "r2", "r3", "r8", "r9", "r10", "r12", "r14"); |
326 |
#else |
#else |
327 |
gen_func(); |
gen_func(); |
328 |
#endif |
#endif |
329 |
|
} |
330 |
|
} else { |
331 |
} |
} |
332 |
} |
} /* for(;;) */ |
333 |
ret = env->exception_index; |
|
334 |
|
|
335 |
#if defined(TARGET_I386) |
#if defined(TARGET_I386) |
336 |
/* restore flags in standard format */ |
/* restore flags in standard format */ |
399 |
SegmentCache *sc; |
SegmentCache *sc; |
400 |
selector &= 0xffff; |
selector &= 0xffff; |
401 |
sc = &env->segs[seg_reg]; |
sc = &env->segs[seg_reg]; |
402 |
/* NOTE: in VM86 mode, limit and seg_32bit are never reloaded, |
/* NOTE: in VM86 mode, limit and flags are never reloaded, |
403 |
so we must load them here */ |
so we must load them here */ |
404 |
sc->base = (void *)(selector << 4); |
sc->base = (void *)(selector << 4); |
405 |
sc->limit = 0xffff; |
sc->limit = 0xffff; |
406 |
sc->seg_32bit = 0; |
sc->flags = 0; |
407 |
sc->selector = selector; |
sc->selector = selector; |
408 |
} else { |
} else { |
409 |
load_seg(seg_reg, selector, 0); |
load_seg(seg_reg, selector, 0); |
449 |
#include <signal.h> |
#include <signal.h> |
450 |
#include <sys/ucontext.h> |
#include <sys/ucontext.h> |
451 |
|
|
452 |
|
#if defined(TARGET_I386) |
453 |
|
|
454 |
/* 'pc' is the host PC at which the exception was raised. 'address' is |
/* 'pc' is the host PC at which the exception was raised. 'address' is |
455 |
the effective address of the memory exception. 'is_write' is 1 if a |
the effective address of the memory exception. 'is_write' is 1 if a |
456 |
write caused the exception and otherwise 0'. 'old_set' is the |
write caused the exception and otherwise 0'. 'old_set' is the |
460 |
{ |
{ |
461 |
TranslationBlock *tb; |
TranslationBlock *tb; |
462 |
int ret; |
int ret; |
|
uint32_t found_pc; |
|
463 |
|
|
464 |
|
#ifdef RING0_HACKS |
465 |
|
env = global_env; /* XXX: find a better solution */ |
466 |
|
#endif |
467 |
#if defined(DEBUG_SIGNAL) |
#if defined(DEBUG_SIGNAL) |
468 |
printf("qemu: SIGSEGV pc=0x%08lx address=%08lx wr=%d oldset=0x%08lx\n", |
printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n", |
469 |
pc, address, is_write, *(unsigned long *)old_set); |
pc, address, is_write, *(unsigned long *)old_set); |
470 |
#endif |
#endif |
471 |
/* XXX: locking issue */ |
/* XXX: locking issue */ |
472 |
if (is_write && page_unprotect(address)) { |
if (is_write && page_unprotect(address)) { |
473 |
return 1; |
return 1; |
474 |
} |
} |
475 |
|
/* see if it is an MMU fault */ |
476 |
|
ret = cpu_x86_handle_mmu_fault(env, address, is_write); |
477 |
|
if (ret < 0) |
478 |
|
return 0; /* not an MMU fault */ |
479 |
|
if (ret == 0) |
480 |
|
return 1; /* the MMU fault was handled without causing real CPU fault */ |
481 |
|
/* now we have a real cpu fault */ |
482 |
tb = tb_find_pc(pc); |
tb = tb_find_pc(pc); |
483 |
if (tb) { |
if (tb) { |
484 |
/* the PC is inside the translated code. It means that we have |
/* the PC is inside the translated code. It means that we have |
485 |
a virtual CPU fault */ |
a virtual CPU fault */ |
486 |
ret = cpu_search_pc(tb, &found_pc, pc); |
cpu_restore_state(tb, env, pc); |
487 |
if (ret < 0) |
} |
488 |
return 0; |
#if 0 |
489 |
#if defined(TARGET_I386) |
printf("PF exception: EIP=0x%08x CR2=0x%08x error=0x%x\n", |
490 |
env->eip = found_pc - tb->cs_base; |
env->eip, env->cr[2], env->error_code); |
491 |
env->cr[2] = address; |
#endif |
492 |
/* we restore the process signal mask as the sigreturn should |
/* we restore the process signal mask as the sigreturn should |
493 |
do it (XXX: use sigsetjmp) */ |
do it (XXX: use sigsetjmp) */ |
494 |
sigprocmask(SIG_SETMASK, old_set, NULL); |
sigprocmask(SIG_SETMASK, old_set, NULL); |
495 |
raise_exception_err(EXCP0E_PAGE, 4 | (is_write << 1)); |
raise_exception_err(EXCP0E_PAGE, env->error_code); |
496 |
|
/* never comes here */ |
497 |
|
return 1; |
498 |
|
} |
499 |
|
|
500 |
#elif defined(TARGET_ARM) |
#elif defined(TARGET_ARM) |
501 |
env->regs[15] = found_pc; |
static inline int handle_cpu_signal(unsigned long pc, unsigned long address, |
502 |
/* XXX: do more */ |
int is_write, sigset_t *old_set) |
503 |
|
{ |
504 |
|
/* XXX: do more */ |
505 |
|
return 0; |
506 |
|
} |
507 |
#else |
#else |
508 |
#error unsupported target CPU |
#error unsupported target CPU |
509 |
#endif |
#endif |
|
/* never comes here */ |
|
|
return 1; |
|
|
} else { |
|
|
return 0; |
|
|
} |
|
|
} |
|
510 |
|
|
511 |
#if defined(__i386__) |
#if defined(__i386__) |
512 |
|
|
634 |
|
|
635 |
#else |
#else |
636 |
|
|
637 |
#error CPU specific signal handler needed |
#error host CPU specific signal handler needed |
638 |
|
|
639 |
#endif |
#endif |