KVM: x86 emulator: reject SYSENTER in compatibility mode on AMD guests
authorAvi Kivity <avi@redhat.com>
Wed, 1 Feb 2012 10:23:21 +0000 (12:23 +0200)
committerAvi Kivity <avi@redhat.com>
Mon, 5 Mar 2012 12:57:20 +0000 (14:57 +0200)
If the guest thinks it's an AMD, it will not have prepared the SYSENTER MSRs,
and if the guest executes SYSENTER in compatibility mode, it will fails.

Detect this condition and #UD instead, like the spec says.

Signed-off-by: Avi Kivity <avi@redhat.com>
arch/x86/kvm/emulate.c

index 6eaedac..71450ac 100644 (file)
@@ -1892,6 +1892,17 @@ setup_syscalls_segments(struct x86_emulate_ctxt *ctxt,
        ss->p = 1;
 }
 
+static bool vendor_intel(struct x86_emulate_ctxt *ctxt)
+{
+       u32 eax, ebx, ecx, edx;
+
+       eax = ecx = 0;
+       return ctxt->ops->get_cpuid(ctxt, &eax, &ebx, &ecx, &edx)
+               && ebx == X86EMUL_CPUID_VENDOR_GenuineIntel_ebx
+               && ecx == X86EMUL_CPUID_VENDOR_GenuineIntel_ecx
+               && edx == X86EMUL_CPUID_VENDOR_GenuineIntel_edx;
+}
+
 static bool em_syscall_is_enabled(struct x86_emulate_ctxt *ctxt)
 {
        struct x86_emulate_ops *ops = ctxt->ops;
@@ -2008,6 +2019,14 @@ static int em_sysenter(struct x86_emulate_ctxt *ctxt)
        if (ctxt->mode == X86EMUL_MODE_REAL)
                return emulate_gp(ctxt, 0);
 
+       /*
+        * Not recognized on AMD in compat mode (but is recognized in legacy
+        * mode).
+        */
+       if ((ctxt->mode == X86EMUL_MODE_PROT32) && (efer & EFER_LMA)
+           && !vendor_intel(ctxt))
+               return emulate_ud(ctxt);
+
        /* XXX sysenter/sysexit have not been tested in 64bit mode.
        * Therefore, we inject an #UD.
        */