KVM: x86: Use "is Intel compatible" helper to emulate SYSCALL in !64-bit
authorSean Christopherson <seanjc@google.com>
Fri, 5 Apr 2024 23:55:59 +0000 (16:55 -0700)
committerSean Christopherson <seanjc@google.com>
Mon, 10 Jun 2024 21:29:38 +0000 (14:29 -0700)
Use guest_cpuid_is_intel_compatible() to determine whether SYSCALL in
32-bit Protected Mode (including Compatibility Mode) should #UD or succeed.
The existing code already does the exact equivalent of
guest_cpuid_is_intel_compatible(), just in a rather roundabout way.

No functional change intended.

Link: https://lore.kernel.org/r/20240405235603.1173076-7-seanjc@google.com
Signed-off-by: Sean Christopherson <seanjc@google.com>
arch/x86/kvm/emulate.c
arch/x86/kvm/kvm_emulate.h
arch/x86/kvm/x86.c

index 5d4c86133453d88dbb4f1b5f34d04bde7ec45a55..1fb73d96bdf0c10a6861e1c8b311745afba4a1b3 100644 (file)
@@ -2363,41 +2363,6 @@ static bool vendor_intel(struct x86_emulate_ctxt *ctxt)
        return is_guest_vendor_intel(ebx, ecx, edx);
 }
 
-static bool em_syscall_is_enabled(struct x86_emulate_ctxt *ctxt)
-{
-       const struct x86_emulate_ops *ops = ctxt->ops;
-       u32 eax, ebx, ecx, edx;
-
-       /*
-        * syscall should always be enabled in longmode - so only become
-        * vendor specific (cpuid) if other modes are active...
-        */
-       if (ctxt->mode == X86EMUL_MODE_PROT64)
-               return true;
-
-       eax = 0x00000000;
-       ecx = 0x00000000;
-       ops->get_cpuid(ctxt, &eax, &ebx, &ecx, &edx, true);
-       /*
-        * remark: Intel CPUs only support "syscall" in 64bit longmode. Also a
-        * 64bit guest with a 32bit compat-app running will #UD !! While this
-        * behaviour can be fixed (by emulating) into AMD response - CPUs of
-        * AMD can't behave like Intel.
-        */
-       if (is_guest_vendor_intel(ebx, ecx, edx))
-               return false;
-
-       if (is_guest_vendor_amd(ebx, ecx, edx) ||
-           is_guest_vendor_hygon(ebx, ecx, edx))
-               return true;
-
-       /*
-        * default: (not Intel, not AMD, not Hygon), apply Intel's
-        * stricter rules...
-        */
-       return false;
-}
-
 static int em_syscall(struct x86_emulate_ctxt *ctxt)
 {
        const struct x86_emulate_ops *ops = ctxt->ops;
@@ -2411,7 +2376,15 @@ static int em_syscall(struct x86_emulate_ctxt *ctxt)
            ctxt->mode == X86EMUL_MODE_VM86)
                return emulate_ud(ctxt);
 
-       if (!(em_syscall_is_enabled(ctxt)))
+       /*
+        * Intel compatible CPUs only support SYSCALL in 64-bit mode, whereas
+        * AMD allows SYSCALL in any flavor of protected mode.  Note, it's
+        * infeasible to emulate Intel behavior when running on AMD hardware,
+        * as SYSCALL won't fault in the "wrong" mode, i.e. there is no #UD
+        * for KVM to trap-and-emulate, unlike emulating AMD on Intel.
+        */
+       if (ctxt->mode != X86EMUL_MODE_PROT64 &&
+           ctxt->ops->guest_cpuid_is_intel_compatible(ctxt))
                return emulate_ud(ctxt);
 
        ops->get_msr(ctxt, MSR_EFER, &efer);
index 29ea4313e1bb1eea7df2639e8379140c77bb1292..55a18e2f2dcd999cc4b150f899e25fac73e3f963 100644 (file)
@@ -223,6 +223,7 @@ struct x86_emulate_ops {
        bool (*guest_has_movbe)(struct x86_emulate_ctxt *ctxt);
        bool (*guest_has_fxsr)(struct x86_emulate_ctxt *ctxt);
        bool (*guest_has_rdpid)(struct x86_emulate_ctxt *ctxt);
+       bool (*guest_cpuid_is_intel_compatible)(struct x86_emulate_ctxt *ctxt);
 
        void (*set_nmi_mask)(struct x86_emulate_ctxt *ctxt, bool masked);
 
index 461fba9aeaf3b76ecfc10d26006ba06991fcc04f..bfe3dba56e247b2e2d4ed1b8952c5e37896ba6cb 100644 (file)
@@ -8549,6 +8549,11 @@ static bool emulator_guest_has_rdpid(struct x86_emulate_ctxt *ctxt)
        return guest_cpuid_has(emul_to_vcpu(ctxt), X86_FEATURE_RDPID);
 }
 
+static bool emulator_guest_cpuid_is_intel_compatible(struct x86_emulate_ctxt *ctxt)
+{
+       return guest_cpuid_is_intel_compatible(emul_to_vcpu(ctxt));
+}
+
 static ulong emulator_read_gpr(struct x86_emulate_ctxt *ctxt, unsigned reg)
 {
        return kvm_register_read_raw(emul_to_vcpu(ctxt), reg);
@@ -8647,6 +8652,7 @@ static const struct x86_emulate_ops emulate_ops = {
        .guest_has_movbe     = emulator_guest_has_movbe,
        .guest_has_fxsr      = emulator_guest_has_fxsr,
        .guest_has_rdpid     = emulator_guest_has_rdpid,
+       .guest_cpuid_is_intel_compatible = emulator_guest_cpuid_is_intel_compatible,
        .set_nmi_mask        = emulator_set_nmi_mask,
        .is_smm              = emulator_is_smm,
        .is_guest_mode       = emulator_is_guest_mode,