mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Sean Christopherson <seanjc@google.com>
To: Paolo Bonzini <pbonzini@redhat.com>
Cc: Sean Christopherson <seanjc@google.com>,
	Vitaly Kuznetsov <vkuznets@redhat.com>,
	Wanpeng Li <wanpengli@tencent.com>,
	Jim Mattson <jmattson@google.com>, Joerg Roedel <joro@8bytes.org>,
	kvm@vger.kernel.org, linux-kernel@vger.kernel.org,
	Eric Li <ercli@ucdavis.edu>, David Matlack <dmatlack@google.com>,
	Oliver Upton <oupton@google.com>
Subject: [PATCH v5 13/15] KVM: selftests: Add test to verify KVM's VMX MSRs quirk for controls
Date: Tue,  7 Jun 2022 21:36:02 +0000	[thread overview]
Message-ID: <20220607213604.3346000-14-seanjc@google.com> (raw)
In-Reply-To: <20220607213604.3346000-1-seanjc@google.com>

Add a test to verify KVM's established ABI with respect to the entry/exit
controls for PERF_GLOBAL_CTRL and BNDCFGS.  KVM has a quirk where KVM
updates the VMX "true" entry/exit control MSRs to force PERF_GLOBAL_CTRL
and BNDCFGS to follow the guest CPUID model, i.e. set when supported,
clear when not, even though the MSR values are not strictly associated
with CPUID.  Note, KVM's ABI is that its modifications to the MSRs are
preserved even when userspace explicitly writes the MSRs.

Verify that KVM correctly tweaks the MSRs When the quirk is enabled (the
default behavior), and does not touch them when the quirk is disabled.

Suggested-by: Oliver Upton <oupton@google.com>
Signed-off-by: Sean Christopherson <seanjc@google.com>
---
 tools/testing/selftests/kvm/.gitignore        |   1 +
 tools/testing/selftests/kvm/Makefile          |   1 +
 .../selftests/kvm/include/x86_64/processor.h  |   1 +
 .../selftests/kvm/include/x86_64/vmx.h        |   2 +
 .../selftests/kvm/x86_64/vmx_msrs_test.c      | 161 ++++++++++++++++++
 5 files changed, 166 insertions(+)
 create mode 100644 tools/testing/selftests/kvm/x86_64/vmx_msrs_test.c

diff --git a/tools/testing/selftests/kvm/.gitignore b/tools/testing/selftests/kvm/.gitignore
index 0ab0e255d292..5893804b5196 100644
--- a/tools/testing/selftests/kvm/.gitignore
+++ b/tools/testing/selftests/kvm/.gitignore
@@ -47,6 +47,7 @@
 /x86_64/vmx_dirty_log_test
 /x86_64/vmx_exception_with_invalid_guest_state
 /x86_64/vmx_invalid_nested_guest_state
+/x86_64/vmx_msrs_test
 /x86_64/vmx_preemption_timer_test
 /x86_64/vmx_set_nested_state_test
 /x86_64/vmx_tsc_adjust_test
diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile
index 9a256c1f1bdf..2ee2dc55c100 100644
--- a/tools/testing/selftests/kvm/Makefile
+++ b/tools/testing/selftests/kvm/Makefile
@@ -74,6 +74,7 @@ TEST_GEN_PROGS_x86_64 += x86_64/vmx_apic_access_test
 TEST_GEN_PROGS_x86_64 += x86_64/vmx_close_while_nested_test
 TEST_GEN_PROGS_x86_64 += x86_64/vmx_dirty_log_test
 TEST_GEN_PROGS_x86_64 += x86_64/vmx_exception_with_invalid_guest_state
+TEST_GEN_PROGS_x86_64 += x86_64/vmx_msrs_test
 TEST_GEN_PROGS_x86_64 += x86_64/vmx_invalid_nested_guest_state
 TEST_GEN_PROGS_x86_64 += x86_64/vmx_set_nested_state_test
 TEST_GEN_PROGS_x86_64 += x86_64/vmx_tsc_adjust_test
diff --git a/tools/testing/selftests/kvm/include/x86_64/processor.h b/tools/testing/selftests/kvm/include/x86_64/processor.h
index 3fd3d58148c2..51cab9b080f7 100644
--- a/tools/testing/selftests/kvm/include/x86_64/processor.h
+++ b/tools/testing/selftests/kvm/include/x86_64/processor.h
@@ -98,6 +98,7 @@ struct kvm_x86_cpu_feature {
 #define	X86_FEATURE_SMEP	        KVM_X86_CPU_FEATURE(0x7, 0, EBX, 7)
 #define	X86_FEATURE_INVPCID		KVM_X86_CPU_FEATURE(0x7, 0, EBX, 10)
 #define	X86_FEATURE_RTM			KVM_X86_CPU_FEATURE(0x7, 0, EBX, 11)
+#define	X86_FEATURE_MPX			KVM_X86_CPU_FEATURE(0x7, 0, EBX, 14)
 #define	X86_FEATURE_SMAP		KVM_X86_CPU_FEATURE(0x7, 0, EBX, 20)
 #define	X86_FEATURE_PCOMMIT		KVM_X86_CPU_FEATURE(0x7, 0, EBX, 22)
 #define	X86_FEATURE_CLFLUSHOPT		KVM_X86_CPU_FEATURE(0x7, 0, EBX, 23)
diff --git a/tools/testing/selftests/kvm/include/x86_64/vmx.h b/tools/testing/selftests/kvm/include/x86_64/vmx.h
index fe0ebb790b49..5a6002b34d2b 100644
--- a/tools/testing/selftests/kvm/include/x86_64/vmx.h
+++ b/tools/testing/selftests/kvm/include/x86_64/vmx.h
@@ -80,6 +80,7 @@
 #define VM_EXIT_SAVE_IA32_EFER			0x00100000
 #define VM_EXIT_LOAD_IA32_EFER			0x00200000
 #define VM_EXIT_SAVE_VMX_PREEMPTION_TIMER	0x00400000
+#define VM_EXIT_CLEAR_BNDCFGS			0x00800000
 
 #define VM_EXIT_ALWAYSON_WITHOUT_TRUE_MSR	0x00036dff
 
@@ -90,6 +91,7 @@
 #define VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL	0x00002000
 #define VM_ENTRY_LOAD_IA32_PAT			0x00004000
 #define VM_ENTRY_LOAD_IA32_EFER			0x00008000
+#define VM_ENTRY_LOAD_BNDCFGS			0x00010000
 
 #define VM_ENTRY_ALWAYSON_WITHOUT_TRUE_MSR	0x000011ff
 
diff --git a/tools/testing/selftests/kvm/x86_64/vmx_msrs_test.c b/tools/testing/selftests/kvm/x86_64/vmx_msrs_test.c
new file mode 100644
index 000000000000..9be2c2e3acf1
--- /dev/null
+++ b/tools/testing/selftests/kvm/x86_64/vmx_msrs_test.c
@@ -0,0 +1,161 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * VMX control MSR test
+ *
+ * Copyright (C) 2022 Google LLC.
+ *
+ * Tests for KVM ownership of bits in the VMX entry/exit control MSRs. Checks
+ * that KVM will set owned bits where appropriate, and will not if
+ * KVM_X86_QUIRK_TWEAK_VMX_CTRL_MSRS is disabled.
+ */
+
+#include "kvm_util.h"
+#include "vmx.h"
+
+#define SUBTEST_REQUIRE(f)					\
+	if (!(f)) {						\
+		print_skip("Requirement not met: %s", #f);	\
+		return;						\
+	}
+
+static bool vmx_has_ctrl(struct kvm_vcpu *vcpu, uint32_t msr, uint32_t ctrl_mask)
+{
+	return (vcpu_get_msr(vcpu, msr) >> 32) & ctrl_mask;
+}
+
+static void test_vmx_ctrl_msr(struct kvm_vcpu *vcpu,
+			      uint32_t msr, uint64_t ctrl_mask,
+			      bool quirk_enabled, bool feature_enabled)
+{
+	uint64_t ctrl_allowed1 = ctrl_mask << 32;
+	uint64_t val = vcpu_get_msr(vcpu, msr);
+
+	/*
+	 * If the quirk is enabled, KVM should have modified the MSR when the
+	 * guest's CPUID was set.  Don't assert anything when the quirk is
+	 * disabled, the value of the MSR is not known (it could be made known,
+	 * but it gets messy and the added value is minimal).
+	 */
+	TEST_ASSERT(!quirk_enabled || (!!(val & ctrl_allowed1) == feature_enabled),
+		    "KVM owns the ctrl when the quirk is enabled, want 0x%lx, got 0x%lx",
+		    feature_enabled ? ctrl_allowed1 : 0, val & ctrl_allowed1);
+
+	val |= ctrl_allowed1;
+	vcpu_set_msr(vcpu, msr, val);
+
+	val = vcpu_get_msr(vcpu, msr);
+	if (quirk_enabled)
+		TEST_ASSERT(!!(val & ctrl_allowed1) == feature_enabled,
+			    "KVM owns the ctrl when the quirk is enabled, want 0x%lx, got 0x%lx",
+			    feature_enabled ? ctrl_allowed1 : 0, val & ctrl_allowed1);
+	else
+		TEST_ASSERT(val & ctrl_allowed1,
+			    "KVM shouldn't clear the ctrl when the quirk is disabled");
+
+	val &= ~ctrl_allowed1;
+	vcpu_set_msr(vcpu, msr, val);
+
+	val = vcpu_get_msr(vcpu, msr);
+	if (quirk_enabled)
+		TEST_ASSERT(!!(val & ctrl_allowed1) == feature_enabled,
+			    "KVM owns the ctrl when the quirk is enabled, want 0x%lx, got 0x%lx",
+			    feature_enabled ? ctrl_allowed1 : 0, val & ctrl_allowed1);
+	else
+		TEST_ASSERT(!(val & ctrl_allowed1),
+			    "KVM shouldn't set the ctrl when the quirk is disabled");
+}
+
+static void test_vmx_ctrl_msrs_pair(struct kvm_vcpu *vcpu,
+				    bool quirk_enabled, bool feature_enabled,
+				    uint32_t entry_msr, uint64_t entry_mask,
+				    uint32_t exit_msr, uint64_t exit_mask)
+{
+	test_vmx_ctrl_msr(vcpu, entry_msr, entry_mask, quirk_enabled, feature_enabled);
+	test_vmx_ctrl_msr(vcpu, exit_msr, exit_mask, quirk_enabled, feature_enabled);
+}
+
+static void test_vmx_ctrls(struct kvm_vm *vm, struct kvm_vcpu *vcpu,
+			   uint64_t entry_ctrl, uint64_t exit_ctrl)
+{
+	/*
+	 * KVM's quirky behavior only exists for PERF_GLOBAL_CTRL and BNDCFGS,
+	 * any attempt to extend KVM's quirky behavior must be met with fierce
+	 * resistance!
+	 */
+	TEST_ASSERT(entry_ctrl == VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL ||
+		    entry_ctrl == VM_ENTRY_LOAD_BNDCFGS,
+		    "Don't let KVM expand its quirk beyond PERF_GLOBAL_CTRL and BNDCFSG");
+
+	SUBTEST_REQUIRE(vmx_has_ctrl(vcpu, MSR_IA32_VMX_TRUE_ENTRY_CTLS, entry_ctrl));
+	SUBTEST_REQUIRE(vmx_has_ctrl(vcpu, MSR_IA32_VMX_TRUE_EXIT_CTLS, exit_ctrl));
+
+	/*
+	 * Test that, when the quirk is enabled, KVM sets/clears the VMX MSR
+	 * bits based on whether or not the feature is exposed to the guest.
+	 */
+	test_vmx_ctrl_msrs_pair(vcpu, true, true,
+				MSR_IA32_VMX_TRUE_ENTRY_CTLS, entry_ctrl,
+				MSR_IA32_VMX_TRUE_EXIT_CTLS, exit_ctrl);
+
+	/* Hide the feature in CPUID. */
+	if (entry_ctrl == VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL)
+		vcpu_clear_cpuid_entry(vcpu, 0xa);
+	else
+		vcpu_clear_cpuid_feature(vcpu, X86_FEATURE_MPX);
+
+	test_vmx_ctrl_msrs_pair(vcpu, true, false,
+				MSR_IA32_VMX_TRUE_ENTRY_CTLS, entry_ctrl,
+				MSR_IA32_VMX_TRUE_EXIT_CTLS, exit_ctrl);
+
+	/*
+	 * Disable the quirk, giving userspace control of the VMX MSRs.  KVM
+	 * should not touch the MSR, i.e. should allow hiding the control when
+	 * a vPMU is supported, and should allow exposing the control when a
+	 * vPMU is not supported.
+	 */
+	vm_enable_cap(vm, KVM_CAP_DISABLE_QUIRKS2, KVM_X86_QUIRK_TWEAK_VMX_MSRS);
+
+	test_vmx_ctrl_msrs_pair(vcpu, false, false,
+				MSR_IA32_VMX_TRUE_ENTRY_CTLS, entry_ctrl,
+				MSR_IA32_VMX_TRUE_EXIT_CTLS, exit_ctrl);
+
+	/* Restore the full CPUID to expose the feature to the guest. */
+	vcpu_init_cpuid(vcpu, kvm_get_supported_cpuid());
+	test_vmx_ctrl_msrs_pair(vcpu, false, true,
+				MSR_IA32_VMX_TRUE_ENTRY_CTLS, entry_ctrl,
+				MSR_IA32_VMX_TRUE_EXIT_CTLS, exit_ctrl);
+
+	vm_enable_cap(vm, KVM_CAP_DISABLE_QUIRKS2, 0);
+}
+
+static void load_perf_global_ctrl_test(struct kvm_vm *vm, struct kvm_vcpu *vcpu)
+{
+	SUBTEST_REQUIRE(kvm_get_cpuid_max_basic() >= 0xa);
+
+	test_vmx_ctrls(vm, vcpu, VM_ENTRY_LOAD_IA32_PERF_GLOBAL_CTRL,
+		       VM_EXIT_LOAD_IA32_PERF_GLOBAL_CTRL);
+}
+
+static void load_and_clear_bndcfgs_test(struct kvm_vm *vm, struct kvm_vcpu *vcpu)
+{
+	SUBTEST_REQUIRE(kvm_cpu_has(X86_FEATURE_MPX));
+
+	test_vmx_ctrls(vm, vcpu, VM_ENTRY_LOAD_BNDCFGS, VM_EXIT_CLEAR_BNDCFGS);
+}
+
+int main(void)
+{
+	struct kvm_vcpu *vcpu;
+	struct kvm_vm *vm;
+
+	TEST_REQUIRE(kvm_has_cap(KVM_CAP_DISABLE_QUIRKS2));
+	TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_VMX));
+
+	/* No need to actually do KVM_RUN, thus no guest code. */
+	vm = vm_create_with_one_vcpu(&vcpu, NULL);
+
+	load_perf_global_ctrl_test(vm, vcpu);
+	load_and_clear_bndcfgs_test(vm, vcpu);
+
+	kvm_vm_free(vm);
+}
-- 
2.36.1.255.ge46751e96f-goog


  parent reply	other threads:[~2022-06-08  1:30 UTC|newest]

Thread overview: 31+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2022-06-07 21:35 [PATCH v5 00/15] KVM: nVMX: VMX MSR quirk+fixes, CR4 fixes Sean Christopherson
2022-06-07 21:35 ` [PATCH v5 01/15] KVM: x86: Split kvm_is_valid_cr4() and export only the non-vendor bits Sean Christopherson
2022-06-07 21:35 ` [PATCH v5 02/15] KVM: nVMX: Account for KVM reserved CR4 bits in consistency checks Sean Christopherson
2022-06-07 21:35 ` [PATCH v5 03/15] KVM: nVMX: Inject #UD if VMXON is attempted with incompatible CR0/CR4 Sean Christopherson
2022-06-07 21:35 ` [PATCH v5 04/15] KVM: nVMX: Rename handle_vm{on,off}() to handle_vmx{on,off}() Sean Christopherson
2022-06-07 21:35 ` [PATCH v5 05/15] KVM: nVMX: Let userspace set nVMX MSR to any _host_ supported value Sean Christopherson
2022-10-31 16:39   ` Yu Zhang
2022-10-31 17:11     ` Sean Christopherson
2022-11-01 10:18       ` Yu Zhang
2022-11-01 17:58         ` Sean Christopherson
2022-11-02  8:54           ` Yu Zhang
2022-11-03 16:53             ` Sean Christopherson
2022-11-07  8:28               ` Yu Zhang
2022-11-07 15:06                 ` Sean Christopherson
2022-11-08 10:21                   ` Yu Zhang
2022-11-08 18:35                     ` Sean Christopherson
2022-11-10  8:44                       ` Yu Zhang
2022-11-10 16:08                         ` Sean Christopherson
2022-06-07 21:35 ` [PATCH v5 06/15] KVM: nVMX: Keep KVM updates to BNDCFGS ctrl bits across MSR write Sean Christopherson
2022-07-22  9:06   ` Paolo Bonzini
2022-06-07 21:35 ` [PATCH v5 07/15] KVM: VMX: Add helper to check if the guest PMU has PERF_GLOBAL_CTRL Sean Christopherson
2022-06-07 21:35 ` [PATCH v5 08/15] KVM: nVMX: Keep KVM updates to PERF_GLOBAL_CTRL ctrl bits across MSR write Sean Christopherson
2022-06-07 21:35 ` [PATCH v5 09/15] KVM: nVMX: Drop nested_vmx_pmu_refresh() Sean Christopherson
2022-06-07 21:35 ` [PATCH v5 10/15] KVM: nVMX: Add a quirk for KVM tweaks to VMX MSRs Sean Christopherson
2022-06-07 21:36 ` [PATCH v5 11/15] KVM: nVMX: Set UMIP bit CR4_FIXED1 MSR when emulating UMIP Sean Christopherson
2022-07-22  9:49   ` Paolo Bonzini
2022-06-07 21:36 ` [PATCH v5 12/15] KVM: nVMX: Extend VMX MSRs quirk to CR0/4 fixed1 bits Sean Christopherson
2022-07-22  9:50   ` Paolo Bonzini
2022-06-07 21:36 ` Sean Christopherson [this message]
2022-06-07 21:36 ` [PATCH v5 14/15] KVM: selftests: Extend VMX MSRs test to cover CR4_FIXED1 (and its quirks) Sean Christopherson
2022-06-07 21:36 ` [PATCH v5 15/15] KVM: selftests: Verify VMX MSRs can be restored to KVM-supported values Sean Christopherson

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20220607213604.3346000-14-seanjc@google.com \
    --to=seanjc@google.com \
    --cc=dmatlack@google.com \
    --cc=ercli@ucdavis.edu \
    --cc=jmattson@google.com \
    --cc=joro@8bytes.org \
    --cc=kvm@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=oupton@google.com \
    --cc=pbonzini@redhat.com \
    --cc=vkuznets@redhat.com \
    --cc=wanpengli@tencent.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®