2024-04-05 23:57:05

by Sean Christopherson

[permalink] [raw]
Subject: [PATCH 00/10] KVM: x86: Fix LVTPC masking on AMD CPUs

This is kinda sorta v2 of Sandipan's fix for KVM's incorrect setting of
the MASK bit when delivering PMIs through the LVTPC.

It's a bit rushed, as I want to get Sandipan's fix applied early next
week so that it can make its way to Linus' tree for -rc4. And I didn't
want to apply Sandipan's patch as-is, because I'm a little paranoid that
the guest CPUID check could be noticeable slow, and it's easy to avoid.

My plan is to grab patches 1-2 for 6.9 asap, and let the rest simmer for
much, much longer (they are *very* lightly tested).

As for why this looks wildy different than Sandipan's compat_vendor idea,
when I started looking at KVM's various AMD vs. Intel checks, I realized
it makes no sense to support an "unknown" vendor. KVM can't do *nothing*,
and so practically speaking, an "unknown" vendor vCPU would actually end
up with a weird mix of AMD *and* Intel behavior, not AMD *or* Intel
behavior.

Sandipan Das (1):
KVM: x86/pmu: Do not mask LVTPC when handling a PMI on AMD platforms

Sean Christopherson (9):
KVM: x86: Snapshot if a vCPU's vendor model is AMD vs. Intel
compatible
KVM: x86/pmu: Squash period for checkpointed events based on host
HLE/RTM
KVM: x86: Apply Intel's TSC_AUX reserved-bit behavior to Intel compat
vCPUs
KVM: x86: Inhibit code #DBs in MOV-SS shadow for all Intel compat
vCPUs
KVM: x86: Use "is Intel compatible" helper to emulate SYSCALL in
!64-bit
KVM: SVM: Emulate SYSENTER RIP/RSP behavior for all Intel compat vCPUs
KVM: x86: Allow SYSENTER in Compatibility Mode for all Intel compat
vCPUs
KVM: x86: Open code vendor_intel() in string_registers_quirk()
KVM: x86: Bury guest_cpuid_is_amd_or_hygon() in cpuid.c

arch/x86/include/asm/kvm_host.h | 1 +
arch/x86/kvm/cpuid.c | 13 ++++++
arch/x86/kvm/cpuid.h | 16 ++------
arch/x86/kvm/emulate.c | 71 ++++++++++-----------------------
arch/x86/kvm/kvm_emulate.h | 1 +
arch/x86/kvm/lapic.c | 3 +-
arch/x86/kvm/mmu/mmu.c | 2 +-
arch/x86/kvm/pmu.c | 2 +-
arch/x86/kvm/svm/svm.c | 14 +++----
arch/x86/kvm/x86.c | 30 ++++++++------
10 files changed, 68 insertions(+), 85 deletions(-)


base-commit: 8cb4a9a82b21623dbb4b3051dd30d98356cf95bc
--
2.44.0.478.gd926399ef9-goog



2024-04-05 23:57:08

by Sean Christopherson

[permalink] [raw]
Subject: [PATCH 03/10] KVM: x86/pmu: Squash period for checkpointed events based on host HLE/RTM

Zero out the sampling period for checkpointed events if the host supports
HLE or RTM, i.e. supports transactions and thus checkpointed events, not
based on whether the vCPU vendor model is Intel. Perf's refusal to allow
a sample period for checkpointed events is based purely on whether or not
the CPU supports HLE/RTM transactions, i.e. perf has no knowledge of the
vCPU vendor model.

Note, it is _extremely_ unlikely that the existing code is a problem in
real world usage, as there are far, far bigger hurdles that would need to
be cleared to support cross-vendor vPMUs. The motivation is mainly to
eliminate the use of guest_cpuid_is_intel(), in order to get to a state
where KVM pivots on AMD vs. Intel compatibility, i.e. doesn't check for
exactly vendor==Intel except in rare circumstances (i.e. for CPU quirks).

Cc: Like Xu <[email protected]>
Signed-off-by: Sean Christopherson <[email protected]>
---
arch/x86/kvm/pmu.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/x86/kvm/pmu.c b/arch/x86/kvm/pmu.c
index c397b28e3d1b..8c3564917953 100644
--- a/arch/x86/kvm/pmu.c
+++ b/arch/x86/kvm/pmu.c
@@ -194,7 +194,7 @@ static int pmc_reprogram_counter(struct kvm_pmc *pmc, u32 type, u64 config,
attr.sample_period = get_sample_period(pmc, pmc->counter);

if ((attr.config & HSW_IN_TX_CHECKPOINTED) &&
- guest_cpuid_is_intel(pmc->vcpu)) {
+ (boot_cpu_has(X86_FEATURE_RTM) || boot_cpu_has(X86_FEATURE_HLE))) {
/*
* HSW_IN_TX_CHECKPOINTED is not supported with nonzero
* period. Just clear the sample period so at least
--
2.44.0.478.gd926399ef9-goog


2024-04-05 23:57:26

by Sean Christopherson

[permalink] [raw]
Subject: [PATCH 04/10] KVM: x86: Apply Intel's TSC_AUX reserved-bit behavior to Intel compat vCPUs

Extend Intel's check on MSR_TSC_AUX[63:32] to all vCPU models that are
Intel compatible, i.e. aren't AMD or Hygon in KVM's world, as the behavior
is architectural, i.e. applies to any CPU that is compatible with Intel's
architecture. Applying the behavior strictly to Intel wasn't intentional,
KVM simply didn't have a concept of "Intel compatible" as of commit
61a05d444d2c ("KVM: x86: Tie Intel and AMD behavior for MSR_TSC_AUX to
guest CPU model").

Signed-off-by: Sean Christopherson <[email protected]>
---
arch/x86/kvm/x86.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index ebcc12d1e1de..d9719141502a 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -1883,11 +1883,11 @@ static int __kvm_set_msr(struct kvm_vcpu *vcpu, u32 index, u64 data,
* incomplete and conflicting architectural behavior. Current
* AMD CPUs completely ignore bits 63:32, i.e. they aren't
* reserved and always read as zeros. Enforce Intel's reserved
- * bits check if and only if the guest CPU is Intel, and clear
- * the bits in all other cases. This ensures cross-vendor
- * migration will provide consistent behavior for the guest.
+ * bits check if the guest CPU is Intel compatible, otherwise
+ * clear the bits. This ensures cross-vendor migration will
+ * provide consistent behavior for the guest.
*/
- if (guest_cpuid_is_intel(vcpu) && (data >> 32) != 0)
+ if (guest_cpuid_is_intel_compatible(vcpu) && (data >> 32) != 0)
return 1;

data = (u32)data;
--
2.44.0.478.gd926399ef9-goog


2024-04-05 23:57:43

by Sean Christopherson

[permalink] [raw]
Subject: [PATCH 05/10] KVM: x86: Inhibit code #DBs in MOV-SS shadow for all Intel compat vCPUs

Treat code #DBs as inhibited in MOV/POP-SS shadows for vCPU models that
are Intel compatible, not just strictly vCPUs with vendor==Intel. The
behavior is explicitly called out in the SDM, and thus architectural, i.e.
applies to all CPUs that implement Intel's architecture, and isn't a quirk
that is unique to CPUs manufactured by Intel:

However, if an instruction breakpoint is placed on an instruction located
immediately after a POP SS/MOV SS instruction, the breakpoint will be
suppressed as if EFLAGS.RF were 1.

Applying the behavior strictly to Intel wasn't intentional, KVM simply
didn't have a concept of "Intel compatible" as of commit baf67ca8e545
("KVM: x86: Suppress code #DBs on Intel if MOV/POP SS blocking is active").

Signed-off-by: Sean Christopherson <[email protected]>
---
arch/x86/kvm/x86.c | 14 ++++++--------
1 file changed, 6 insertions(+), 8 deletions(-)

diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index d9719141502a..8ea6f4fc910f 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -8984,19 +8984,17 @@ EXPORT_SYMBOL_GPL(kvm_skip_emulated_instruction);

static bool kvm_is_code_breakpoint_inhibited(struct kvm_vcpu *vcpu)
{
- u32 shadow;
-
if (kvm_get_rflags(vcpu) & X86_EFLAGS_RF)
return true;

/*
- * Intel CPUs inhibit code #DBs when MOV/POP SS blocking is active,
- * but AMD CPUs do not. MOV/POP SS blocking is rare, check that first
- * to avoid the relatively expensive CPUID lookup.
+ * Intel compatible CPUs inhibit code #DBs when MOV/POP SS blocking is
+ * active, but AMD compatible CPUs do not.
*/
- shadow = static_call(kvm_x86_get_interrupt_shadow)(vcpu);
- return (shadow & KVM_X86_SHADOW_INT_MOV_SS) &&
- guest_cpuid_is_intel(vcpu);
+ if (!guest_cpuid_is_intel_compatible(vcpu))
+ return false;
+
+ return static_call(kvm_x86_get_interrupt_shadow)(vcpu) & KVM_X86_SHADOW_INT_MOV_SS;
}

static bool kvm_vcpu_check_code_breakpoint(struct kvm_vcpu *vcpu,
--
2.44.0.478.gd926399ef9-goog


2024-04-05 23:58:08

by Sean Christopherson

[permalink] [raw]
Subject: [PATCH 06/10] KVM: x86: Use "is Intel compatible" helper to emulate SYSCALL in !64-bit

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.

Signed-off-by: Sean Christopherson <[email protected]>
---
arch/x86/kvm/emulate.c | 45 ++++++++------------------------------
arch/x86/kvm/kvm_emulate.h | 1 +
arch/x86/kvm/x86.c | 6 +++++
3 files changed, 16 insertions(+), 36 deletions(-)

diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 5d4c86133453..1fb73d96bdf0 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -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);
diff --git a/arch/x86/kvm/kvm_emulate.h b/arch/x86/kvm/kvm_emulate.h
index 5382646162a3..0f71d4699b78 100644
--- a/arch/x86/kvm/kvm_emulate.h
+++ b/arch/x86/kvm/kvm_emulate.h
@@ -222,6 +222,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);

diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 8ea6f4fc910f..ac607b41890e 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -8505,6 +8505,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);
@@ -8603,6 +8608,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,
--
2.44.0.478.gd926399ef9-goog


2024-04-05 23:58:15

by Sean Christopherson

[permalink] [raw]
Subject: [PATCH 07/10] KVM: SVM: Emulate SYSENTER RIP/RSP behavior for all Intel compat vCPUs

Emulate bits 63:32 of the SYSENTER_R{I,S}P MSRs for all vCPUs that are
compatible with Intel's architecture, not just strictly vCPUs that have
vendor==Intel. The behavior of bits 63:32 is architecturally defined in
the SDM, i.e. not some uarch specific quirk of Intel CPUs.

Signed-off-by: Sean Christopherson <[email protected]>
---
arch/x86/kvm/cpuid.h | 8 --------
arch/x86/kvm/svm/svm.c | 14 +++++++-------
2 files changed, 7 insertions(+), 15 deletions(-)

diff --git a/arch/x86/kvm/cpuid.h b/arch/x86/kvm/cpuid.h
index 23dbb9eb277c..03d015e9ce33 100644
--- a/arch/x86/kvm/cpuid.h
+++ b/arch/x86/kvm/cpuid.h
@@ -112,14 +112,6 @@ static inline bool guest_cpuid_is_amd_or_hygon(struct kvm_vcpu *vcpu)
is_guest_vendor_hygon(best->ebx, best->ecx, best->edx));
}

-static inline bool guest_cpuid_is_intel(struct kvm_vcpu *vcpu)
-{
- struct kvm_cpuid_entry2 *best;
-
- best = kvm_find_cpuid_entry(vcpu, 0);
- return best && is_guest_vendor_intel(best->ebx, best->ecx, best->edx);
-}
-
static inline bool guest_cpuid_is_amd_compatible(struct kvm_vcpu *vcpu)
{
return vcpu->arch.is_amd_compatible;
diff --git a/arch/x86/kvm/svm/svm.c b/arch/x86/kvm/svm/svm.c
index d1a9f9951635..e1266b023203 100644
--- a/arch/x86/kvm/svm/svm.c
+++ b/arch/x86/kvm/svm/svm.c
@@ -1196,7 +1196,7 @@ static inline void init_vmcb_after_set_cpuid(struct kvm_vcpu *vcpu)
{
struct vcpu_svm *svm = to_svm(vcpu);

- if (guest_cpuid_is_intel(vcpu)) {
+ if (guest_cpuid_is_intel_compatible(vcpu)) {
/*
* We must intercept SYSENTER_EIP and SYSENTER_ESP
* accesses because the processor only stores 32 bits.
@@ -2853,12 +2853,12 @@ static int svm_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
break;
case MSR_IA32_SYSENTER_EIP:
msr_info->data = (u32)svm->vmcb01.ptr->save.sysenter_eip;
- if (guest_cpuid_is_intel(vcpu))
+ if (guest_cpuid_is_intel_compatible(vcpu))
msr_info->data |= (u64)svm->sysenter_eip_hi << 32;
break;
case MSR_IA32_SYSENTER_ESP:
msr_info->data = svm->vmcb01.ptr->save.sysenter_esp;
- if (guest_cpuid_is_intel(vcpu))
+ if (guest_cpuid_is_intel_compatible(vcpu))
msr_info->data |= (u64)svm->sysenter_esp_hi << 32;
break;
case MSR_TSC_AUX:
@@ -3081,11 +3081,11 @@ static int svm_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr)
* 32 bit part of these msrs to support Intel's
* implementation of SYSENTER/SYSEXIT.
*/
- svm->sysenter_eip_hi = guest_cpuid_is_intel(vcpu) ? (data >> 32) : 0;
+ svm->sysenter_eip_hi = guest_cpuid_is_intel_compatible(vcpu) ? (data >> 32) : 0;
break;
case MSR_IA32_SYSENTER_ESP:
svm->vmcb01.ptr->save.sysenter_esp = (u32)data;
- svm->sysenter_esp_hi = guest_cpuid_is_intel(vcpu) ? (data >> 32) : 0;
+ svm->sysenter_esp_hi = guest_cpuid_is_intel_compatible(vcpu) ? (data >> 32) : 0;
break;
case MSR_TSC_AUX:
/*
@@ -4328,11 +4328,11 @@ static void svm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu)
kvm_governed_feature_check_and_set(vcpu, X86_FEATURE_LBRV);

/*
- * Intercept VMLOAD if the vCPU mode is Intel in order to emulate that
+ * Intercept VMLOAD if the vCPU model is Intel in order to emulate that
* VMLOAD drops bits 63:32 of SYSENTER (ignoring the fact that exposing
* SVM on Intel is bonkers and extremely unlikely to work).
*/
- if (!guest_cpuid_is_intel(vcpu))
+ if (!guest_cpuid_is_intel_compatible(vcpu))
kvm_governed_feature_check_and_set(vcpu, X86_FEATURE_V_VMSAVE_VMLOAD);

kvm_governed_feature_check_and_set(vcpu, X86_FEATURE_PAUSEFILTER);
--
2.44.0.478.gd926399ef9-goog


2024-04-05 23:58:33

by Sean Christopherson

[permalink] [raw]
Subject: [PATCH 08/10] KVM: x86: Allow SYSENTER in Compatibility Mode for all Intel compat vCPUs

Emulate SYSENTER in Compatibility Mode for all vCPUs models that are
compatible with Intel's architecture, as the behavior if SYSENTER is
architecturally defined in Intel's SDM, i.e. should be followed by any
CPU that implements Intel's architecture.

Signed-off-by: Sean Christopherson <[email protected]>
---
arch/x86/kvm/emulate.c | 10 ++++++----
1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 1fb73d96bdf0..26e8c197a1d1 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -2354,6 +2354,7 @@ setup_syscalls_segments(struct desc_struct *cs, struct desc_struct *ss)
ss->avl = 0;
}

+#ifdef CONFIG_X86_64
static bool vendor_intel(struct x86_emulate_ctxt *ctxt)
{
u32 eax, ebx, ecx, edx;
@@ -2362,6 +2363,7 @@ static bool vendor_intel(struct x86_emulate_ctxt *ctxt)
ctxt->ops->get_cpuid(ctxt, &eax, &ebx, &ecx, &edx, true);
return is_guest_vendor_intel(ebx, ecx, edx);
}
+#endif

static int em_syscall(struct x86_emulate_ctxt *ctxt)
{
@@ -2444,11 +2446,11 @@ static int em_sysenter(struct x86_emulate_ctxt *ctxt)
return emulate_gp(ctxt, 0);

/*
- * Not recognized on AMD in compat mode (but is recognized in legacy
- * mode).
+ * Intel's architecture allows SYSENTER in compatibility mode, but AMD
+ * does not. Note, AMD does allow SYSENTER in legacy protected mode.
*/
- if ((ctxt->mode != X86EMUL_MODE_PROT64) && (efer & EFER_LMA)
- && !vendor_intel(ctxt))
+ if ((ctxt->mode != X86EMUL_MODE_PROT64) && (efer & EFER_LMA) &&
+ !ctxt->ops->guest_cpuid_is_intel_compatible(ctxt))
return emulate_ud(ctxt);

/* sysenter/sysexit have not been tested in 64bit mode. */
--
2.44.0.478.gd926399ef9-goog


2024-04-05 23:58:54

by Sean Christopherson

[permalink] [raw]
Subject: [PATCH 09/10] KVM: x86: Open code vendor_intel() in string_registers_quirk()

Open code the is_guest_vendor_intel() check in string_registers_quirk() to
discourage makiking exact vendor==Intel checks in the emulator, and to
remove the rather awful #ifdeffery.

The string quirk is literally the only Intel specific, *non-architectural*
behavior that KVM emulates. All Intel specific behavior that is
architecturally defined applies to all vendors that are compatible with
Intel's architecture, i.e. should use guest_cpuid_is_intel_compatible().

Signed-off-by: Sean Christopherson <[email protected]>
---
arch/x86/kvm/emulate.c | 20 ++++++++------------
1 file changed, 8 insertions(+), 12 deletions(-)

diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index 26e8c197a1d1..1acd97c6fa53 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -2354,17 +2354,6 @@ setup_syscalls_segments(struct desc_struct *cs, struct desc_struct *ss)
ss->avl = 0;
}

-#ifdef CONFIG_X86_64
-static bool vendor_intel(struct x86_emulate_ctxt *ctxt)
-{
- u32 eax, ebx, ecx, edx;
-
- eax = ecx = 0;
- ctxt->ops->get_cpuid(ctxt, &eax, &ebx, &ecx, &edx, true);
- return is_guest_vendor_intel(ebx, ecx, edx);
-}
-#endif
-
static int em_syscall(struct x86_emulate_ctxt *ctxt)
{
const struct x86_emulate_ops *ops = ctxt->ops;
@@ -2622,7 +2611,14 @@ static void string_registers_quirk(struct x86_emulate_ctxt *ctxt)
* manner when ECX is zero due to REP-string optimizations.
*/
#ifdef CONFIG_X86_64
- if (ctxt->ad_bytes != 4 || !vendor_intel(ctxt))
+ u32 eax, ebx, ecx, edx;
+
+ if (ctxt->ad_bytes != 4)
+ return;
+
+ eax = ecx = 0;
+ ctxt->ops->get_cpuid(ctxt, &eax, &ebx, &ecx, &edx, true);
+ if (!is_guest_vendor_intel(ebx, ecx, edx))
return;

*reg_write(ctxt, VCPU_REGS_RCX) = 0;
--
2.44.0.478.gd926399ef9-goog


2024-04-05 23:59:12

by Sean Christopherson

[permalink] [raw]
Subject: [PATCH 10/10] KVM: x86: Bury guest_cpuid_is_amd_or_hygon() in cpuid.c

Move guest_cpuid_is_amd_or_hygon() into cpuid.c now that, except for one
Intel quirk in the emulator, KVM checks for AMD vs. Intel *compatible*
vCPUs, not exact vendors, i.e. now that there should not be any reason for
KVM at-large to care about the exact vendor.

Opportunistically refactor the guts of the helper to use "entry" instead
of "best", and short circuit the !entry path to make the common case more
readable.

Signed-off-by: Sean Christopherson <[email protected]>
---
arch/x86/kvm/cpuid.c | 12 ++++++++++++
arch/x86/kvm/cpuid.h | 10 ----------
2 files changed, 12 insertions(+), 10 deletions(-)

diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
index 77352a4abd87..c5fb39930213 100644
--- a/arch/x86/kvm/cpuid.c
+++ b/arch/x86/kvm/cpuid.c
@@ -335,6 +335,18 @@ static bool kvm_cpuid_has_hyperv(struct kvm_cpuid_entry2 *entries, int nent)
#endif
}

+static bool guest_cpuid_is_amd_or_hygon(struct kvm_vcpu *vcpu)
+{
+ struct kvm_cpuid_entry2 *entry;
+
+ entry = kvm_find_cpuid_entry(vcpu, 0);
+ if (!entry)
+ return false;
+
+ return is_guest_vendor_amd(entry->ebx, entry->ecx, entry->edx) ||
+ is_guest_vendor_hygon(entry->ebx, entry->ecx, entry->edx);
+}
+
static void kvm_vcpu_after_set_cpuid(struct kvm_vcpu *vcpu)
{
struct kvm_lapic *apic = vcpu->arch.apic;
diff --git a/arch/x86/kvm/cpuid.h b/arch/x86/kvm/cpuid.h
index 03d015e9ce33..41697cca354e 100644
--- a/arch/x86/kvm/cpuid.h
+++ b/arch/x86/kvm/cpuid.h
@@ -102,16 +102,6 @@ static __always_inline void guest_cpuid_clear(struct kvm_vcpu *vcpu,
*reg &= ~__feature_bit(x86_feature);
}

-static inline bool guest_cpuid_is_amd_or_hygon(struct kvm_vcpu *vcpu)
-{
- struct kvm_cpuid_entry2 *best;
-
- best = kvm_find_cpuid_entry(vcpu, 0);
- return best &&
- (is_guest_vendor_amd(best->ebx, best->ecx, best->edx) ||
- is_guest_vendor_hygon(best->ebx, best->ecx, best->edx));
-}
-
static inline bool guest_cpuid_is_amd_compatible(struct kvm_vcpu *vcpu)
{
return vcpu->arch.is_amd_compatible;
--
2.44.0.478.gd926399ef9-goog


2024-04-09 02:02:15

by Sean Christopherson

[permalink] [raw]
Subject: Re: [PATCH 00/10] KVM: x86: Fix LVTPC masking on AMD CPUs

On Fri, 05 Apr 2024 16:55:53 -0700, Sean Christopherson wrote:
> This is kinda sorta v2 of Sandipan's fix for KVM's incorrect setting of
> the MASK bit when delivering PMIs through the LVTPC.
>
> It's a bit rushed, as I want to get Sandipan's fix applied early next
> week so that it can make its way to Linus' tree for -rc4. And I didn't
> want to apply Sandipan's patch as-is, because I'm a little paranoid that
> the guest CPUID check could be noticeable slow, and it's easy to avoid.
>
> [...]

Applied 1 and 2 to kvm-x86 fixes.

[01/10] KVM: x86: Snapshot if a vCPU's vendor model is AMD vs. Intel compatible
https://github.com/kvm-x86/linux/commit/3b764d0af391
[02/10] KVM: x86/pmu: Do not mask LVTPC when handling a PMI on AMD platforms
https://github.com/kvm-x86/linux/commit/85cff527ab31

--
https://github.com/kvm-x86/linux/tree/next

2024-04-11 18:09:18

by Paolo Bonzini

[permalink] [raw]
Subject: Re: [PATCH 00/10] KVM: x86: Fix LVTPC masking on AMD CPUs

On Sat, Apr 6, 2024 at 1:56 AM Sean Christopherson <[email protected]> wrote:
>
> This is kinda sorta v2 of Sandipan's fix for KVM's incorrect setting of
> the MASK bit when delivering PMIs through the LVTPC.
>
> It's a bit rushed, as I want to get Sandipan's fix applied early next
> week so that it can make its way to Linus' tree for -rc4. And I didn't
> want to apply Sandipan's patch as-is, because I'm a little paranoid that
> the guest CPUID check could be noticeable slow, and it's easy to avoid.
>
> My plan is to grab patches 1-2 for 6.9 asap, and let the rest simmer for
> much, much longer (they are *very* lightly tested).

Oops---I missed your queuing message and pushed the same to kvm/master.

Is it okay if you use commit 49ff3b4aec51e as the basis for any 6.10
topic branches that may conflict (or that build open the first two
patches)?

Paolo


Paolo

>
> As for why this looks wildy different than Sandipan's compat_vendor idea,
> when I started looking at KVM's various AMD vs. Intel checks, I realized
> it makes no sense to support an "unknown" vendor. KVM can't do *nothing*,
> and so practically speaking, an "unknown" vendor vCPU would actually end
> up with a weird mix of AMD *and* Intel behavior, not AMD *or* Intel
> behavior.
>
> Sandipan Das (1):
> KVM: x86/pmu: Do not mask LVTPC when handling a PMI on AMD platforms
>
> Sean Christopherson (9):
> KVM: x86: Snapshot if a vCPU's vendor model is AMD vs. Intel
> compatible
> KVM: x86/pmu: Squash period for checkpointed events based on host
> HLE/RTM
> KVM: x86: Apply Intel's TSC_AUX reserved-bit behavior to Intel compat
> vCPUs
> KVM: x86: Inhibit code #DBs in MOV-SS shadow for all Intel compat
> vCPUs
> KVM: x86: Use "is Intel compatible" helper to emulate SYSCALL in
> !64-bit
> KVM: SVM: Emulate SYSENTER RIP/RSP behavior for all Intel compat vCPUs
> KVM: x86: Allow SYSENTER in Compatibility Mode for all Intel compat
> vCPUs
> KVM: x86: Open code vendor_intel() in string_registers_quirk()
> KVM: x86: Bury guest_cpuid_is_amd_or_hygon() in cpuid.c
>
> arch/x86/include/asm/kvm_host.h | 1 +
> arch/x86/kvm/cpuid.c | 13 ++++++
> arch/x86/kvm/cpuid.h | 16 ++------
> arch/x86/kvm/emulate.c | 71 ++++++++++-----------------------
> arch/x86/kvm/kvm_emulate.h | 1 +
> arch/x86/kvm/lapic.c | 3 +-
> arch/x86/kvm/mmu/mmu.c | 2 +-
> arch/x86/kvm/pmu.c | 2 +-
> arch/x86/kvm/svm/svm.c | 14 +++----
> arch/x86/kvm/x86.c | 30 ++++++++------
> 10 files changed, 68 insertions(+), 85 deletions(-)
>
>
> base-commit: 8cb4a9a82b21623dbb4b3051dd30d98356cf95bc
> --
> 2.44.0.478.gd926399ef9-goog
>


2024-06-12 01:22:32

by Sean Christopherson

[permalink] [raw]
Subject: Re: [PATCH 00/10] KVM: x86: Fix LVTPC masking on AMD CPUs

On Fri, 05 Apr 2024 16:55:53 -0700, Sean Christopherson wrote:
> This is kinda sorta v2 of Sandipan's fix for KVM's incorrect setting of
> the MASK bit when delivering PMIs through the LVTPC.
>
> It's a bit rushed, as I want to get Sandipan's fix applied early next
> week so that it can make its way to Linus' tree for -rc4. And I didn't
> want to apply Sandipan's patch as-is, because I'm a little paranoid that
> the guest CPUID check could be noticeable slow, and it's easy to avoid.
>
> [...]

Applied 3-10 to kvm-x86 misc (1-2 went into 6.9).

[01/10] KVM: x86: Snapshot if a vCPU's vendor model is AMD vs. Intel compatible
(previously applied)
[02/10] KVM: x86/pmu: Do not mask LVTPC when handling a PMI on AMD platforms
(previously applied)
[03/10] KVM: x86/pmu: Squash period for checkpointed events based on host HLE/RTM
https://github.com/kvm-x86/linux/commit/5a4f8b3026fc
[04/10] KVM: x86: Apply Intel's TSC_AUX reserved-bit behavior to Intel compat vCPUs
https://github.com/kvm-x86/linux/commit/6463e5e41842
[05/10] KVM: x86: Inhibit code #DBs in MOV-SS shadow for all Intel compat vCPUs
https://github.com/kvm-x86/linux/commit/c092fc879f99
[06/10] KVM: x86: Use "is Intel compatible" helper to emulate SYSCALL in !64-bit
https://github.com/kvm-x86/linux/commit/d99e4cb2ae2e
[07/10] KVM: SVM: Emulate SYSENTER RIP/RSP behavior for all Intel compat vCPUs
https://github.com/kvm-x86/linux/commit/dc2b8b2b524a
[08/10] KVM: x86: Allow SYSENTER in Compatibility Mode for all Intel compat vCPUs
https://github.com/kvm-x86/linux/commit/4067c2395e80
[09/10] KVM: x86: Open code vendor_intel() in string_registers_quirk()
https://github.com/kvm-x86/linux/commit/bdaff4f92bce
[10/10] KVM: x86: Bury guest_cpuid_is_amd_or_hygon() in cpuid.c
https://github.com/kvm-x86/linux/commit/1028893a73fe

--
https://github.com/kvm-x86/linux/tree/next