[PATCH 1/2] KVM: selftests: Test consistency of setting MSR_IA32_DS_AREA

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Jinrong Liang <cloudliang@xxxxxxxxxxx>

Tests have been added to this commit to check if setting
MSR_IA32_DS_AREA with a non-classical address causes a fault. By
verifying that KVM is correctly faulting non-classical addresses
in MSR_IA32_DS_AREA, it helps ensure the accuracy and stability
of the KVM subsystem.

Signed-off-by: Jinrong Liang <cloudliang@xxxxxxxxxxx>
---
 .../selftests/kvm/x86_64/vmx_pmu_caps_test.c  | 100 ++++++++++++++++++
 1 file changed, 100 insertions(+)

diff --git a/tools/testing/selftests/kvm/x86_64/vmx_pmu_caps_test.c b/tools/testing/selftests/kvm/x86_64/vmx_pmu_caps_test.c
index 4c90f76930f9..02903084598f 100644
--- a/tools/testing/selftests/kvm/x86_64/vmx_pmu_caps_test.c
+++ b/tools/testing/selftests/kvm/x86_64/vmx_pmu_caps_test.c
@@ -19,6 +19,9 @@
 #include "kvm_util.h"
 #include "vmx.h"
 
+#define MAX_LINEAR_ADDR_MASK		GENMASK_ULL(15, 8)
+#define ADDR_OFS_BIT			8
+
 union perf_capabilities {
 	struct {
 		u64	lbr_format:6;
@@ -232,6 +235,102 @@ static void test_lbr_perf_capabilities(union perf_capabilities host_cap)
 	kvm_vm_free(vm);
 }
 
+/*
+ * Generate a non-canonical address for a given number of address bits.
+ * @addr_bits: The number of address bits used in the system.
+ *
+ * This function calculates a non-canonical address by setting the most
+ * significant bit to 1 and adding an offset equal to the maximum value
+ * that can be represented by the remaining bits. This ensures that the
+ * generated address is outside the valid address range and is consistent.
+ */
+static inline uint64_t non_canonical_address(unsigned int addr_bits)
+{
+	return (1ULL << (addr_bits - 1)) + ((1ULL << (addr_bits - 1)) - 1);
+}
+
+static uint64_t get_addr_bits(struct kvm_vcpu *vcpu)
+{
+	const struct kvm_cpuid_entry2 *kvm_entry;
+	unsigned int addr_bits;
+	struct kvm_sregs sregs;
+
+	kvm_entry = get_cpuid_entry(kvm_get_supported_cpuid(), 0x80000008, 0);
+	addr_bits = (kvm_entry->eax & MAX_LINEAR_ADDR_MASK) >> ADDR_OFS_BIT;
+	/*
+	 * Get the size of the virtual address space by checking the LA57 bit
+	 * in the CR4 control register. If the LA57 bit is set, then the virtual
+	 * address space is 57 bits. Otherwise, it's 48 bits.
+	 */
+	if (addr_bits != 32) {
+		vcpu_sregs_get(vcpu, &sregs);
+		addr_bits = (sregs.cr4 & X86_CR4_LA57) ? 57 : 48;
+	}
+
+	return addr_bits;
+}
+
+static void test_ds_guest_code(uint64_t bad_addr)
+{
+	uint8_t vector = 0;
+
+	vector = wrmsr_safe(MSR_IA32_DS_AREA, bad_addr);
+	GUEST_SYNC(vector);
+}
+
+/* Check if setting MSR_IA32_DS_AREA in guest and kvm userspace will fail. */
+static void test_ds_area_noncanonical_address(union perf_capabilities host_cap)
+{
+	struct kvm_vm *vm;
+	struct kvm_vcpu *vcpu;
+	unsigned int r, addr_bits;
+	uint64_t bad_addr, without_pebs_fmt_caps;
+	struct ucall uc;
+
+	vm = vm_create_with_one_vcpu(&vcpu, test_ds_guest_code);
+	vm_init_descriptor_tables(vm);
+	vcpu_init_descriptor_tables(vcpu);
+
+	/* Check that Setting MSR_IA32_DS_AREA with 0 should succeed. */
+	r = _vcpu_set_msr(vcpu, MSR_IA32_DS_AREA, 0);
+	TEST_ASSERT(r, "Setting MSR_IA32_DS_AREA with 0 should succeed.");
+
+	/*
+	 * Check that if PEBS_FMT is not set setting MSR_IA32_DS_AREA will
+	 * succeed.
+	 */
+	without_pebs_fmt_caps = host_cap.capabilities & ~PERF_CAP_PEBS_FORMAT;
+	vcpu_set_msr(vcpu, MSR_IA32_PERF_CAPABILITIES, without_pebs_fmt_caps);
+	r = _vcpu_set_msr(vcpu, MSR_IA32_DS_AREA, 1);
+	TEST_ASSERT(r, "Setting MSR_IA32_DS_AREA with bad addr should fail.");
+
+	/*
+	 * Check that setting MSR_IA32_DS_AREA in kvm userspace to use a
+	 * non-canonical address should fail.
+	 */
+	vcpu_set_msr(vcpu, MSR_IA32_PERF_CAPABILITIES, host_cap.capabilities);
+	addr_bits = get_addr_bits(vcpu);
+	bad_addr = non_canonical_address(addr_bits);
+	r = _vcpu_set_msr(vcpu, MSR_IA32_DS_AREA, bad_addr);
+	TEST_ASSERT(!r, "Setting MSR_IA32_DS_AREA with bad addr should fail.");
+
+	/*
+	 * Check that setting MSR_IA32_DS_AREA in guest to use a non-canonical
+	 * address should cause the #GP.
+	 */
+	vcpu_args_set(vcpu, 1, bad_addr);
+	vcpu_run(vcpu);
+
+	TEST_ASSERT_KVM_EXIT_REASON(vcpu, KVM_EXIT_IO);
+	get_ucall(vcpu, &uc);
+	TEST_ASSERT(uc.cmd == UCALL_SYNC,
+		    "Received ucall other than UCALL_SYNC: %lu", uc.cmd);
+	TEST_ASSERT(uc.args[1] == GP_VECTOR,
+		    "Setting MSR_IA32_DS_AREA with bad addr should fail.");
+
+	kvm_vm_free(vm);
+}
+
 int main(int argc, char *argv[])
 {
 	union perf_capabilities host_cap;
@@ -252,4 +351,5 @@ int main(int argc, char *argv[])
 	test_immutable_perf_capabilities(host_cap);
 	test_guest_wrmsr_perf_capabilities(host_cap);
 	test_lbr_perf_capabilities(host_cap);
+	test_ds_area_noncanonical_address(host_cap);
 }
-- 
2.31.1




[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux