diff options
| author | Ali Mashtizadeh <ali@mashtizadeh.com> | 2026-06-05 23:48:53 +0000 |
|---|---|---|
| committer | Mitchell Horne <mhorne@FreeBSD.org> | 2026-06-09 19:46:31 +0000 |
| commit | dded0ab415cc09eed506968366e383d406834823 (patch) | |
| tree | 4e9b6cd81df2d2ab4cc06c39b6e5e2b009d73f67 | |
| parent | 8f9aabbdbcd55b25b698bd762e8693d43f295bbd (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.c | 37 |
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, ®); + 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 |
