git: dded0ab415cc - main - hwpmc: Disable AMD PMCs if in an unsupported VM

From: Mitchell Horne <mhorne_at_FreeBSD.org>
Date: Tue, 09 Jun 2026 19:46:34 UTC
The branch main has been updated by mhorne:

URL: https://cgit.FreeBSD.org/src/commit/?id=dded0ab415cc09eed506968366e383d406834823

commit dded0ab415cc09eed506968366e383d406834823
Author:     Ali Mashtizadeh <ali@mashtizadeh.com>
AuthorDate: 2026-06-05 23:48:53 +0000
Commit:     Mitchell Horne <mhorne@FreeBSD.org>
CommitDate: 2026-06-09 19:46:31 +0000

    hwpmc: Disable AMD PMCs if in an unsupported VM
    
    AMD does not have a CPUID bit to indicate the lack of K8 PMCs.  If all
    other PMC features are not present we should test an event selector to
    see if it stores and returns a value.  If the VM is implemented
    correctly, this should result in a #GP on the initial wrmsr_safe.  Bhyve
    and a few other VMs ignore writes, so I got one step further and test
    that it retains the OS and USR bits.
    
    Tested on Zen 5 native and a Zen 5 Bhyve virtual machine.  This code
    should not run on any recent hardware, except in a VM, as it checks that
    the core counter extension is missing.
    
    PR:             268943
    Reported by:    Sandipan Das, John F. Carr <jfc@mit.edu>
    Reviewed by:    mhorne, imp
    Sponsored by:   Netflix
    MFC after:      1 week
    Pull Request:   https://github.com/freebsd/freebsd-src/pull/2272/changes
---
 sys/dev/hwpmc/hwpmc_amd.c | 37 +++++++++++++++++++++++++++++++++++--
 1 file changed, 35 insertions(+), 2 deletions(-)

diff --git a/sys/dev/hwpmc/hwpmc_amd.c b/sys/dev/hwpmc/hwpmc_amd.c
index 299021494716..e76bdef118d5 100644
--- a/sys/dev/hwpmc/hwpmc_amd.c
+++ b/sys/dev/hwpmc/hwpmc_amd.c
@@ -869,12 +869,14 @@ amd_pcpu_fini(struct pmc_mdep *md, int cpu)
 struct pmc_mdep *
 pmc_amd_initialize(void)
 {
+	struct amd_descr *d;
 	struct pmc_classdep *pcd;
 	struct pmc_mdep *pmc_mdep;
+	uint64_t reg;
 	enum pmc_cputype cputype;
-	int error, i, ncpus, nclasses;
+	int ncpus, nclasses, i;
 	int family, model, stepping;
-	struct amd_descr *d;
+	int error;
 
 	/*
 	 * The presence of hardware performance counters on the AMD
@@ -905,6 +907,37 @@ pmc_amd_initialize(void)
 		return (NULL);
 	}
 
+	/*
+	 * Unforunately, there is no way to communicate that the original four
+	 * core counters are disabled through CPUIDs alone.  We attempt to
+	 * write and read back the MSR to validate that it is working.
+	 *
+	 * Referenced the BIOS and Kernel Developer Guide for AMD Athlon 64 and
+	 * AMD Opteron Processors 26094 Rev. 3.24 January, 2005 to ensure these
+	 * fields are valid.
+	 */
+	if ((amd_feature2 & AMDID2_PCXC) == 0) {
+		error = wrmsr_safe(AMD_PMC_EVSEL_0, AMD_PMC_OS | AMD_PMC_USR);
+		if (error != 0) {
+			printf("hwpmc: AMD evsel 0 wrmsr failed!\n");
+			return (NULL);
+		}
+
+		error = rdmsr_safe(AMD_PMC_EVSEL_0, &reg);
+		if (error != 0) {
+			printf("hwpmc: AMD evsel 0 rdmsr failed!\n");
+			return (NULL);
+		}
+
+		if (reg == 0) {
+			printf("hwpmc: AMD evsel returned invalid value! "
+			    "You may be in a VM without PMC support.\n");
+			return (NULL);
+		}
+
+		wrmsr(AMD_PMC_EVSEL_0, 0);
+	}
+
 	/*
 	 * From PPR for AMD Family 1Ah, a new cpuid leaf specifies the maximum
 	 * number of PMCs of each type.  If we do not have that leaf, we use