On 9/1/2023 3:28 PM, Xiong Zhang wrote:
With Arch PMU V5, register CPUID.0AH.ECX indicates Fixed Counter
enumeration. It is a bit mask which enumerates the supported Fixed
counters.
FxCtrl[i]_is_supported := ECX[i] || (EDX[4:0] > i)
where EDX[4:0] is Number of continuous fixed-function performance
counters starting from 0 (if version ID > 1).
Here ECX and EDX[4:0] should satisfy the following consistency:
1. if 1 < pmu_version < 5, ECX == 0;
2. if pmu_version == 5 && edx[4:0] == 0, ECX[bit 0] == 0
3. if pmu_version == 5 && edx[4:0] > 0,
ecx & ((1 << edx[4:0]) - 1) == (1 << edx[4:0]) -1
Otherwise it is mess to decide whether a fixed counter is supported
or not. i.e. pmu_version = 5, edx[4:0] = 3, ecx = 0x10, it is hard
to decide whether fixed counters 0 ~ 2 are supported or not.
User can call SET_CPUID2 ioctl to set guest CPUID.0AH, this commit
adds a check to guarantee ecx and edx consistency specified by user.
Once user specifies an un-consistency value, KVM can return an
error to user and drop user setting, or correct the un-consistency
data and accept the corrected data, this commit chooses to
return an error to user.
Signed-off-by: Xiong Zhang <xiong.y.zhang@xxxxxxxxx>
---
arch/x86/kvm/cpuid.c | 27 +++++++++++++++++++++++++++
1 file changed, 27 insertions(+)
diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
index e961e9a05847..95dc5e8847e0 100644
--- a/arch/x86/kvm/cpuid.c
+++ b/arch/x86/kvm/cpuid.c
@@ -150,6 +150,33 @@ static int kvm_check_cpuid(struct kvm_vcpu *vcpu,
return -EINVAL;
}
+ best = cpuid_entry2_find(entries, nent, 0xa,
+ KVM_CPUID_INDEX_NOT_SIGNIFICANT);
+ if (best && vcpu->kvm->arch.enable_pmu) {
+ union cpuid10_eax eax;
+ union cpuid10_edx edx;
Remove the redundant space before edx.
+
+ eax.full = best->eax;
+ edx.full = best->edx;
+
We may add SDM quotes as comments here. That makes reader to understand
the logic easily.
+ if (eax.split.version_id > 1 &&
+ eax.split.version_id < 5 &&
+ best->ecx != 0) {
+ return -EINVAL;
+ } else if (eax.split.version_id >= 5) {
+ int fixed_count = edx.split.num_counters_fixed;
+
+ if (fixed_count == 0 && (best->ecx & 0x1)) {
+ return -EINVAL;
+ } else if (fixed_count > 0) {
+ int low_fixed_mask = (1 << fixed_count) - 1;
+
+ if ((best->ecx & low_fixed_mask) != low_fixed_mask)
+ return -EINVAL;
+ }
+ }
+ }
+
/*
* Exposing dynamic xfeatures to the guest requires additional
* enabling in the FPU, e.g. to expand the guest XSAVE state size.