qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH 3/3] [x86] SYSENTER/SYSEXIT IA-32e implementation v2


From: Alexander Graf
Subject: [Qemu-devel] [PATCH 3/3] [x86] SYSENTER/SYSEXIT IA-32e implementation v2
Date: Mon, 18 Aug 2008 16:07:20 +0200
User-agent: Thunderbird 2.0.0.14 (X11/20080421)

On Intel CPUs, sysenter and sysexit are valid in 64-bit mode. This patch makes both 64-bit aware and enables them for Intel CPUs.

Changes since v1: Add cpu save/load for 64-bit wide sysenter variables

Signed-off-by: Alexander Graf <address@hidden>

diff --git a/qemu/target-i386/cpu.h b/qemu/target-i386/cpu.h
index 7e95900..3c84dc9 100644
--- a/qemu/target-i386/cpu.h
+++ b/qemu/target-i386/cpu.h
@@ -542,8 +555,8 @@ typedef struct CPUX86State {
 
     /* sysenter registers */
     uint32_t sysenter_cs;
-    uint32_t sysenter_esp;
-    uint32_t sysenter_eip;
+    target_ulong sysenter_esp;
+    target_ulong sysenter_eip;
     uint64_t efer;
     uint64_t star;
 
@@ -737,7 +750,7 @@ static inline int cpu_get_time_fast(void)
 #define cpu_signal_handler cpu_x86_signal_handler
 #define cpu_list x86_cpu_list
 
-#define CPU_SAVE_VERSION 6
+#define CPU_SAVE_VERSION 7
 
 /* MMU modes definitions */
 #define MMU_MODE0_SUFFIX _kernel
diff --git a/qemu/target-i386/helper.h b/qemu/target-i386/helper.h
index 8df6acc..ffe9ab6 100644
--- a/qemu/target-i386/helper.h
+++ b/qemu/target-i386/helper.h
@@ -55,7 +55,7 @@ DEF_HELPER(void, helper_enter_level, (int level, int data32, 
target_ulong t1))
 DEF_HELPER(void, helper_enter64_level, (int level, int data64, target_ulong 
t1))
 #endif
 DEF_HELPER(void, helper_sysenter, (void))
-DEF_HELPER(void, helper_sysexit, (void))
+DEF_HELPER(void, helper_sysexit, (int dflag))
 #ifdef TARGET_X86_64
 DEF_HELPER(void, helper_syscall, (int next_eip_addend))
 DEF_HELPER(void, helper_sysret, (int dflag))
diff --git a/qemu/target-i386/op_helper.c b/qemu/target-i386/op_helper.c
index 0b5fdc0..781c1d5 100644
--- a/qemu/target-i386/op_helper.c
+++ b/qemu/target-i386/op_helper.c
@@ -2878,11 +2915,23 @@ void helper_sysenter(void)
     }
     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,
-                           0, 0xffffffff,
-                           DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
-                           DESC_S_MASK |
-                           DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK);
+
+#ifdef TARGET_X86_64
+    if (env->hflags & HF_LMA_MASK) {
+        cpu_x86_load_seg_cache(env, R_CS, env->sysenter_cs & 0xfffc,
+                               0, 0xffffffff,
+                               DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
+                               DESC_S_MASK |
+                               DESC_CS_MASK | DESC_R_MASK | DESC_A_MASK | 
DESC_L_MASK);
+    } else
+#endif
+    {
+        cpu_x86_load_seg_cache(env, R_CS, env->sysenter_cs & 0xfffc,
+                               0, 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,
                            0, 0xffffffff,
                            DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
@@ -2892,7 +2941,7 @@ void helper_sysenter(void)
     EIP = env->sysenter_eip;
 }
 
-void helper_sysexit(void)
+void helper_sysexit(int dflag)
 {
     int cpl;
 
@@ -2901,16 +2950,32 @@ void helper_sysexit(void)
         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,
-                           0, 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,
-                           0, 0xffffffff,
-                           DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
-                           DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
-                           DESC_W_MASK | DESC_A_MASK);
+#ifdef TARGET_X86_64
+    if (dflag == 2) {
+        cpu_x86_load_seg_cache(env, R_CS, ((env->sysenter_cs + 32) & 0xfffc) | 
3,
+                               0, 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 | 
DESC_L_MASK);
+        cpu_x86_load_seg_cache(env, R_SS, ((env->sysenter_cs + 40) & 0xfffc) | 
3,
+                               0, 0xffffffff,
+                               DESC_G_MASK | DESC_B_MASK | DESC_P_MASK |
+                               DESC_S_MASK | (3 << DESC_DPL_SHIFT) |
+                               DESC_W_MASK | DESC_A_MASK);
+    } else
+#endif
+    {
+        cpu_x86_load_seg_cache(env, R_CS, ((env->sysenter_cs + 16) & 0xfffc) | 
3,
+                               0, 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,
+                               0, 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;
 #ifdef USE_KQEMU
diff --git a/qemu/target-i386/translate.c b/qemu/target-i386/translate.c
index c4a1195..cf7347e 100644
--- a/qemu/target-i386/translate.c
+++ b/qemu/target-i386/translate.c
@@ -6401,7 +6401,8 @@ static target_ulong disas_insn(DisasContext *s, 
target_ulong pc_start)
         tcg_gen_helper_0_0(helper_rdpmc);
         break;
     case 0x134: /* sysenter */
-        if (CODE64(s))
+        /* For Intel SYSENTER is valid on 64-bit */
+        if (CODE64(s) && cpu_single_env->cpuid_vendor1 != CPUID_VENDOR_INTEL_1)
             goto illegal_op;
         if (!s->pe) {
             gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
@@ -6416,7 +6417,8 @@ static target_ulong disas_insn(DisasContext *s, 
target_ulong pc_start)
         }
         break;
     case 0x135: /* sysexit */
-        if (CODE64(s))
+        /* For Intel SYSEXIT is valid on 64-bit */
+        if (CODE64(s) && cpu_single_env->cpuid_vendor1 != CPUID_VENDOR_INTEL_1)
             goto illegal_op;
         if (!s->pe) {
             gen_exception(s, EXCP0D_GPF, pc_start - s->cs_base);
@@ -6426,7 +6428,7 @@ static target_ulong disas_insn(DisasContext *s, 
target_ulong pc_start)
                 s->cc_op = CC_OP_DYNAMIC;
             }
             gen_jmp_im(pc_start - s->cs_base);
-            tcg_gen_helper_0_0(helper_sysexit);
+            tcg_gen_helper_0_1(helper_sysexit, tcg_const_i32(dflag));
             gen_eob(s);
         }
         break;
diff --git a/qemu/target-i386/machine.c b/qemu/target-i386/machine.c
index a3da01a..1367fd5 100644
--- a/qemu/target-i386/machine.c
+++ b/qemu/target-i386/machine.c
@@ -94,9 +94,9 @@ void cpu_save(QEMUFile *f, void *opaque)
     cpu_put_seg(f, &env->gdt);
     cpu_put_seg(f, &env->idt);
 
-    qemu_put_be32s(f, &env->sysenter_cs);
-    qemu_put_be32s(f, &env->sysenter_esp);
-    qemu_put_be32s(f, &env->sysenter_eip);
+    qemu_put_bels(f, &env->sysenter_cs);
+    qemu_put_bels(f, &env->sysenter_esp);
+    qemu_put_bels(f, &env->sysenter_eip);
 
     qemu_put_betls(f, &env->cr[0]);
     qemu_put_betls(f, &env->cr[2]);
@@ -182,7 +182,7 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
     int32_t a20_mask;
 
     if (version_id != 3 && version_id != 4 && version_id != 5
-        && version_id != 6)
+        && version_id != 6 && version_id != 7)
         return -EINVAL;
     for(i = 0; i < CPU_NB_REGS; i++)
         qemu_get_betls(f, &env->regs[i]);
@@ -257,8 +257,13 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id)
     cpu_get_seg(f, &env->idt);
 
     qemu_get_be32s(f, &env->sysenter_cs);
-    qemu_get_be32s(f, &env->sysenter_esp);
-    qemu_get_be32s(f, &env->sysenter_eip);
+    if (version_id >= 7) {
+        qemu_get_bels(f, &env->sysenter_esp);
+        qemu_get_bels(f, &env->sysenter_eip);
+    } else {
+        qemu_get_be32s(f, &env->sysenter_esp);
+        qemu_get_be32s(f, &env->sysenter_eip);
+    }
 
     qemu_get_betls(f, &env->cr[0]);
     qemu_get_betls(f, &env->cr[2]);

reply via email to

[Prev in Thread] Current Thread [Next in Thread]