@@ -549,6 +549,9 @@ struct kvm_pmu {
* redundant check before cleanup if guest don't use vPMU at all.
*/
u8 event_count;
+
+ /* Guest arch lbr depth supported by KVM. */
+ u64 kvm_arch_lbr_depth;
};
struct kvm_pmu_ops;
@@ -182,6 +182,10 @@ static bool intel_pmu_is_valid_lbr_msr(struct kvm_vcpu *vcpu, u32 index)
(index == MSR_LBR_SELECT || index == MSR_LBR_TOS))
return true;
+ if (index == MSR_ARCH_LBR_DEPTH)
+ return kvm_cpu_cap_has(X86_FEATURE_ARCH_LBR) &&
+ guest_cpuid_has(vcpu, X86_FEATURE_ARCH_LBR);
+
if ((index >= records->from && index < records->from + records->nr) ||
(index >= records->to && index < records->to + records->nr))
return true;
@@ -349,6 +353,7 @@ static int intel_pmu_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
{
struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
struct kvm_pmc *pmc;
+ struct lbr_desc *lbr_desc = vcpu_to_lbr_desc(vcpu);
u32 msr = msr_info->index;
switch (msr) {
@@ -373,6 +378,9 @@ static int intel_pmu_get_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
case MSR_PEBS_DATA_CFG:
msr_info->data = pmu->pebs_data_cfg;
return 0;
+ case MSR_ARCH_LBR_DEPTH:
+ msr_info->data = lbr_desc->records.nr;
+ return 0;
default:
if ((pmc = get_gp_pmc(pmu, msr, MSR_IA32_PERFCTR0)) ||
(pmc = get_gp_pmc(pmu, msr, MSR_IA32_PMC0))) {
@@ -399,6 +407,7 @@ static int intel_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
{
struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
struct kvm_pmc *pmc;
+ struct lbr_desc *lbr_desc = vcpu_to_lbr_desc(vcpu);
u32 msr = msr_info->index;
u64 data = msr_info->data;
u64 reserved_bits;
@@ -456,6 +465,24 @@ static int intel_pmu_set_msr(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
return 0;
}
break;
+ case MSR_ARCH_LBR_DEPTH:
+ if (!pmu->kvm_arch_lbr_depth && !msr_info->host_initiated)
+ return 1;
+ /*
+ * When guest/host depth are different, the handling would be tricky,
+ * so only max depth is supported for both host and guest.
+ */
+ if (data != pmu->kvm_arch_lbr_depth)
+ return 1;
+
+ lbr_desc->records.nr = data;
+ /*
+ * Writing depth MSR from guest could either setting the
+ * MSR or resetting the LBR records with the side-effect.
+ */
+ if (kvm_cpu_cap_has(X86_FEATURE_ARCH_LBR))
+ wrmsrl(MSR_ARCH_LBR_DEPTH, lbr_desc->records.nr);
+ return 0;
default:
if ((pmc = get_gp_pmc(pmu, msr, MSR_IA32_PERFCTR0)) ||
(pmc = get_gp_pmc(pmu, msr, MSR_IA32_PMC0))) {
@@ -506,6 +533,32 @@ static void setup_fixed_pmc_eventsel(struct kvm_pmu *pmu)
}
}
+static bool cpuid_enable_lbr(struct kvm_vcpu *vcpu)
+{
+ struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
+ struct kvm_cpuid_entry2 *entry;
+ int depth_bit;
+
+ if (!kvm_cpu_cap_has(X86_FEATURE_ARCH_LBR))
+ return !static_cpu_has(X86_FEATURE_ARCH_LBR) &&
+ cpuid_model_is_consistent(vcpu);
+
+ pmu->kvm_arch_lbr_depth = 0;
+ if (!guest_cpuid_has(vcpu, X86_FEATURE_ARCH_LBR))
+ return false;
+
+ entry = kvm_find_cpuid_entry(vcpu, 0x1C);
+ if (!entry)
+ return false;
+
+ depth_bit = fls(cpuid_eax(0x1C) & 0xff);
+ if ((entry->eax & 0xff) != (1 << (depth_bit - 1)))
+ return false;
+
+ pmu->kvm_arch_lbr_depth = depth_bit * 8;
+ return true;
+}
+
static void intel_pmu_refresh(struct kvm_vcpu *vcpu)
{
struct kvm_pmu *pmu = vcpu_to_pmu(vcpu);
@@ -590,8 +643,8 @@ static void intel_pmu_refresh(struct kvm_vcpu *vcpu)
INTEL_PMC_MAX_GENERIC, pmu->nr_arch_fixed_counters);
perf_capabilities = vcpu_get_perf_capabilities(vcpu);
- if (cpuid_model_is_consistent(vcpu) &&
- (perf_capabilities & PMU_CAP_LBR_FMT))
+ if ((perf_capabilities & PMU_CAP_LBR_FMT) &&
+ cpuid_enable_lbr(vcpu))
x86_perf_get_lbr(&lbr_desc->records);
else
lbr_desc->records.nr = 0;