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
This commit is contained in:
committed by
Mitchell Horne
parent
8f9aabbdbc
commit
dded0ab415
@@ -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, ®);
|
||||
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
|
||||
|
||||
Reference in New Issue
Block a user