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

Configure Feed

Select the types of activity you want to include in your feed.

perf/x86/core: Add APIs to switch to/from mediated PMI vector (for KVM)

Add APIs (exported only for KVM) to switch PMIs to the dedicated mediated
PMU IRQ vector when loading guest context, and back to perf's standard NMI
when the guest context is put. I.e. route PMIs to
PERF_GUEST_MEDIATED_PMI_VECTOR when the guest context is active, and to
NMIs while the host context is active.

While running with guest context loaded, ignore all NMIs (in perf). Any
NMI that arrives while the LVTPC points at the mediated PMU IRQ vector
can't possibly be due to a host perf event.

Signed-off-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org>
Link: https://patch.msgid.link/20251206001720.468579-10-seanjc@google.com

authored by

Sean Christopherson and committed by
Peter Zijlstra
560ac136 a05385d8

+37
+32
arch/x86/events/core.c
··· 56 56 .pmu = &pmu, 57 57 }; 58 58 59 + static DEFINE_PER_CPU(bool, guest_lvtpc_loaded); 60 + 59 61 DEFINE_STATIC_KEY_FALSE(rdpmc_never_available_key); 60 62 DEFINE_STATIC_KEY_FALSE(rdpmc_always_available_key); 61 63 DEFINE_STATIC_KEY_FALSE(perf_is_hybrid); ··· 1762 1760 apic_write(APIC_LVTPC, APIC_DM_NMI); 1763 1761 } 1764 1762 1763 + #ifdef CONFIG_PERF_GUEST_MEDIATED_PMU 1764 + void perf_load_guest_lvtpc(u32 guest_lvtpc) 1765 + { 1766 + u32 masked = guest_lvtpc & APIC_LVT_MASKED; 1767 + 1768 + apic_write(APIC_LVTPC, 1769 + APIC_DM_FIXED | PERF_GUEST_MEDIATED_PMI_VECTOR | masked); 1770 + this_cpu_write(guest_lvtpc_loaded, true); 1771 + } 1772 + EXPORT_SYMBOL_FOR_MODULES(perf_load_guest_lvtpc, "kvm"); 1773 + 1774 + void perf_put_guest_lvtpc(void) 1775 + { 1776 + this_cpu_write(guest_lvtpc_loaded, false); 1777 + apic_write(APIC_LVTPC, APIC_DM_NMI); 1778 + } 1779 + EXPORT_SYMBOL_FOR_MODULES(perf_put_guest_lvtpc, "kvm"); 1780 + #endif /* CONFIG_PERF_GUEST_MEDIATED_PMU */ 1781 + 1765 1782 static int 1766 1783 perf_event_nmi_handler(unsigned int cmd, struct pt_regs *regs) 1767 1784 { 1768 1785 u64 start_clock; 1769 1786 u64 finish_clock; 1770 1787 int ret; 1788 + 1789 + /* 1790 + * Ignore all NMIs when the CPU's LVTPC is configured to route PMIs to 1791 + * PERF_GUEST_MEDIATED_PMI_VECTOR, i.e. when an NMI time can't be due 1792 + * to a PMI. Attempting to handle a PMI while the guest's context is 1793 + * loaded will generate false positives and clobber guest state. Note, 1794 + * the LVTPC is switched to/from the dedicated mediated PMI IRQ vector 1795 + * while host events are quiesced. 1796 + */ 1797 + if (this_cpu_read(guest_lvtpc_loaded)) 1798 + return NMI_DONE; 1771 1799 1772 1800 /* 1773 1801 * All PMUs/events that share this PMI handler should make sure to
+5
arch/x86/include/asm/perf_event.h
··· 759 759 static inline void perf_check_microcode(void) { } 760 760 #endif 761 761 762 + #ifdef CONFIG_PERF_GUEST_MEDIATED_PMU 763 + extern void perf_load_guest_lvtpc(u32 guest_lvtpc); 764 + extern void perf_put_guest_lvtpc(void); 765 + #endif 766 + 762 767 #if defined(CONFIG_PERF_EVENTS) && defined(CONFIG_CPU_SUP_INTEL) 763 768 extern struct perf_guest_switch_msr *perf_guest_get_msrs(int *nr, void *data); 764 769 extern void x86_perf_get_lbr(struct x86_pmu_lbr *lbr);