25 |
|
|
26 |
/* main execution loop */ |
/* main execution loop */ |
27 |
|
|
|
/* thread support */ |
|
|
|
|
|
spinlock_t global_cpu_lock = SPIN_LOCK_UNLOCKED; |
|
|
|
|
|
void cpu_lock(void) |
|
|
{ |
|
|
spin_lock(&global_cpu_lock); |
|
|
} |
|
|
|
|
|
void cpu_unlock(void) |
|
|
{ |
|
|
spin_unlock(&global_cpu_lock); |
|
|
} |
|
|
|
|
|
void cpu_loop_exit(void) |
|
|
{ |
|
|
/* NOTE: the register at this point must be saved by hand because |
|
|
longjmp restore them */ |
|
|
#ifdef __sparc__ |
|
|
/* We have to stay in the same register window as our caller, |
|
|
* thus this trick. |
|
|
*/ |
|
|
__asm__ __volatile__("restore\n\t" |
|
|
"mov\t%o0, %i0"); |
|
|
#endif |
|
|
#ifdef reg_EAX |
|
|
env->regs[R_EAX] = EAX; |
|
|
#endif |
|
|
#ifdef reg_ECX |
|
|
env->regs[R_ECX] = ECX; |
|
|
#endif |
|
|
#ifdef reg_EDX |
|
|
env->regs[R_EDX] = EDX; |
|
|
#endif |
|
|
#ifdef reg_EBX |
|
|
env->regs[R_EBX] = EBX; |
|
|
#endif |
|
|
#ifdef reg_ESP |
|
|
env->regs[R_ESP] = ESP; |
|
|
#endif |
|
|
#ifdef reg_EBP |
|
|
env->regs[R_EBP] = EBP; |
|
|
#endif |
|
|
#ifdef reg_ESI |
|
|
env->regs[R_ESI] = ESI; |
|
|
#endif |
|
|
#ifdef reg_EDI |
|
|
env->regs[R_EDI] = EDI; |
|
|
#endif |
|
|
longjmp(env->jmp_env, 1); |
|
|
} |
|
|
|
|
28 |
int cpu_x86_exec(CPUX86State *env1) |
int cpu_x86_exec(CPUX86State *env1) |
29 |
{ |
{ |
30 |
int saved_T0, saved_T1, saved_A0; |
int saved_T0, saved_T1, saved_A0; |
53 |
#ifdef reg_EDI |
#ifdef reg_EDI |
54 |
int saved_EDI; |
int saved_EDI; |
55 |
#endif |
#endif |
56 |
|
#ifdef __sparc__ |
57 |
|
int saved_i7, tmp_T0; |
58 |
|
#endif |
59 |
int code_gen_size, ret; |
int code_gen_size, ret; |
60 |
void (*gen_func)(void); |
void (*gen_func)(void); |
61 |
TranslationBlock *tb, **ptb; |
TranslationBlock *tb, **ptb; |
62 |
uint8_t *tc_ptr, *cs_base, *pc; |
uint8_t *tc_ptr, *cs_base, *pc; |
63 |
unsigned int flags; |
unsigned int flags; |
64 |
|
|
65 |
/* first we save global registers */ |
/* first we save global registers */ |
66 |
saved_T0 = T0; |
saved_T0 = T0; |
67 |
saved_T1 = T1; |
saved_T1 = T1; |
100 |
saved_EDI = EDI; |
saved_EDI = EDI; |
101 |
EDI = env->regs[R_EDI]; |
EDI = env->regs[R_EDI]; |
102 |
#endif |
#endif |
103 |
|
#ifdef __sparc__ |
104 |
|
/* we also save i7 because longjmp may not restore it */ |
105 |
|
asm volatile ("mov %%i7, %0" : "=r" (saved_i7)); |
106 |
|
#endif |
107 |
|
|
108 |
/* put eflags in CPU temporary format */ |
/* put eflags in CPU temporary format */ |
109 |
CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); |
CC_SRC = env->eflags & (CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C); |
116 |
if (setjmp(env->jmp_env) == 0) { |
if (setjmp(env->jmp_env) == 0) { |
117 |
T0 = 0; /* force lookup of first TB */ |
T0 = 0; /* force lookup of first TB */ |
118 |
for(;;) { |
for(;;) { |
119 |
|
#ifdef __sparc__ |
120 |
|
/* g1 can be modified by some libc? functions */ |
121 |
|
tmp_T0 = T0; |
122 |
|
#endif |
123 |
if (env->interrupt_request) { |
if (env->interrupt_request) { |
124 |
env->exception_index = EXCP_INTERRUPT; |
env->exception_index = EXCP_INTERRUPT; |
125 |
cpu_loop_exit(); |
cpu_loop_exit(); |
199 |
lookup_symbol((void *)tb->pc)); |
lookup_symbol((void *)tb->pc)); |
200 |
} |
} |
201 |
#endif |
#endif |
202 |
|
#ifdef __sparc__ |
203 |
|
T0 = tmp_T0; |
204 |
|
#endif |
205 |
/* see if we can patch the calling TB */ |
/* see if we can patch the calling TB */ |
206 |
if (T0 != 0 && !(env->eflags & TF_MASK)) { |
if (T0 != 0 && !(env->eflags & TF_MASK)) { |
207 |
spin_lock(&tb_lock); |
spin_lock(&tb_lock); |
208 |
tb_add_jump((TranslationBlock *)(T0 & ~3), T0 & 3, tb); |
tb_add_jump((TranslationBlock *)(T0 & ~3), T0 & 3, tb); |
209 |
spin_unlock(&tb_lock); |
spin_unlock(&tb_lock); |
210 |
} |
} |
|
|
|
211 |
tc_ptr = tb->tc_ptr; |
tc_ptr = tb->tc_ptr; |
212 |
|
|
213 |
/* execute the generated code */ |
/* execute the generated code */ |
214 |
gen_func = (void *)tc_ptr; |
gen_func = (void *)tc_ptr; |
215 |
#ifdef __sparc__ |
#if defined(__sparc__) |
216 |
__asm__ __volatile__("call %0\n\t" |
__asm__ __volatile__("call %0\n\t" |
217 |
" mov %%o7,%%i0" |
"mov %%o7,%%i0" |
218 |
: /* no outputs */ |
: /* no outputs */ |
219 |
: "r" (gen_func) |
: "r" (gen_func) |
220 |
: "i0", "i1", "i2", "i3", "i4", "i5"); |
: "i0", "i1", "i2", "i3", "i4", "i5"); |
221 |
|
#elif defined(__arm__) |
222 |
|
asm volatile ("mov pc, %0\n\t" |
223 |
|
".global exec_loop\n\t" |
224 |
|
"exec_loop:\n\t" |
225 |
|
: /* no outputs */ |
226 |
|
: "r" (gen_func) |
227 |
|
: "r1", "r2", "r3", "r8", "r9", "r10", "r12", "r14"); |
228 |
#else |
#else |
229 |
gen_func(); |
gen_func(); |
230 |
#endif |
#endif |
260 |
#ifdef reg_EDI |
#ifdef reg_EDI |
261 |
EDI = saved_EDI; |
EDI = saved_EDI; |
262 |
#endif |
#endif |
263 |
|
#ifdef __sparc__ |
264 |
|
asm volatile ("mov %0, %%i7" : : "r" (saved_i7)); |
265 |
|
#endif |
266 |
T0 = saved_T0; |
T0 = saved_T0; |
267 |
T1 = saved_T1; |
T1 = saved_T1; |
268 |
A0 = saved_A0; |
A0 = saved_A0; |
428 |
uint32_t insn = *pc; |
uint32_t insn = *pc; |
429 |
int is_write = 0; |
int is_write = 0; |
430 |
|
|
431 |
|
/* XXX: need kernel patch to get write flag faster */ |
432 |
switch (insn >> 26) { |
switch (insn >> 26) { |
433 |
case 0x0d: // stw |
case 0x0d: // stw |
434 |
case 0x0e: // stb |
case 0x0e: // stb |
447 |
return handle_cpu_signal(pc, (unsigned long)info->si_addr, |
return handle_cpu_signal(pc, (unsigned long)info->si_addr, |
448 |
is_write, &uc->uc_sigmask); |
is_write, &uc->uc_sigmask); |
449 |
} |
} |
450 |
|
#elif defined(__sparc__) |
451 |
|
|
452 |
|
int cpu_x86_signal_handler(int host_signum, struct siginfo *info, |
453 |
|
void *puc) |
454 |
|
{ |
455 |
|
uint32_t *regs = (uint32_t *)(info + 1); |
456 |
|
void *sigmask = (regs + 20); |
457 |
|
unsigned long pc; |
458 |
|
int is_write; |
459 |
|
uint32_t insn; |
460 |
|
|
461 |
|
/* XXX: is there a standard glibc define ? */ |
462 |
|
pc = regs[1]; |
463 |
|
/* XXX: need kernel patch to get write flag faster */ |
464 |
|
is_write = 0; |
465 |
|
insn = *(uint32_t *)pc; |
466 |
|
if ((insn >> 30) == 3) { |
467 |
|
switch((insn >> 19) & 0x3f) { |
468 |
|
case 0x05: // stb |
469 |
|
case 0x06: // sth |
470 |
|
case 0x04: // st |
471 |
|
case 0x07: // std |
472 |
|
case 0x24: // stf |
473 |
|
case 0x27: // stdf |
474 |
|
case 0x25: // stfsr |
475 |
|
is_write = 1; |
476 |
|
break; |
477 |
|
} |
478 |
|
} |
479 |
|
return handle_cpu_signal(pc, (unsigned long)info->si_addr, |
480 |
|
is_write, sigmask); |
481 |
|
} |
482 |
|
|
483 |
|
#elif defined(__arm__) |
484 |
|
|
485 |
|
int cpu_x86_signal_handler(int host_signum, struct siginfo *info, |
486 |
|
void *puc) |
487 |
|
{ |
488 |
|
struct ucontext *uc = puc; |
489 |
|
unsigned long pc; |
490 |
|
int is_write; |
491 |
|
|
492 |
|
pc = uc->uc_mcontext.gregs[R15]; |
493 |
|
/* XXX: compute is_write */ |
494 |
|
is_write = 0; |
495 |
|
return handle_cpu_signal(pc, (unsigned long)info->si_addr, |
496 |
|
is_write, |
497 |
|
&uc->uc_sigmask); |
498 |
|
} |
499 |
|
|
500 |
#else |
#else |
501 |
|
|
502 |
#error CPU specific signal handler needed |
#error CPU specific signal handler needed |