diff options
author | bellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162> | 2004-05-29 11:08:52 +0000 |
---|---|---|
committer | bellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162> | 2004-05-29 11:08:52 +0000 |
commit | 023fe10d24acd124d0b7c5c5ac8edd41d6cc08f2 (patch) | |
tree | a8916df0fb3521f53aedf8e695ef312d0c2e7f13 | |
parent | f66723fab9eab2695a1b3cf15b55ffc2936b6418 (diff) | |
download | hqemu-023fe10d24acd124d0b7c5c5ac8edd41d6cc08f2.zip hqemu-023fe10d24acd124d0b7c5c5ac8edd41d6cc08f2.tar.gz |
fnop FPU exception support (aka FreeBSD FPU probe) - sysenter/sysexit support (untested, not enabled in cpuid)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@869 c046a42c-6fe2-441c-8c8c-71466251a162
-rw-r--r-- | target-i386/exec.h | 2 | ||||
-rw-r--r-- | target-i386/helper.c | 44 | ||||
-rw-r--r-- | target-i386/op.c | 10 | ||||
-rw-r--r-- | target-i386/translate.c | 31 |
4 files changed, 87 insertions, 0 deletions
diff --git a/target-i386/exec.h b/target-i386/exec.h index f5b03fb..4410069 100644 --- a/target-i386/exec.h +++ b/target-i386/exec.h @@ -167,6 +167,8 @@ void helper_divl_EAX_T0(uint32_t eip); void helper_idivl_EAX_T0(uint32_t eip); void helper_cmpxchg8b(void); void helper_cpuid(void); +void helper_sysenter(void); +void helper_sysexit(void); void helper_rdtsc(void); void helper_rdmsr(void); void helper_wrmsr(void); diff --git a/target-i386/helper.c b/target-i386/helper.c index 5782bab..9a88275 100644 --- a/target-i386/helper.c +++ b/target-i386/helper.c @@ -1746,6 +1746,50 @@ void helper_lret_protected(int shift, int addend) helper_ret_protected(shift, 0, addend); } +void helper_sysenter(void) +{ + if (env->sysenter_cs == 0) { + raise_exception_err(EXCP0D_GPF, 0); + } + env->eflags &= ~(VM_MASK | IF_MASK | RF_MASK); + cpu_x86_set_cpl(env, 0); + cpu_x86_load_seg_cache(env, R_CS, env->sysenter_cs & 0xfffc, + NULL, 0xffffffff, + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | + DESC_S_MASK | + DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK); + cpu_x86_load_seg_cache(env, R_SS, (env->sysenter_cs + 8) & 0xfffc, + NULL, 0xffffffff, + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | + DESC_S_MASK | + DESC_W_MASK | DESC_A_MASK); + ESP = env->sysenter_esp; + EIP = env->sysenter_eip; +} + +void helper_sysexit(void) +{ + int cpl; + + cpl = env->hflags & HF_CPL_MASK; + if (env->sysenter_cs == 0 || cpl != 0) { + raise_exception_err(EXCP0D_GPF, 0); + } + cpu_x86_set_cpl(env, 3); + cpu_x86_load_seg_cache(env, R_CS, ((env->sysenter_cs + 16) & 0xfffc) | 3, + NULL, 0xffffffff, + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | + DESC_S_MASK | (3 << DESC_DPL_SHIFT) | + DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK); + cpu_x86_load_seg_cache(env, R_SS, ((env->sysenter_cs + 24) & 0xfffc) | 3, + NULL, 0xffffffff, + DESC_G_MASK | DESC_B_MASK | DESC_P_MASK | + DESC_S_MASK | (3 << DESC_DPL_SHIFT) | + DESC_W_MASK | DESC_A_MASK); + ESP = ECX; + EIP = EDX; +} + void helper_movl_crN_T0(int reg) { switch(reg) { diff --git a/target-i386/op.c b/target-i386/op.c index fad8a73..3f9afb1 100644 --- a/target-i386/op.c +++ b/target-i386/op.c @@ -700,6 +700,16 @@ void OPPROTO op_cpuid(void) helper_cpuid(); } +void OPPROTO op_sysenter(void) +{ + helper_sysenter(); +} + +void OPPROTO op_sysexit(void) +{ + helper_sysexit(); +} + void OPPROTO op_rdmsr(void) { helper_rdmsr(); diff --git a/target-i386/translate.c b/target-i386/translate.c index 514399d..ee4f05a 100644 --- a/target-i386/translate.c +++ b/target-i386/translate.c @@ -2973,6 +2973,11 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) case 0x0a: /* grp d9/2 */ switch(rm) { case 0: /* fnop */ + /* check exceptions (FreeBSD FPU probe) */ + if (s->cc_op != CC_OP_DYNAMIC) + gen_op_set_cc_op(s->cc_op); + gen_op_jmp_im(pc_start - s->cs_base); + gen_op_fwait(); break; default: goto illegal_op; @@ -3881,6 +3886,32 @@ static uint8_t *disas_insn(DisasContext *s, uint8_t *pc_start) case 0x131: /* rdtsc */ gen_op_rdtsc(); break; + case 0x134: /* sysenter */ + if (!s->pe) { + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + } else { + if (s->cc_op != CC_OP_DYNAMIC) { + gen_op_set_cc_op(s->cc_op); + s->cc_op = CC_OP_DYNAMIC; + } + gen_op_jmp_im(pc_start - s->cs_base); + gen_op_sysenter(); + gen_eob(s); + } + break; + case 0x135: /* sysexit */ + if (!s->pe) { + gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base); + } else { + if (s->cc_op != CC_OP_DYNAMIC) { + gen_op_set_cc_op(s->cc_op); + s->cc_op = CC_OP_DYNAMIC; + } + gen_op_jmp_im(pc_start - s->cs_base); + gen_op_sysexit(); + gen_eob(s); + } + break; case 0x1a2: /* cpuid */ gen_op_cpuid(); break; |