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
This commit is contained in:
bellard 2004-05-29 11:08:52 +00:00
parent f66723fab9
commit 023fe10d24
4 changed files with 87 additions and 0 deletions

View file

@ -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);

View file

@ -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) {

View file

@ -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();

View file

@ -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;