|
@@ -2182,6 +2182,41 @@ static void intel_snb_check_microcode(void)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * Under certain circumstances, access certain MSR may cause #GP.
|
|
|
+ * The function tests if the input MSR can be safely accessed.
|
|
|
+ */
|
|
|
+static bool check_msr(unsigned long msr, u64 mask)
|
|
|
+{
|
|
|
+ u64 val_old, val_new, val_tmp;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Read the current value, change it and read it back to see if it
|
|
|
+ * matches, this is needed to detect certain hardware emulators
|
|
|
+ * (qemu/kvm) that don't trap on the MSR access and always return 0s.
|
|
|
+ */
|
|
|
+ if (rdmsrl_safe(msr, &val_old))
|
|
|
+ return false;
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Only change the bits which can be updated by wrmsrl.
|
|
|
+ */
|
|
|
+ val_tmp = val_old ^ mask;
|
|
|
+ if (wrmsrl_safe(msr, val_tmp) ||
|
|
|
+ rdmsrl_safe(msr, &val_new))
|
|
|
+ return false;
|
|
|
+
|
|
|
+ if (val_new != val_tmp)
|
|
|
+ return false;
|
|
|
+
|
|
|
+ /* Here it's sure that the MSR can be safely accessed.
|
|
|
+ * Restore the old value and return.
|
|
|
+ */
|
|
|
+ wrmsrl(msr, val_old);
|
|
|
+
|
|
|
+ return true;
|
|
|
+}
|
|
|
+
|
|
|
static __init void intel_sandybridge_quirk(void)
|
|
|
{
|
|
|
x86_pmu.check_microcode = intel_snb_check_microcode;
|
|
@@ -2271,7 +2306,8 @@ __init int intel_pmu_init(void)
|
|
|
union cpuid10_ebx ebx;
|
|
|
struct event_constraint *c;
|
|
|
unsigned int unused;
|
|
|
- int version;
|
|
|
+ struct extra_reg *er;
|
|
|
+ int version, i;
|
|
|
|
|
|
if (!cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON)) {
|
|
|
switch (boot_cpu_data.x86) {
|
|
@@ -2577,6 +2613,34 @@ __init int intel_pmu_init(void)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ /*
|
|
|
+ * Access LBR MSR may cause #GP under certain circumstances.
|
|
|
+ * E.g. KVM doesn't support LBR MSR
|
|
|
+ * Check all LBT MSR here.
|
|
|
+ * Disable LBR access if any LBR MSRs can not be accessed.
|
|
|
+ */
|
|
|
+ if (x86_pmu.lbr_nr && !check_msr(x86_pmu.lbr_tos, 0x3UL))
|
|
|
+ x86_pmu.lbr_nr = 0;
|
|
|
+ for (i = 0; i < x86_pmu.lbr_nr; i++) {
|
|
|
+ if (!(check_msr(x86_pmu.lbr_from + i, 0xffffUL) &&
|
|
|
+ check_msr(x86_pmu.lbr_to + i, 0xffffUL)))
|
|
|
+ x86_pmu.lbr_nr = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Access extra MSR may cause #GP under certain circumstances.
|
|
|
+ * E.g. KVM doesn't support offcore event
|
|
|
+ * Check all extra_regs here.
|
|
|
+ */
|
|
|
+ if (x86_pmu.extra_regs) {
|
|
|
+ for (er = x86_pmu.extra_regs; er->msr; er++) {
|
|
|
+ er->extra_msr_access = check_msr(er->msr, 0x1ffUL);
|
|
|
+ /* Disable LBR select mapping */
|
|
|
+ if ((er->idx == EXTRA_REG_LBR) && !er->extra_msr_access)
|
|
|
+ x86_pmu.lbr_sel_map = NULL;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
/* Support full width counters using alternative MSR range */
|
|
|
if (x86_pmu.intel_cap.full_width_write) {
|
|
|
x86_pmu.max_period = x86_pmu.cntval_mask;
|