* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "config.h"
-#ifdef TARGET_I386
-#include "exec-i386.h"
-#endif
-#ifdef TARGET_ARM
-#include "exec-arm.h"
-#endif
-
+#include "exec.h"
#include "disas.h"
//#define DEBUG_EXEC
//#define DEBUG_SIGNAL
-/* enable it to have a fully working x86 emulator for ring 0 */
-//#define RING0_HACKS
-#if defined(TARGET_ARM)
+#if defined(TARGET_ARM) || defined(TARGET_SPARC)
/* XXX: unify with i386 target */
void cpu_loop_exit(void)
{
#ifdef __sparc__
int saved_i7, tmp_T0;
#endif
- int code_gen_size, ret;
+ int code_gen_size, ret, interrupt_request;
void (*gen_func)(void);
TranslationBlock *tb, **ptb;
uint8_t *tc_ptr, *cs_base, *pc;
env->VF = (psr << 3) & 0x80000000;
env->cpsr = psr & ~0xf0000000;
}
+#elif defined(TARGET_SPARC)
#else
#error unsupported target CPU
#endif
- env->interrupt_request = 0;
env->exception_index = -1;
/* prepare setjmp context for exception handling */
/* if user mode only, we simulate a fake exception
which will be hanlded outside the cpu execution
loop */
+#if defined(TARGET_I386)
do_interrupt_user(env->exception_index,
env->exception_is_int,
env->error_code,
env->exception_next_eip);
+#endif
ret = env->exception_index;
break;
} else {
+#if defined(TARGET_I386)
/* simulate a real cpu exception. On i386, it can
trigger new exceptions, but we do not handle
double or triple faults yet. */
do_interrupt(env->exception_index,
env->exception_is_int,
env->error_code,
- env->exception_next_eip);
+ env->exception_next_eip, 0);
+#endif
}
env->exception_index = -1;
}
-#if defined(TARGET_I386)
- /* if hardware interrupt pending, we execute it */
- if (env->hard_interrupt_request &&
- (env->eflags & IF_MASK)) {
- int intno;
- intno = cpu_x86_get_pic_interrupt(env);
- if (loglevel) {
- fprintf(logfile, "Servicing hardware INT=0x%02x\n", intno);
- }
- do_interrupt(intno, 0, 0, 0);
- env->hard_interrupt_request = 0;
- }
-#endif
T0 = 0; /* force lookup of first TB */
for(;;) {
#ifdef __sparc__
/* g1 can be modified by some libc? functions */
tmp_T0 = T0;
#endif
- if (env->interrupt_request) {
- env->exception_index = EXCP_INTERRUPT;
- cpu_loop_exit();
+ interrupt_request = env->interrupt_request;
+ if (__builtin_expect(interrupt_request, 0)) {
+#if defined(TARGET_I386)
+ /* if hardware interrupt pending, we execute it */
+ if ((interrupt_request & CPU_INTERRUPT_HARD) &&
+ (env->eflags & IF_MASK) &&
+ !(env->hflags & HF_INHIBIT_IRQ_MASK)) {
+ int intno;
+ intno = cpu_x86_get_pic_interrupt(env);
+ if (loglevel) {
+ fprintf(logfile, "Servicing hardware INT=0x%02x\n", intno);
+ }
+ do_interrupt(intno, 0, 0, 0, 1);
+ env->interrupt_request &= ~CPU_INTERRUPT_HARD;
+ /* ensure that no TB jump will be modified as
+ the program flow was changed */
+#ifdef __sparc__
+ tmp_T0 = 0;
+#else
+ T0 = 0;
+#endif
+ }
+#endif
+ if (interrupt_request & CPU_INTERRUPT_EXIT) {
+ env->interrupt_request &= ~CPU_INTERRUPT_EXIT;
+ env->exception_index = EXCP_INTERRUPT;
+ cpu_loop_exit();
+ }
}
#ifdef DEBUG_EXEC
if (loglevel) {
env->regs[R_EBP] = EBP;
env->regs[R_ESP] = ESP;
env->eflags = env->eflags | cc_table[CC_OP].compute_all() | (DF & DF_MASK);
- cpu_x86_dump_state(env, logfile, 0);
+ cpu_x86_dump_state(env, logfile, X86_DUMP_CCOP);
env->eflags &= ~(DF_MASK | CC_O | CC_S | CC_Z | CC_A | CC_P | CC_C);
#elif defined(TARGET_ARM)
+ env->cpsr = compute_cpsr();
cpu_arm_dump_state(env, logfile, 0);
+ env->cpsr &= ~0xf0000000;
+#elif defined(TARGET_SPARC)
+ cpu_sparc_dump_state (env, logfile, 0);
#else
#error unsupported target CPU
#endif
}
#endif
- /* we compute the CPU state. We assume it will not
- change during the whole generated block. */
+ /* we record a subset of the CPU state. It will
+ always be the same before a given translated block
+ is executed. */
#if defined(TARGET_I386)
- flags = (env->segs[R_CS].flags & DESC_B_MASK)
- >> (DESC_B_SHIFT - GEN_FLAG_CODE32_SHIFT);
- flags |= (env->segs[R_SS].flags & DESC_B_MASK)
- >> (DESC_B_SHIFT - GEN_FLAG_SS32_SHIFT);
- flags |= (((unsigned long)env->segs[R_DS].base |
- (unsigned long)env->segs[R_ES].base |
- (unsigned long)env->segs[R_SS].base) != 0) <<
- GEN_FLAG_ADDSEG_SHIFT;
- if (!(env->eflags & VM_MASK)) {
- flags |= (env->segs[R_CS].selector & 3) << GEN_FLAG_CPL_SHIFT;
- } else {
- /* NOTE: a dummy CPL is kept */
- flags |= (1 << GEN_FLAG_VM_SHIFT);
- flags |= (3 << GEN_FLAG_CPL_SHIFT);
- }
- flags |= (env->eflags & (IOPL_MASK | TF_MASK));
+ flags = env->hflags;
+ flags |= (env->eflags & (IOPL_MASK | TF_MASK | VM_MASK));
cs_base = env->segs[R_CS].base;
pc = cs_base + env->eip;
#elif defined(TARGET_ARM)
flags = 0;
cs_base = 0;
pc = (uint8_t *)env->regs[15];
+#elif defined(TARGET_SPARC)
+ flags = 0;
+ cs_base = 0;
+ if (env->npc) {
+ env->pc = env->npc;
+ env->npc = 0;
+ }
+ pc = (uint8_t *) env->pc;
#else
#error unsupported CPU
#endif
tb->tc_ptr = tc_ptr;
tb->cs_base = (unsigned long)cs_base;
tb->flags = flags;
- ret = cpu_gen_code(tb, CODE_GEN_MAX_SIZE, &code_gen_size);
-#if defined(TARGET_I386)
- /* XXX: suppress that, this is incorrect */
- /* 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);
- }
-#endif
+ /* XXX: an MMU exception can occur here */
+ cpu_gen_code(env, tb, CODE_GEN_MAX_SIZE, &code_gen_size);
*ptb = tb;
tb->hash_next = NULL;
tb_link(tb);
#ifdef __sparc__
T0 = tmp_T0;
#endif
- /* see if we can patch the calling TB. XXX: remove TF test */
-#ifndef RING0_HACKS
-
- if (T0 != 0
-#if defined(TARGET_I386)
- && !(env->eflags & TF_MASK)
-#endif
- ) {
+ /* see if we can patch the calling TB. */
+ if (T0 != 0) {
spin_lock(&tb_lock);
tb_add_jump((TranslationBlock *)(T0 & ~3), T0 & 3, tb);
spin_unlock(&tb_lock);
}
-#endif
tc_ptr = tb->tc_ptr;
-
+ env->current_tb = tb;
/* execute the generated code */
gen_func = (void *)tc_ptr;
#if defined(__sparc__)
: "r1", "r2", "r3", "r8", "r9", "r10", "r12", "r14");
#else
gen_func();
+#endif
+ env->current_tb = NULL;
+ /* reset soft MMU for next block (it can currently
+ only be set by a memory fault) */
+#if defined(TARGET_I386) && !defined(CONFIG_SOFTMMU)
+ if (env->hflags & HF_SOFTMMU_MASK) {
+ env->hflags &= ~HF_SOFTMMU_MASK;
+ /* do not allow linking to another block */
+ T0 = 0;
+ }
#endif
}
} else {
EDI = saved_EDI;
#endif
#elif defined(TARGET_ARM)
- {
- int ZF;
- ZF = (env->NZF == 0);
- env->cpsr = env->cpsr | (env->NZF & 0x80000000) | (ZF << 30) |
- (env->CF << 29) | ((env->VF & 0x80000000) >> 3);
- }
+ env->cpsr = compute_cpsr();
+#elif defined(TARGET_SPARC)
#else
#error unsupported target CPU
#endif
return ret;
}
-void cpu_interrupt(CPUState *s)
-{
- s->interrupt_request = 1;
-}
-
-
-#if defined(TARGET_I386)
+#if defined(TARGET_I386) && defined(CONFIG_USER_ONLY)
void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
{
saved_env = env;
env = s;
- if (env->eflags & VM_MASK) {
- SegmentCache *sc;
+ if (!(env->cr[0] & CR0_PE_MASK) || (env->eflags & VM_MASK)) {
selector &= 0xffff;
- sc = &env->segs[seg_reg];
- /* NOTE: in VM86 mode, limit and flags are never reloaded,
- so we must load them here */
- sc->base = (void *)(selector << 4);
- sc->limit = 0xffff;
- sc->flags = 0;
- sc->selector = selector;
+ cpu_x86_load_seg_cache(env, seg_reg, selector,
+ (uint8_t *)(selector << 4), 0xffff, 0);
} else {
load_seg(seg_reg, selector, 0);
}
{
TranslationBlock *tb;
int ret;
-
-#ifdef RING0_HACKS
- env = global_env; /* XXX: find a better solution */
-#endif
+
+ if (cpu_single_env)
+ env = cpu_single_env; /* XXX: find a correct solution for multithread */
#if defined(DEBUG_SIGNAL)
printf("qemu: SIGSEGV pc=0x%08lx address=%08lx w=%d oldset=0x%08lx\n",
pc, address, is_write, *(unsigned long *)old_set);
return 1;
}
/* see if it is an MMU fault */
- ret = cpu_x86_handle_mmu_fault(env, address, is_write);
+ ret = cpu_x86_handle_mmu_fault(env, address, is_write,
+ ((env->hflags & HF_CPL_MASK) == 3), 0);
if (ret < 0)
return 0; /* not an MMU fault */
if (ret == 0)
a virtual CPU fault */
cpu_restore_state(tb, env, pc);
}
+ if (ret == 1) {
#if 0
- printf("PF exception: EIP=0x%08x CR2=0x%08x error=0x%x\n",
- env->eip, env->cr[2], env->error_code);
+ printf("PF exception: EIP=0x%08x CR2=0x%08x error=0x%x\n",
+ env->eip, env->cr[2], env->error_code);
#endif
- /* we restore the process signal mask as the sigreturn should
- do it (XXX: use sigsetjmp) */
- sigprocmask(SIG_SETMASK, old_set, NULL);
- raise_exception_err(EXCP0E_PAGE, env->error_code);
+ /* we restore the process signal mask as the sigreturn should
+ do it (XXX: use sigsetjmp) */
+ sigprocmask(SIG_SETMASK, old_set, NULL);
+ raise_exception_err(EXCP0E_PAGE, env->error_code);
+ } else {
+ /* activate soft MMU for this block */
+ env->hflags |= HF_SOFTMMU_MASK;
+ sigprocmask(SIG_SETMASK, old_set, NULL);
+ cpu_loop_exit();
+ }
/* never comes here */
return 1;
}
/* XXX: do more */
return 0;
}
+#elif defined(TARGET_SPARC)
+static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
+ int is_write, sigset_t *old_set)
+{
+ return 0;
+}
#else
#error unsupported target CPU
#endif
&uc->uc_sigmask);
}
+#elif defined(__mc68000)
+
+int cpu_signal_handler(int host_signum, struct siginfo *info,
+ void *puc)
+{
+ struct ucontext *uc = puc;
+ unsigned long pc;
+ int is_write;
+
+ pc = uc->uc_mcontext.gregs[16];
+ /* XXX: compute is_write */
+ is_write = 0;
+ return handle_cpu_signal(pc, (unsigned long)info->si_addr,
+ is_write,
+ &uc->uc_sigmask);
+}
+
#else
#error host CPU specific signal handler needed