Skip to contentSkip to conversation

SYSENTER/SYSEXIT IA-32e implementation v2

PATCH New Alexander Graf 1 participant 1 message Aug 18, 2008

lore
Share & tools
lore
#0 lore raw

PATCH 3/3 SYSENTER/SYSEXIT IA-32e implementation v2

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

qemu/target-i386/cpu.h +3 -3
index 7e95900..3c84dc9 100644
@@ -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
qemu/target-i386/helper.h +1 -1
index 8df6acc..ffe9ab6 100644
@@ -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))
qemu/target-i386/op_helper.c +44 -16

78 lines not on this page · raw message

qemu/target-i386/translate.c +5 -3
index c4a1195..cf7347e 100644
@@ -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;
qemu/target-i386/machine.c +11 -6
index a3da01a..1367fd5 100644
@@ -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]);