hardware interrupt support - support forfull ring 0 exception simulation

git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@260 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
bellard 2003-06-24 13:22:59 +00:00
parent f76af4b3f3
commit 3fb2ded1d5
1 changed files with 202 additions and 138 deletions

View File

@ -29,6 +29,8 @@
//#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)
/* XXX: unify with i386 target */
@ -140,9 +142,51 @@ int cpu_exec(CPUState *env1)
#error unsupported target CPU
#endif
env->interrupt_request = 0;
env->exception_index = -1;
/* prepare setjmp context for exception handling */
for(;;) {
if (setjmp(env->jmp_env) == 0) {
/* if an exception is pending, we execute it here */
if (env->exception_index >= 0) {
if (env->exception_index >= EXCP_INTERRUPT) {
/* exit request from the cpu execution loop */
ret = env->exception_index;
break;
} else if (env->user_mode_only) {
/* if user mode only, we simulate a fake exception
which will be hanlded outside the cpu execution
loop */
do_interrupt_user(env->exception_index,
env->exception_is_int,
env->error_code,
env->exception_next_eip);
ret = env->exception_index;
break;
} else {
/* 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_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__
@ -178,8 +222,10 @@ int cpu_exec(CPUState *env1)
/* we compute the CPU state. We assume it will not
change during the whole generated block. */
#if defined(TARGET_I386)
flags = env->segs[R_CS].seg_32bit << GEN_FLAG_CODE32_SHIFT;
flags |= env->segs[R_SS].seg_32bit << GEN_FLAG_SS32_SHIFT;
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) <<
@ -248,6 +294,8 @@ int cpu_exec(CPUState *env1)
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)
@ -257,6 +305,7 @@ int cpu_exec(CPUState *env1)
tb_add_jump((TranslationBlock *)(T0 & ~3), T0 & 3, tb);
spin_unlock(&tb_lock);
}
#endif
tc_ptr = tb->tc_ptr;
/* execute the generated code */
@ -278,8 +327,10 @@ int cpu_exec(CPUState *env1)
gen_func();
#endif
}
} else {
}
ret = env->exception_index;
} /* for(;;) */
#if defined(TARGET_I386)
/* restore flags in standard format */
@ -348,11 +399,11 @@ void cpu_x86_load_seg(CPUX86State *s, int seg_reg, int selector)
SegmentCache *sc;
selector &= 0xffff;
sc = &env->segs[seg_reg];
/* NOTE: in VM86 mode, limit and seg_32bit are never reloaded,
/* 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->seg_32bit = 0;
sc->flags = 0;
sc->selector = selector;
} else {
load_seg(seg_reg, selector, 0);
@ -398,6 +449,8 @@ void cpu_x86_frstor(CPUX86State *s, uint8_t *ptr, int data32)
#include <signal.h>
#include <sys/ucontext.h>
#if defined(TARGET_I386)
/* 'pc' is the host PC at which the exception was raised. 'address' is
the effective address of the memory exception. 'is_write' is 1 if a
write caused the exception and otherwise 0'. 'old_set' is the
@ -407,42 +460,53 @@ static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
{
TranslationBlock *tb;
int ret;
uint32_t found_pc;
#ifdef RING0_HACKS
env = global_env; /* XXX: find a better solution */
#endif
#if defined(DEBUG_SIGNAL)
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",
pc, address, is_write, *(unsigned long *)old_set);
#endif
/* XXX: locking issue */
if (is_write && page_unprotect(address)) {
return 1;
}
/* see if it is an MMU fault */
ret = cpu_x86_handle_mmu_fault(env, address, is_write);
if (ret < 0)
return 0; /* not an MMU fault */
if (ret == 0)
return 1; /* the MMU fault was handled without causing real CPU fault */
/* now we have a real cpu fault */
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_search_pc(tb, &found_pc, pc);
if (ret < 0)
return 0;
#if defined(TARGET_I386)
env->eip = found_pc - tb->cs_base;
env->cr[2] = address;
cpu_restore_state(tb, env, pc);
}
#if 0
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, 4 | (is_write << 1));
raise_exception_err(EXCP0E_PAGE, env->error_code);
/* never comes here */
return 1;
}
#elif defined(TARGET_ARM)
env->regs[15] = found_pc;
static inline int handle_cpu_signal(unsigned long pc, unsigned long address,
int is_write, sigset_t *old_set)
{
/* XXX: do more */
return 0;
}
#else
#error unsupported target CPU
#endif
/* never comes here */
return 1;
} else {
return 0;
}
}
#if defined(__i386__)
@ -570,6 +634,6 @@ int cpu_signal_handler(int host_signum, struct siginfo *info,
#else
#error CPU specific signal handler needed
#error host CPU specific signal handler needed
#endif