spin_unlock(&global_cpu_lock);
}
-/* exception support */
-/* NOTE: not static to force relocation generation by GCC */
-void raise_exception_err(int exception_index, int error_code)
+void cpu_loop_exit(void)
{
/* NOTE: the register at this point must be saved by hand because
longjmp restore them */
#ifdef reg_EDI
env->regs[R_EDI] = EDI;
#endif
- env->exception_index = exception_index;
- env->error_code = error_code;
longjmp(env->jmp_env, 1);
}
-/* short cut if error_code is 0 or not present */
-void raise_exception(int exception_index)
-{
- raise_exception_err(exception_index, 0);
-}
-
int cpu_x86_exec(CPUX86State *env1)
{
int saved_T0, saved_T1, saved_A0;
#ifdef reg_EDI
int saved_EDI;
#endif
- int code_gen_size, ret, code_size;
+ int code_gen_size, ret;
void (*gen_func)(void);
TranslationBlock *tb, **ptb;
uint8_t *tc_ptr, *cs_base, *pc;
unsigned int flags;
-
+
/* first we save global registers */
saved_T0 = T0;
saved_T1 = T1;
/* prepare setjmp context for exception handling */
if (setjmp(env->jmp_env) == 0) {
+ T0 = 0; /* force lookup of first TB */
for(;;) {
if (env->interrupt_request) {
- raise_exception(EXCP_INTERRUPT);
+ env->exception_index = EXCP_INTERRUPT;
+ cpu_loop_exit();
}
#ifdef DEBUG_EXEC
if (loglevel) {
flags |= (1 << GEN_FLAG_VM_SHIFT);
flags |= (3 << GEN_FLAG_CPL_SHIFT);
}
- flags |= (env->eflags & IOPL_MASK) >> (12 - GEN_FLAG_IOPL_SHIFT);
- flags |= (env->eflags & TF_MASK) << (GEN_FLAG_TF_SHIFT - 8);
+ flags |= (env->eflags & (IOPL_MASK | TF_MASK));
cs_base = env->seg_cache[R_CS].base;
pc = cs_base + env->eip;
tb = tb_find(&ptb, (unsigned long)pc, (unsigned long)cs_base,
flags);
if (!tb) {
- /* if no translated code available, then translate it now */
- /* very inefficient but safe: we lock all the cpus
- when generating code */
spin_lock(&tb_lock);
+ /* if no translated code available, then translate it now */
+ tb = tb_alloc((unsigned long)pc);
+ if (!tb) {
+ /* flush must be done */
+ tb_flush();
+ /* cannot fail at this point */
+ tb = tb_alloc((unsigned long)pc);
+ /* don't forget to invalidate previous TB info */
+ ptb = &tb_hash[tb_hash_func((unsigned long)pc)];
+ T0 = 0;
+ }
tc_ptr = code_gen_ptr;
- ret = cpu_x86_gen_code(code_gen_ptr, CODE_GEN_MAX_SIZE,
- &code_gen_size, pc, cs_base, flags,
- &code_size);
+ tb->tc_ptr = tc_ptr;
+ tb->cs_base = (unsigned long)cs_base;
+ tb->flags = flags;
+ ret = cpu_x86_gen_code(tb, CODE_GEN_MAX_SIZE, &code_gen_size);
/* if invalid instruction, signal it */
if (ret != 0) {
+ /* NOTE: the tb is allocated but not linked, so we
+ can leave it */
spin_unlock(&tb_lock);
raise_exception(EXCP06_ILLOP);
}
- tb = tb_alloc((unsigned long)pc, code_size);
*ptb = tb;
- tb->cs_base = (unsigned long)cs_base;
- tb->flags = flags;
- tb->tc_ptr = tc_ptr;
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);
}
lookup_symbol((void *)tb->pc));
}
#endif
- /* execute the generated code */
+ /* see if we can patch the calling TB */
+ if (T0 != 0 && !(env->eflags & TF_MASK)) {
+ spin_lock(&tb_lock);
+ tb_add_jump((TranslationBlock *)(T0 & ~3), T0 & 3, tb);
+ spin_unlock(&tb_lock);
+ }
+
tc_ptr = tb->tc_ptr;
+
+ /* execute the generated code */
gen_func = (void *)tc_ptr;
#ifdef __sparc__
__asm__ __volatile__("call %0\n\t"
" mov %%o7,%%i0"
: /* no outputs */
- : "r" (gen_func)
+ : "r" (gen_func)
: "i0", "i1", "i2", "i3", "i4", "i5");
#else
gen_func();
saved_env = env;
env = s;
- load_seg(seg_reg, selector);
+ if (env->eflags & VM_MASK) {
+ SegmentCache *sc;
+ selector &= 0xffff;
+ sc = &env->seg_cache[seg_reg];
+ /* NOTE: in VM86 mode, limit and seg_32bit are never reloaded,
+ so we must load them here */
+ sc->base = (void *)(selector << 4);
+ sc->limit = 0xffff;
+ sc->seg_32bit = 0;
+ env->segs[seg_reg] = selector;
+ } else {
+ load_seg(seg_reg, selector, 0);
+ }
+ env = saved_env;
+}
+
+void cpu_x86_fsave(CPUX86State *s, uint8_t *ptr, int data32)
+{
+ CPUX86State *saved_env;
+
+ saved_env = env;
+ env = s;
+
+ helper_fsave(ptr, data32);
+
+ env = saved_env;
+}
+
+void cpu_x86_frstor(CPUX86State *s, uint8_t *ptr, int data32)
+{
+ CPUX86State *saved_env;
+
+ saved_env = env;
+ env = s;
+
+ helper_frstor(ptr, data32);
+
env = saved_env;
}
the effective address of the memory exception. 'is_write' is 1 if a
write caused the exception and otherwise 0'. 'old_set' is the
signal set which should be restored */
-static inline int handle_cpu_signal(unsigned long pc,
- unsigned long address,
- int is_write,
- sigset_t *old_set)
+static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
+ int is_write, sigset_t *old_set)
{
+ TranslationBlock *tb;
+ int ret;
+ uint32_t found_pc;
+
#if defined(DEBUG_SIGNAL)
printf("qemu: SIGSEGV pc=0x%08lx address=%08lx wr=%d oldset=0x%08lx\n",
pc, address, is_write, *(unsigned long *)old_set);
#endif
/* XXX: locking issue */
if (is_write && page_unprotect(address)) {
- sigprocmask(SIG_SETMASK, old_set, NULL);
return 1;
}
- if (pc >= (unsigned long)code_gen_buffer &&
- pc < (unsigned long)code_gen_buffer + CODE_GEN_BUFFER_SIZE) {
+ tb = tb_find_pc(pc);
+ if (tb) {
/* the PC is inside the translated code. It means that we have
a virtual CPU fault */
+ ret = cpu_x86_search_pc(tb, &found_pc, pc);
+ if (ret < 0)
+ return 0;
+ env->eip = found_pc - tb->cs_base;
+ env->cr2 = address;
/* we restore the process signal mask as the sigreturn should
- do it */
+ do it (XXX: use sigsetjmp) */
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;
raise_exception_err(EXCP0E_PAGE, 4 | (is_write << 1));
/* never comes here */
return 1;
}
}
+#if defined(__i386__)
+
int cpu_x86_signal_handler(int host_signum, struct siginfo *info,
void *puc)
{
-#if defined(__i386__)
struct ucontext *uc = puc;
unsigned long pc;
- sigset_t *pold_set;
#ifndef REG_EIP
/* for glibc 2.1 */
#define REG_TRAPNO TRAPNO
#endif
pc = uc->uc_mcontext.gregs[REG_EIP];
- pold_set = &uc->uc_sigmask;
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
uc->uc_mcontext.gregs[REG_TRAPNO] == 0xe ?
(uc->uc_mcontext.gregs[REG_ERR] >> 1) & 1 : 0,
- pold_set);
+ &uc->uc_sigmask);
+}
+
#elif defined(__powerpc)
+
+int cpu_x86_signal_handler(int host_signum, struct siginfo *info,
+ void *puc)
+{
struct ucontext *uc = puc;
struct pt_regs *regs = uc->uc_mcontext.regs;
unsigned long pc;
- sigset_t *pold_set;
int is_write;
pc = regs->nip;
- pold_set = &uc->uc_sigmask;
is_write = 0;
#if 0
/* ppc 4xx case */
is_write = 1;
#endif
return handle_cpu_signal(pc, (unsigned long)info->si_addr,
- is_write, pold_set);
+ is_write, &uc->uc_sigmask);
+}
+
#else
+
#error CPU specific signal handler needed
- return 0;
+
#endif
-}