lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite for Android: free password hash cracker in your pocket
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20230323072714.82289-8-likexu@tencent.com>
Date:   Thu, 23 Mar 2023 15:27:14 +0800
From:   Like Xu <like.xu.linux@...il.com>
To:     Sean Christopherson <seanjc@...gle.com>
Cc:     Paolo Bonzini <pbonzini@...hat.com>,
        Jinrong Liang <cloudliang@...cent.com>,
        linux-kernel@...r.kernel.org, kvm@...r.kernel.org
Subject: [PATCH 7/7] KVM: selftests: Test Intel counters' bit width emulation

From: Like Xu <likexu@...cent.com>

Add tests to cover Intel counters' bit-width emulation. When the VM has
FW_WRITES bit, the bitwidth of the gp and fixed counters will be specified
by the CPUID (no less than 32 bits and no greater than the host bitwidth)
and accessing bits that are not within the bitwidth will generate #GP.
However, when it does not have FW_WRITES bit, only the low 32-bits
signed data will be in effect and naturally #GP will not be generated.

Co-developed-by: Jinrong Liang <cloudliang@...cent.com>
Signed-off-by: Jinrong Liang <cloudliang@...cent.com>
Signed-off-by: Like Xu <likexu@...cent.com>
---
 .../selftests/kvm/x86_64/pmu_cpuid_test.c     | 105 ++++++++++++++++++
 1 file changed, 105 insertions(+)

diff --git a/tools/testing/selftests/kvm/x86_64/pmu_cpuid_test.c b/tools/testing/selftests/kvm/x86_64/pmu_cpuid_test.c
index caf0d98079c7..e7465b01178a 100644
--- a/tools/testing/selftests/kvm/x86_64/pmu_cpuid_test.c
+++ b/tools/testing/selftests/kvm/x86_64/pmu_cpuid_test.c
@@ -29,6 +29,10 @@
 #define INTEL_PMC_IDX_FIXED 32
 #define RDPMC_FIXED_BASE BIT_ULL(30)
 #define FIXED_CTR_NUM_MASK GENMASK_ULL(4, 0)
+#define GP_WIDTH_OFS_BIT 16
+#define GP_WIDTH_MASK GENMASK_ULL(23, GP_WIDTH_OFS_BIT)
+#define FIXED_WIDTH_OFS_BIT 5
+#define FIXED_WIDTH_MASK GENMASK_ULL(12, FIXED_WIDTH_OFS_BIT)
 
 #define ARCH_EVENT(select, umask) (((select) & 0xff) | ((umask) & 0xff) << 8)
 
@@ -62,6 +66,16 @@ static const uint64_t perf_caps[] = {
  */
 #define MSR_INTEL_ARCH_PMU_GPCTR (MSR_IA32_PERFCTR0 + 2)
 
+static const uint32_t msr_bases[] = {
+	MSR_INTEL_ARCH_PMU_GPCTR,
+	MSR_IA32_PMC0,
+	MSR_CORE_PERF_FIXED_CTR0,
+};
+
+static const uint64_t bit_widths[] = {
+	0, 1, 31, 32, 47, 48, 63, 64,
+};
+
 static uint64_t evt_code_for_fixed_ctr(uint8_t idx)
 {
 	return arch_events[fixed_events[idx]];
@@ -99,6 +113,22 @@ static uint32_t kvm_max_pmu_version(void)
 	return kvm_entry->eax & PMU_VERSION_MASK;
 }
 
+static uint32_t kvm_gp_ctr_bit_width(void)
+{
+	const struct kvm_cpuid_entry2 *kvm_entry;
+
+	kvm_entry = get_cpuid_entry(kvm_get_supported_cpuid(), 0xa, 0);
+	return (kvm_entry->eax & GP_WIDTH_MASK) >> GP_WIDTH_OFS_BIT;
+}
+
+static uint32_t kvm_fixed_ctr_bit_width(void)
+{
+	const struct kvm_cpuid_entry2 *kvm_entry;
+
+	kvm_entry = get_cpuid_entry(kvm_get_supported_cpuid(), 0xa, 0);
+	return (kvm_entry->edx & FIXED_WIDTH_MASK) >> FIXED_WIDTH_OFS_BIT;
+}
+
 static struct kvm_vcpu *new_vcpu(void *guest_code)
 {
 	struct kvm_vm *vm;
@@ -381,6 +411,50 @@ static void test_pmu_version_setup(struct kvm_vcpu *vcpu, uint8_t version)
 	vm_install_exception_handler(vcpu->vm, GP_VECTOR, guest_gp_handler);
 }
 
+static uint64_t test_ctrs_bit_width_setup(struct kvm_vcpu *vcpu,
+					  uint8_t bit_width,
+					  uint64_t perf_cap,
+					  uint32_t msr_base)
+{
+	struct kvm_cpuid_entry2 *entry;
+	bool fw_wr = perf_cap & PMU_CAP_FW_WRITES;
+	uint64_t kvm_width;
+	uint64_t value;
+
+	entry = vcpu_get_cpuid_entry(vcpu, 0xa);
+	if (msr_base != MSR_CORE_PERF_FIXED_CTR0) {
+		kvm_width = kvm_gp_ctr_bit_width();
+		entry->eax = (entry->eax & ~GP_WIDTH_MASK) |
+			(bit_width << GP_WIDTH_OFS_BIT);
+	} else {
+		kvm_width = kvm_fixed_ctr_bit_width();
+		entry->edx = (entry->edx & ~FIXED_WIDTH_MASK) |
+			(bit_width << FIXED_WIDTH_OFS_BIT);
+	}
+	TEST_REQUIRE(kvm_width > 31);
+
+	vcpu_set_cpuid(vcpu);
+	vcpu_set_msr(vcpu, MSR_IA32_PERF_CAPABILITIES, perf_cap);
+
+	/* No less than 32 bits and no greater than the host bitwidth */
+	bit_width = fw_wr ? max_t(int, 32, bit_width) : 32;
+	bit_width = min_t(int, bit_width, kvm_width);
+
+	/* Unconditionally set signed bit 31 for the case w/o FW_WRITES */
+	value = BIT_ULL(bit_width) | 0x1234567ull | BIT_ULL(31);
+	vcpu_args_set(vcpu, 4, msr_base, value, 1, 1);
+
+	if (fw_wr && msr_base != MSR_INTEL_ARCH_PMU_GPCTR) {
+		vm_install_exception_handler(vcpu->vm, GP_VECTOR,
+					     guest_gp_handler);
+		return GP_VECTOR;
+	} else if (msr_base == MSR_INTEL_ARCH_PMU_GPCTR) {
+		value = (s32)(value & (BIT_ULL(32) - 1));
+	}
+
+	return value & (BIT_ULL(bit_width) - 1);
+}
+
 static void intel_check_arch_event_is_unavl(uint8_t idx)
 {
 	const char *msg = "Unavailable arch event is counting.";
@@ -497,12 +571,43 @@ static void intel_test_pmu_version(void)
 	}
 }
 
+static void vcpu_run_bit_width(uint8_t bit_width, uint64_t perf_cap,
+			       uint32_t msr_base)
+{
+	const char *msg = "Fail to emulate counters' bit width.";
+	struct kvm_vcpu *vcpu;
+	uint64_t ret;
+
+	vcpu = new_vcpu(guest_wr_and_rd_msrs);
+	ret = test_ctrs_bit_width_setup(vcpu, bit_width, perf_cap, msr_base);
+	run_vcpu(vcpu, msg, first_uc_arg_equals, (void *)ret);
+	free_vcpu(vcpu);
+}
+
+static void intel_test_counters_bit_width(void)
+{
+	uint8_t i, j, k;
+
+	for (i = 0; i < ARRAY_SIZE(perf_caps); i++) {
+		for (j = 0; j < ARRAY_SIZE(msr_bases); j++) {
+			if (!(perf_caps[i] & PMU_CAP_FW_WRITES) &&
+			    msr_bases[j] == MSR_IA32_PMC0)
+				continue;
+
+			for (k = 0; k < ARRAY_SIZE(bit_widths); k++)
+				vcpu_run_bit_width(bit_widths[k], perf_caps[i],
+						   msr_bases[j]);
+		}
+	}
+}
+
 static void intel_test_pmu_cpuid(void)
 {
 	intel_test_arch_events();
 	intel_test_counters_num();
 	intel_test_fixed_counters();
 	intel_test_pmu_version();
+	intel_test_counters_bit_width();
 }
 
 int main(int argc, char *argv[])
-- 
2.40.0

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ