aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAli Mashtizadeh <ali@mashtizadeh.com>2026-06-05 23:48:53 +0000
committerMitchell Horne <mhorne@FreeBSD.org>2026-06-09 19:46:31 +0000
commitdded0ab415cc09eed506968366e383d406834823 (patch)
tree4e9b6cd81df2d2ab4cc06c39b6e5e2b009d73f67
parent8f9aabbdbcd55b25b698bd762e8693d43f295bbd (diff)
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
-rw-r--r--sys/dev/hwpmc/hwpmc_amd.c37
1 files 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
@@ -906,6 +908,37 @@ pmc_amd_initialize(void)
}
/*
+ * 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
* the prior default values that are only valid if we have the feature