Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

xen/PMU: Intercept PMU-related MSR and APIC accesses

Provide interfaces for recognizing accesses to PMU-related MSRs and
LVTPC APIC and process these accesses in Xen PMU code.

(The interrupt handler performs XENPMU_flush right away in the beginning
since no PMU emulation is available. It will be added with a later patch).

Signed-off-by: Boris Ostrovsky <boris.ostrovsky@oracle.com>
Reviewed-by: David Vrabel <david.vrabel@citrix.com>
Signed-off-by: David Vrabel <david.vrabel@citrix.com>

authored by

Boris Ostrovsky and committed by
David Vrabel
6b08cd63 e27b72df

+109 -8
+4 -1
arch/x86/xen/apic.c
··· 7 7 #include <xen/xen.h> 8 8 #include <xen/interface/physdev.h> 9 9 #include "xen-ops.h" 10 + #include "pmu.h" 10 11 #include "smp.h" 11 12 12 13 static unsigned int xen_io_apic_read(unsigned apic, unsigned reg) ··· 73 72 74 73 static void xen_apic_write(u32 reg, u32 val) 75 74 { 76 - if (reg == APIC_LVTPC) 75 + if (reg == APIC_LVTPC) { 76 + (void)pmu_apic_update(reg); 77 77 return; 78 + } 78 79 79 80 /* Warn to see if there's any stray references */ 80 81 WARN(1,"register: %x, value: %x\n", reg, val);
+5 -6
arch/x86/xen/enlighten.c
··· 1031 1031 { 1032 1032 u64 val; 1033 1033 1034 + if (pmu_msr_read(msr, &val, err)) 1035 + return val; 1036 + 1034 1037 val = native_read_msr_safe(msr, err); 1035 1038 switch (msr) { 1036 1039 case MSR_IA32_APICBASE: ··· 1080 1077 Xen console noise. */ 1081 1078 1082 1079 default: 1083 - ret = native_write_msr_safe(msr, low, high); 1080 + if (!pmu_msr_write(msr, low, high, &ret)) 1081 + ret = native_write_msr_safe(msr, low, high); 1084 1082 } 1085 1083 1086 1084 return ret; 1087 - } 1088 - 1089 - unsigned long long xen_read_pmc(int counter) 1090 - { 1091 - return 0; 1092 1085 } 1093 1086 1094 1087 void xen_setup_shared_info(void)
+94 -1
arch/x86/xen/pmu.c
··· 51 51 /* Alias registers (0x4c1) for full-width writes to PMCs */ 52 52 #define MSR_PMC_ALIAS_MASK (~(MSR_IA32_PERFCTR0 ^ MSR_IA32_PMC0)) 53 53 54 + #define INTEL_PMC_TYPE_SHIFT 30 55 + 54 56 static __read_mostly int intel_num_arch_counters, intel_num_fixed_counters; 55 57 56 58 ··· 169 167 } 170 168 } 171 169 170 + bool pmu_msr_read(unsigned int msr, uint64_t *val, int *err) 171 + { 172 + 173 + if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) { 174 + if (is_amd_pmu_msr(msr)) { 175 + *val = native_read_msr_safe(msr, err); 176 + return true; 177 + } 178 + } else { 179 + int type, index; 180 + 181 + if (is_intel_pmu_msr(msr, &type, &index)) { 182 + *val = native_read_msr_safe(msr, err); 183 + return true; 184 + } 185 + } 186 + 187 + return false; 188 + } 189 + 190 + bool pmu_msr_write(unsigned int msr, uint32_t low, uint32_t high, int *err) 191 + { 192 + if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) { 193 + if (is_amd_pmu_msr(msr)) { 194 + *err = native_write_msr_safe(msr, low, high); 195 + return true; 196 + } 197 + } else { 198 + int type, index; 199 + 200 + if (is_intel_pmu_msr(msr, &type, &index)) { 201 + *err = native_write_msr_safe(msr, low, high); 202 + return true; 203 + } 204 + } 205 + 206 + return false; 207 + } 208 + 209 + static unsigned long long xen_amd_read_pmc(int counter) 210 + { 211 + uint32_t msr; 212 + int err; 213 + 214 + msr = amd_counters_base + (counter * amd_msr_step); 215 + return native_read_msr_safe(msr, &err); 216 + } 217 + 218 + static unsigned long long xen_intel_read_pmc(int counter) 219 + { 220 + int err; 221 + uint32_t msr; 222 + 223 + if (counter & (1<<INTEL_PMC_TYPE_SHIFT)) 224 + msr = MSR_CORE_PERF_FIXED_CTR0 + (counter & 0xffff); 225 + else 226 + msr = MSR_IA32_PERFCTR0 + counter; 227 + 228 + return native_read_msr_safe(msr, &err); 229 + } 230 + 231 + unsigned long long xen_read_pmc(int counter) 232 + { 233 + if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) 234 + return xen_amd_read_pmc(counter); 235 + else 236 + return xen_intel_read_pmc(counter); 237 + } 238 + 239 + int pmu_apic_update(uint32_t val) 240 + { 241 + int ret; 242 + struct xen_pmu_data *xenpmu_data = get_xenpmu_data(); 243 + 244 + if (!xenpmu_data) { 245 + pr_warn_once("%s: pmudata not initialized\n", __func__); 246 + return -EINVAL; 247 + } 248 + 249 + xenpmu_data->pmu.l.lapic_lvtpc = val; 250 + ret = HYPERVISOR_xenpmu_op(XENPMU_lvtpc_set, NULL); 251 + 252 + return ret; 253 + } 254 + 172 255 /* perf callbacks */ 173 256 static int xen_is_in_guest(void) 174 257 { ··· 326 239 327 240 irqreturn_t xen_pmu_irq_handler(int irq, void *dev_id) 328 241 { 329 - int ret = IRQ_NONE; 242 + int err, ret = IRQ_NONE; 330 243 struct pt_regs regs; 331 244 const struct xen_pmu_data *xenpmu_data = get_xenpmu_data(); 332 245 333 246 if (!xenpmu_data) { 334 247 pr_warn_once("%s: pmudata not initialized\n", __func__); 248 + return ret; 249 + } 250 + 251 + err = HYPERVISOR_xenpmu_op(XENPMU_flush, NULL); 252 + if (err) { 253 + pr_warn_once("%s: failed hypercall, err: %d\n", __func__, err); 335 254 return ret; 336 255 } 337 256
+4
arch/x86/xen/pmu.h
··· 7 7 void xen_pmu_init(int cpu); 8 8 void xen_pmu_finish(int cpu); 9 9 bool is_xen_pmu(int cpu); 10 + bool pmu_msr_read(unsigned int msr, uint64_t *val, int *err); 11 + bool pmu_msr_write(unsigned int msr, uint32_t low, uint32_t high, int *err); 12 + int pmu_apic_update(uint32_t reg); 13 + unsigned long long xen_read_pmc(int counter); 10 14 11 15 #endif /* __XEN_PMU_H */
+2
include/xen/interface/xenpmu.h
··· 20 20 #define XENPMU_feature_set 3 21 21 #define XENPMU_init 4 22 22 #define XENPMU_finish 5 23 + #define XENPMU_lvtpc_set 6 24 + #define XENPMU_flush 7 23 25 24 26 /* ` } */ 25 27