fnop FPU exception support (aka FreeBSD FPU probe) - sysenter/sysexit support (untest...
authorbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>
Sat, 29 May 2004 11:08:52 +0000 (11:08 +0000)
committerbellard <bellard@c046a42c-6fe2-441c-8c8c-71466251a162>
Sat, 29 May 2004 11:08:52 +0000 (11:08 +0000)
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@869 c046a42c-6fe2-441c-8c8c-71466251a162

target-i386/exec.h
target-i386/helper.c
target-i386/op.c
target-i386/translate.c

index f5b03fb..4410069 100644 (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);
index 5782bab..9a88275 100644 (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) {
index fad8a73..3f9afb1 100644 (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();
index 514399d..ee4f05a 100644 (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;