Skip to contentSkip to conversation

SYSENTER/SYSEXIT IA-32e implementation v4

PATCH In review Alexander Graf 1 participant 1 message Aug 22, 2008

lore
Share & tools
lore
#0 lore raw

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

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 Changes since v3: Use betls instead of bels

target-i386/cpu.h +3 -3
Index: qemu/target-i386/cpu.h
===================================================================
@@ -549,8 +549,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 +737,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
target-i386/helper.h +1 -1
Index: qemu/target-i386/helper.h
===================================================================
@@ -55,7 +55,7 @@ DEF_HELPER(void, helper_enter_level, (in
 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))
target-i386/op_helper.c +44 -16

78 lines not on this page · raw message

target-i386/translate.c +5 -3
Index: qemu/target-i386/translate.c
===================================================================
@@ -6401,7 +6401,8 @@ static target_ulong disas_insn(DisasCont
         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(DisasCont
         }
         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(DisasCont
                 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;
target-i386/machine.c +11 -6
Index: qemu/target-i386/machine.c
===================================================================
@@ -88,9 +88,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_betls(f, &env->sysenter_cs);
+    qemu_put_betls(f, &env->sysenter_esp);
+    qemu_put_betls(f, &env->sysenter_eip);
 
     qemu_put_betls(f, &env->cr[0]);
     qemu_put_betls(f, &env->cr[2]);
@@ -169,7 +169,7 @@ int cpu_load(QEMUFile *f, void *opaque,
     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]);
@@ -244,8 +244,13 @@ int cpu_load(QEMUFile *f, void *opaque,
     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_betls(f, &env->sysenter_esp);
+        qemu_get_betls(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]);