From ca4bb99d013df4db50758ffb1d1b2dfcc3915778 Mon Sep 17 00:00:00 2001 From: Colton Lewis Date: Wed, 13 Nov 2024 19:01:51 +0000 Subject: [PATCH 01/20] perf/arm: Drop unused functions ANBZ: #45489 commit e33ed362cf9e35db6082f7a776b7e8d557407e19 upstream. For ARM's implementation, perf_instruction_pointer() and perf_misc_flags() are equivalent to the generic versions in include/linux/perf_event.h so arch/arm doesn't need to provide its own versions. Drop them here. Signed-off-by: Colton Lewis Signed-off-by: Ingo Molnar Reviewed-by: Oliver Upton Acked-by: Will Deacon Link: https://lore.kernel.org/r/20241113190156.2145593-2-coltonlewis@google.com Signed-off-by: Jason Zeng --- arch/arm/include/asm/perf_event.h | 7 ------- arch/arm/kernel/perf_callchain.c | 17 ----------------- 2 files changed, 24 deletions(-) diff --git a/arch/arm/include/asm/perf_event.h b/arch/arm/include/asm/perf_event.h index bdbc1e590891..c08f16f2e243 100644 --- a/arch/arm/include/asm/perf_event.h +++ b/arch/arm/include/asm/perf_event.h @@ -8,13 +8,6 @@ #ifndef __ARM_PERF_EVENT_H__ #define __ARM_PERF_EVENT_H__ -#ifdef CONFIG_PERF_EVENTS -struct pt_regs; -extern unsigned long perf_instruction_pointer(struct pt_regs *regs); -extern unsigned long perf_misc_flags(struct pt_regs *regs); -#define perf_misc_flags(regs) perf_misc_flags(regs) -#endif - #define perf_arch_fetch_caller_regs(regs, __ip) { \ (regs)->ARM_pc = (__ip); \ frame_pointer((regs)) = (unsigned long) __builtin_frame_address(0); \ diff --git a/arch/arm/kernel/perf_callchain.c b/arch/arm/kernel/perf_callchain.c index 1d230ac9d0eb..a2601b1ef318 100644 --- a/arch/arm/kernel/perf_callchain.c +++ b/arch/arm/kernel/perf_callchain.c @@ -96,20 +96,3 @@ perf_callchain_kernel(struct perf_callchain_entry_ctx *entry, struct pt_regs *re arm_get_current_stackframe(regs, &fr); walk_stackframe(&fr, callchain_trace, entry); } - -unsigned long perf_instruction_pointer(struct pt_regs *regs) -{ - return instruction_pointer(regs); -} - -unsigned long perf_misc_flags(struct pt_regs *regs) -{ - int misc = 0; - - if (user_mode(regs)) - misc |= PERF_RECORD_MISC_USER; - else - misc |= PERF_RECORD_MISC_KERNEL; - - return misc; -} -- Gitee From 76502725682a1245abf9813b795966b63a4084a5 Mon Sep 17 00:00:00 2001 From: Colton Lewis Date: Wed, 13 Nov 2024 19:01:52 +0000 Subject: [PATCH 02/20] perf/core: Hoist perf_instruction_pointer() and perf_misc_flags() ANBZ: #45489 commit 04782e63917dbcb60932fe93df52c4a4e3859d07 upstream. For clarity, rename the arch-specific definitions of these functions to perf_arch_* to denote they are arch-specifc. Define the generic-named functions in one place where they can call the arch-specific ones as needed. Signed-off-by: Colton Lewis Signed-off-by: Ingo Molnar Reviewed-by: Oliver Upton Acked-by: Thomas Richter Acked-by: Mark Rutland Acked-by: Madhavan Srinivasan Acked-by: Kan Liang Link: https://lore.kernel.org/r/20241113190156.2145593-3-coltonlewis@google.com [jz: - also change function names for riscv and sw_64 - fix an arm64 compilation issue caused by incomplete change of perf_misc_flags -> perf_arch_misc_flags in arch/arm64/include/asm/perf_event.h. This causes Anolis CICD failure. Since this line will eventually be removed in later commit, so fix it here is safe.] Signed-off-by: Jason Zeng --- arch/arm64/include/asm/perf_event.h | 6 +++--- arch/arm64/kernel/perf_callchain.c | 4 ++-- arch/powerpc/include/asm/perf_event_server.h | 6 +++--- arch/powerpc/perf/core-book3s.c | 4 ++-- arch/riscv/include/asm/perf_event.h | 6 +++--- arch/riscv/kernel/perf_callchain.c | 4 ++-- arch/s390/include/asm/perf_event.h | 6 +++--- arch/s390/kernel/perf_event.c | 4 ++-- arch/sw_64/include/asm/perf_event.h | 6 +++--- arch/sw_64/kernel/perf_callchain.c | 4 ++-- arch/x86/events/core.c | 4 ++-- arch/x86/include/asm/perf_event.h | 10 +++++----- include/linux/perf_event.h | 9 ++++++--- kernel/events/core.c | 10 ++++++++++ 14 files changed, 48 insertions(+), 35 deletions(-) diff --git a/arch/arm64/include/asm/perf_event.h b/arch/arm64/include/asm/perf_event.h index eb7071c9eb34..d1e753f16d3b 100644 --- a/arch/arm64/include/asm/perf_event.h +++ b/arch/arm64/include/asm/perf_event.h @@ -11,9 +11,9 @@ #ifdef CONFIG_PERF_EVENTS struct pt_regs; -extern unsigned long perf_instruction_pointer(struct pt_regs *regs); -extern unsigned long perf_misc_flags(struct pt_regs *regs); -#define perf_misc_flags(regs) perf_misc_flags(regs) +extern unsigned long perf_arch_instruction_pointer(struct pt_regs *regs); +extern unsigned long perf_arch_misc_flags(struct pt_regs *regs); +#define perf_arch_misc_flags(regs) perf_arch_misc_flags(regs) #define perf_arch_bpf_user_pt_regs(regs) ®s->user_regs #endif diff --git a/arch/arm64/kernel/perf_callchain.c b/arch/arm64/kernel/perf_callchain.c index 6d157f32187b..62a9200c044e 100644 --- a/arch/arm64/kernel/perf_callchain.c +++ b/arch/arm64/kernel/perf_callchain.c @@ -149,7 +149,7 @@ void perf_callchain_kernel(struct perf_callchain_entry_ctx *entry, arch_stack_walk(callchain_trace, entry, current, regs); } -unsigned long perf_instruction_pointer(struct pt_regs *regs) +unsigned long perf_arch_instruction_pointer(struct pt_regs *regs) { if (perf_guest_state()) return perf_guest_get_ip(); @@ -157,7 +157,7 @@ unsigned long perf_instruction_pointer(struct pt_regs *regs) return instruction_pointer(regs); } -unsigned long perf_misc_flags(struct pt_regs *regs) +unsigned long perf_arch_misc_flags(struct pt_regs *regs) { unsigned int guest_state = perf_guest_state(); int misc = 0; diff --git a/arch/powerpc/include/asm/perf_event_server.h b/arch/powerpc/include/asm/perf_event_server.h index e2221d29fdf9..b604170819c6 100644 --- a/arch/powerpc/include/asm/perf_event_server.h +++ b/arch/powerpc/include/asm/perf_event_server.h @@ -101,8 +101,8 @@ struct power_pmu { int __init register_power_pmu(struct power_pmu *pmu); struct pt_regs; -extern unsigned long perf_misc_flags(struct pt_regs *regs); -extern unsigned long perf_instruction_pointer(struct pt_regs *regs); +extern unsigned long perf_arch_misc_flags(struct pt_regs *regs); +extern unsigned long perf_arch_instruction_pointer(struct pt_regs *regs); extern unsigned long int read_bhrb(int n); /* @@ -110,7 +110,7 @@ extern unsigned long int read_bhrb(int n); * if we have hardware PMU support. */ #ifdef CONFIG_PPC_PERF_CTRS -#define perf_misc_flags(regs) perf_misc_flags(regs) +#define perf_arch_misc_flags(regs) perf_arch_misc_flags(regs) #endif /* diff --git a/arch/powerpc/perf/core-book3s.c b/arch/powerpc/perf/core-book3s.c index bc173628238b..0ce4397b6943 100644 --- a/arch/powerpc/perf/core-book3s.c +++ b/arch/powerpc/perf/core-book3s.c @@ -2363,7 +2363,7 @@ static void record_and_restart(struct perf_event *event, unsigned long val, * Called from generic code to get the misc flags (i.e. processor mode) * for an event_id. */ -unsigned long perf_misc_flags(struct pt_regs *regs) +unsigned long perf_arch_misc_flags(struct pt_regs *regs) { u32 flags = perf_get_misc_flags(regs); @@ -2377,7 +2377,7 @@ unsigned long perf_misc_flags(struct pt_regs *regs) * Called from generic code to get the instruction pointer * for an event_id. */ -unsigned long perf_instruction_pointer(struct pt_regs *regs) +unsigned long perf_arch_instruction_pointer(struct pt_regs *regs) { unsigned long siar = mfspr(SPRN_SIAR); diff --git a/arch/riscv/include/asm/perf_event.h b/arch/riscv/include/asm/perf_event.h index 38926b4a902d..196d607afc33 100644 --- a/arch/riscv/include/asm/perf_event.h +++ b/arch/riscv/include/asm/perf_event.h @@ -10,9 +10,9 @@ #ifdef CONFIG_PERF_EVENTS #include -extern unsigned long perf_instruction_pointer(struct pt_regs *regs); -extern unsigned long perf_misc_flags(struct pt_regs *regs); -#define perf_misc_flags(regs) perf_misc_flags(regs) +extern unsigned long perf_arch_instruction_pointer(struct pt_regs *regs); +extern unsigned long perf_arch_misc_flags(struct pt_regs *regs); +#define perf_arch_misc_flags(regs) perf_arch_misc_flags(regs) #define perf_arch_bpf_user_pt_regs(regs) (struct user_regs_struct *)regs #define perf_arch_fetch_caller_regs(regs, __ip) { \ diff --git a/arch/riscv/kernel/perf_callchain.c b/arch/riscv/kernel/perf_callchain.c index c2c81a80f816..397afe5468e4 100644 --- a/arch/riscv/kernel/perf_callchain.c +++ b/arch/riscv/kernel/perf_callchain.c @@ -47,7 +47,7 @@ void perf_callchain_kernel(struct perf_callchain_entry_ctx *entry, walk_stackframe(NULL, regs, fill_callchain, entry); } -unsigned long perf_instruction_pointer(struct pt_regs *regs) +unsigned long perf_arch_instruction_pointer(struct pt_regs *regs) { if (perf_guest_state()) return perf_guest_get_ip(); @@ -55,7 +55,7 @@ unsigned long perf_instruction_pointer(struct pt_regs *regs) return instruction_pointer(regs); } -unsigned long perf_misc_flags(struct pt_regs *regs) +unsigned long perf_arch_misc_flags(struct pt_regs *regs) { unsigned int guest_state = perf_guest_state(); unsigned long misc = 0; diff --git a/arch/s390/include/asm/perf_event.h b/arch/s390/include/asm/perf_event.h index 66aff768f815..cc5dbf288b2b 100644 --- a/arch/s390/include/asm/perf_event.h +++ b/arch/s390/include/asm/perf_event.h @@ -37,9 +37,9 @@ extern ssize_t cpumf_events_sysfs_show(struct device *dev, /* Perf callbacks */ struct pt_regs; -extern unsigned long perf_instruction_pointer(struct pt_regs *regs); -extern unsigned long perf_misc_flags(struct pt_regs *regs); -#define perf_misc_flags(regs) perf_misc_flags(regs) +extern unsigned long perf_arch_instruction_pointer(struct pt_regs *regs); +extern unsigned long perf_arch_misc_flags(struct pt_regs *regs); +#define perf_arch_misc_flags(regs) perf_arch_misc_flags(regs) #define perf_arch_bpf_user_pt_regs(regs) ®s->user_regs /* Perf pt_regs extension for sample-data-entry indicators */ diff --git a/arch/s390/kernel/perf_event.c b/arch/s390/kernel/perf_event.c index c27321cb0969..f87f19b45fbf 100644 --- a/arch/s390/kernel/perf_event.c +++ b/arch/s390/kernel/perf_event.c @@ -54,7 +54,7 @@ static unsigned long instruction_pointer_guest(struct pt_regs *regs) return sie_block(regs)->gpsw.addr; } -unsigned long perf_instruction_pointer(struct pt_regs *regs) +unsigned long perf_arch_instruction_pointer(struct pt_regs *regs) { return is_in_guest(regs) ? instruction_pointer_guest(regs) : instruction_pointer(regs); @@ -81,7 +81,7 @@ static unsigned long perf_misc_flags_sf(struct pt_regs *regs) return flags; } -unsigned long perf_misc_flags(struct pt_regs *regs) +unsigned long perf_arch_misc_flags(struct pt_regs *regs) { /* Check if the cpum_sf PMU has created the pt_regs structure. * In this case, perf misc flags can be easily extracted. Otherwise, diff --git a/arch/sw_64/include/asm/perf_event.h b/arch/sw_64/include/asm/perf_event.h index 391ab1c6d621..a8c9d93cb8f3 100644 --- a/arch/sw_64/include/asm/perf_event.h +++ b/arch/sw_64/include/asm/perf_event.h @@ -13,9 +13,9 @@ #ifdef CONFIG_PERF_EVENTS struct pt_regs; -extern unsigned long perf_instruction_pointer(struct pt_regs *regs); -extern unsigned long perf_misc_flags(struct pt_regs *regs); -#define perf_misc_flags(regs) perf_misc_flags(regs) +extern unsigned long perf_arch_instruction_pointer(struct pt_regs *regs); +extern unsigned long perf_arch_misc_flags(struct pt_regs *regs); +#define perf_arch_misc_flags(regs) perf_arch_misc_flags(regs) #define perf_arch_bpf_user_pt_regs(regs) ®s->user_regs #endif diff --git a/arch/sw_64/kernel/perf_callchain.c b/arch/sw_64/kernel/perf_callchain.c index 0c0a4c180919..af1e897dd273 100644 --- a/arch/sw_64/kernel/perf_callchain.c +++ b/arch/sw_64/kernel/perf_callchain.c @@ -113,7 +113,7 @@ void perf_callchain_kernel(struct perf_callchain_entry_ctx *entry, */ #undef is_in_guest -unsigned long perf_instruction_pointer(struct pt_regs *regs) +unsigned long perf_arch_instruction_pointer(struct pt_regs *regs) { if (perf_guest_state()) return perf_guest_get_ip(); @@ -121,7 +121,7 @@ unsigned long perf_instruction_pointer(struct pt_regs *regs) return instruction_pointer(regs); } -unsigned long perf_misc_flags(struct pt_regs *regs) +unsigned long perf_arch_misc_flags(struct pt_regs *regs) { unsigned int guest_state = perf_guest_state(); int misc = 0; diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c index e4098c502cc6..a7cd778e2e05 100644 --- a/arch/x86/events/core.c +++ b/arch/x86/events/core.c @@ -3108,7 +3108,7 @@ static unsigned long code_segment_base(struct pt_regs *regs) return 0; } -unsigned long perf_instruction_pointer(struct pt_regs *regs) +unsigned long perf_arch_instruction_pointer(struct pt_regs *regs) { if (perf_guest_state()) return perf_guest_get_ip(); @@ -3116,7 +3116,7 @@ unsigned long perf_instruction_pointer(struct pt_regs *regs) return regs->ip + code_segment_base(regs); } -unsigned long perf_misc_flags(struct pt_regs *regs) +unsigned long perf_arch_misc_flags(struct pt_regs *regs) { unsigned int guest_state = perf_guest_state(); int misc = 0; diff --git a/arch/x86/include/asm/perf_event.h b/arch/x86/include/asm/perf_event.h index 38f25bccec47..e87f5032aa79 100644 --- a/arch/x86/include/asm/perf_event.h +++ b/arch/x86/include/asm/perf_event.h @@ -753,15 +753,15 @@ struct x86_perf_regs { u64 *xmm_regs; }; -extern unsigned long perf_instruction_pointer(struct pt_regs *regs); -extern unsigned long perf_misc_flags(struct pt_regs *regs); -#define perf_misc_flags(regs) perf_misc_flags(regs) +extern unsigned long perf_arch_instruction_pointer(struct pt_regs *regs); +extern unsigned long perf_arch_misc_flags(struct pt_regs *regs); +#define perf_arch_misc_flags(regs) perf_arch_misc_flags(regs) #include /* - * We abuse bit 3 from flags to pass exact information, see perf_misc_flags - * and the comment with PERF_EFLAGS_EXACT. + * We abuse bit 3 from flags to pass exact information, see + * perf_arch_misc_flags() and the comment with PERF_EFLAGS_EXACT. */ #define perf_arch_fetch_caller_regs(regs, __ip) { \ (regs)->ip = (__ip); \ diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index b3ccaaad28d8..e78ec55752c7 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -1732,10 +1732,13 @@ extern void perf_tp_event(u16 event_type, u64 count, void *record, struct task_struct *task); extern void perf_bp_event(struct perf_event *event, void *data); -#ifndef perf_misc_flags -# define perf_misc_flags(regs) \ +extern unsigned long perf_misc_flags(struct pt_regs *regs); +extern unsigned long perf_instruction_pointer(struct pt_regs *regs); + +#ifndef perf_arch_misc_flags +# define perf_arch_misc_flags(regs) \ (user_mode(regs) ? PERF_RECORD_MISC_USER : PERF_RECORD_MISC_KERNEL) -# define perf_instruction_pointer(regs) instruction_pointer(regs) +# define perf_arch_instruction_pointer(regs) instruction_pointer(regs) #endif #ifndef perf_arch_bpf_user_pt_regs # define perf_arch_bpf_user_pt_regs(regs) regs diff --git a/kernel/events/core.c b/kernel/events/core.c index 26fd19f82841..68b4c378d8ac 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -7258,6 +7258,16 @@ void perf_unregister_guest_info_callbacks(struct perf_guest_info_callbacks *cbs) EXPORT_SYMBOL_GPL(perf_unregister_guest_info_callbacks); #endif +unsigned long perf_misc_flags(struct pt_regs *regs) +{ + return perf_arch_misc_flags(regs); +} + +unsigned long perf_instruction_pointer(struct pt_regs *regs) +{ + return perf_arch_instruction_pointer(regs); +} + static void perf_output_sample_regs(struct perf_output_handle *handle, struct pt_regs *regs, u64 mask) -- Gitee From 605820e07416c1d0d2943469b62f52f252a86f5e Mon Sep 17 00:00:00 2001 From: Colton Lewis Date: Wed, 13 Nov 2024 19:01:53 +0000 Subject: [PATCH 03/20] perf/powerpc: Use perf_arch_instruction_pointer() ANBZ: #45489 commit 3e807cf07d96eedb57d91a91f611f828e8918aab upstream. Make sure PowerPC uses the arch-specific function now that those have been reorganized. Signed-off-by: Colton Lewis Signed-off-by: Ingo Molnar Reviewed-by: Oliver Upton Acked-by: Madhavan Srinivasan Link: https://lore.kernel.org/r/20241113190156.2145593-4-coltonlewis@google.com Signed-off-by: Jason Zeng --- arch/powerpc/perf/callchain.c | 2 +- arch/powerpc/perf/callchain_32.c | 2 +- arch/powerpc/perf/callchain_64.c | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arch/powerpc/perf/callchain.c b/arch/powerpc/perf/callchain.c index 6b4434dd0ff3..26aa26482c9a 100644 --- a/arch/powerpc/perf/callchain.c +++ b/arch/powerpc/perf/callchain.c @@ -51,7 +51,7 @@ perf_callchain_kernel(struct perf_callchain_entry_ctx *entry, struct pt_regs *re lr = regs->link; sp = regs->gpr[1]; - perf_callchain_store(entry, perf_instruction_pointer(regs)); + perf_callchain_store(entry, perf_arch_instruction_pointer(regs)); if (!validate_sp(sp, current)) return; diff --git a/arch/powerpc/perf/callchain_32.c b/arch/powerpc/perf/callchain_32.c index ea8cfe3806dc..ddcc2d8aa64a 100644 --- a/arch/powerpc/perf/callchain_32.c +++ b/arch/powerpc/perf/callchain_32.c @@ -139,7 +139,7 @@ void perf_callchain_user_32(struct perf_callchain_entry_ctx *entry, long level = 0; unsigned int __user *fp, *uregs; - next_ip = perf_instruction_pointer(regs); + next_ip = perf_arch_instruction_pointer(regs); lr = regs->link; sp = regs->gpr[1]; perf_callchain_store(entry, next_ip); diff --git a/arch/powerpc/perf/callchain_64.c b/arch/powerpc/perf/callchain_64.c index 488e8a21a11e..115d1c105e8a 100644 --- a/arch/powerpc/perf/callchain_64.c +++ b/arch/powerpc/perf/callchain_64.c @@ -74,7 +74,7 @@ void perf_callchain_user_64(struct perf_callchain_entry_ctx *entry, struct signal_frame_64 __user *sigframe; unsigned long __user *fp, *uregs; - next_ip = perf_instruction_pointer(regs); + next_ip = perf_arch_instruction_pointer(regs); lr = regs->link; sp = regs->gpr[1]; perf_callchain_store(entry, next_ip); -- Gitee From 75ef98567cc20431af0c9e773b7f7e27c31ccbdf Mon Sep 17 00:00:00 2001 From: Colton Lewis Date: Wed, 13 Nov 2024 19:01:54 +0000 Subject: [PATCH 04/20] perf/x86: Refactor misc flag assignments ANBZ: #45489 commit baff01f3d75ff3948a0465853dcaa71c394c5c46 upstream. Break the assignment logic for misc flags into their own respective functions to reduce the complexity of the nested logic. Signed-off-by: Colton Lewis Signed-off-by: Ingo Molnar Reviewed-by: Oliver Upton Acked-by: Kan Liang Link: https://lore.kernel.org/r/20241113190156.2145593-5-coltonlewis@google.com Signed-off-by: Jason Zeng --- arch/x86/events/core.c | 59 ++++++++++++++++++++++--------- arch/x86/include/asm/perf_event.h | 2 ++ 2 files changed, 44 insertions(+), 17 deletions(-) diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c index a7cd778e2e05..ee0022a6b0e8 100644 --- a/arch/x86/events/core.c +++ b/arch/x86/events/core.c @@ -3116,27 +3116,52 @@ unsigned long perf_arch_instruction_pointer(struct pt_regs *regs) return regs->ip + code_segment_base(regs); } -unsigned long perf_arch_misc_flags(struct pt_regs *regs) +static unsigned long common_misc_flags(struct pt_regs *regs) { - unsigned int guest_state = perf_guest_state(); - int misc = 0; + if (regs->flags & PERF_EFLAGS_EXACT) + return PERF_RECORD_MISC_EXACT_IP; - if (guest_state) { - if (guest_state & PERF_GUEST_USER) - misc |= PERF_RECORD_MISC_GUEST_USER; - else - misc |= PERF_RECORD_MISC_GUEST_KERNEL; - } else { - if (user_mode(regs)) - misc |= PERF_RECORD_MISC_USER; - else - misc |= PERF_RECORD_MISC_KERNEL; - } + return 0; +} - if (regs->flags & PERF_EFLAGS_EXACT) - misc |= PERF_RECORD_MISC_EXACT_IP; +static unsigned long guest_misc_flags(struct pt_regs *regs) +{ + unsigned long guest_state = perf_guest_state(); + + if (!(guest_state & PERF_GUEST_ACTIVE)) + return 0; + + if (guest_state & PERF_GUEST_USER) + return PERF_RECORD_MISC_GUEST_USER; + else + return PERF_RECORD_MISC_GUEST_KERNEL; + +} + +static unsigned long host_misc_flags(struct pt_regs *regs) +{ + if (user_mode(regs)) + return PERF_RECORD_MISC_USER; + else + return PERF_RECORD_MISC_KERNEL; +} + +unsigned long perf_arch_guest_misc_flags(struct pt_regs *regs) +{ + unsigned long flags = common_misc_flags(regs); + + flags |= guest_misc_flags(regs); + + return flags; +} + +unsigned long perf_arch_misc_flags(struct pt_regs *regs) +{ + unsigned long flags = common_misc_flags(regs); + + flags |= host_misc_flags(regs); - return misc; + return flags; } void perf_get_x86_pmu_capability(struct x86_pmu_capability *cap) diff --git a/arch/x86/include/asm/perf_event.h b/arch/x86/include/asm/perf_event.h index e87f5032aa79..e9a67cc2c20f 100644 --- a/arch/x86/include/asm/perf_event.h +++ b/arch/x86/include/asm/perf_event.h @@ -755,7 +755,9 @@ struct x86_perf_regs { extern unsigned long perf_arch_instruction_pointer(struct pt_regs *regs); extern unsigned long perf_arch_misc_flags(struct pt_regs *regs); +extern unsigned long perf_arch_guest_misc_flags(struct pt_regs *regs); #define perf_arch_misc_flags(regs) perf_arch_misc_flags(regs) +#define perf_arch_guest_misc_flags(regs) perf_arch_guest_misc_flags(regs) #include -- Gitee From 78ba6b517ab015ccc6dcdda23d55413016f9b0e4 Mon Sep 17 00:00:00 2001 From: Colton Lewis Date: Wed, 13 Nov 2024 19:01:55 +0000 Subject: [PATCH 05/20] perf/core: Correct perf sampling with guest VMs ANBZ: #45489 commit 2c47e7a74f445426d156278e339b7abb259e50de upstream. Previously any PMU overflow interrupt that fired while a VCPU was loaded was recorded as a guest event whether it truly was or not. This resulted in nonsense perf recordings that did not honor perf_event_attr.exclude_guest and recorded guest IPs where it should have recorded host IPs. Rework the sampling logic to only record guest samples for events with exclude_guest = 0. This way any host-only events with exclude_guest set will never see unexpected guest samples. The behaviour of events with exclude_guest = 0 is unchanged. Note that events configured to sample both host and guest may still misattribute a PMI that arrived in the host as a guest event depending on KVM arch and vendor behavior. Signed-off-by: Colton Lewis Signed-off-by: Ingo Molnar Reviewed-by: Oliver Upton Acked-by: Mark Rutland Acked-by: Kan Liang Cc: Peter Zijlstra Cc: Arnaldo Carvalho de Melo Cc: Jiri Olsa Cc: Alexander Shishkin Cc: Namhyung Kim Link: https://lore.kernel.org/r/20241113190156.2145593-6-coltonlewis@google.com Conflicts: include/linux/perf_event.h [jz: - resolve context conflict due to that we fixed an issue when backporting the following upstream commit: 04782e63917d perf/core: Hoist perf_instruction_pointer() and perf_misc_flags()] Signed-off-by: Jason Zeng --- arch/arm64/include/asm/perf_event.h | 4 ---- arch/arm64/kernel/perf_callchain.c | 28 ---------------------------- arch/x86/events/core.c | 3 --- include/linux/perf_event.h | 21 +++++++++++++++++++-- kernel/events/core.c | 21 +++++++++++++++++---- 5 files changed, 36 insertions(+), 41 deletions(-) diff --git a/arch/arm64/include/asm/perf_event.h b/arch/arm64/include/asm/perf_event.h index d1e753f16d3b..ee45b4e77347 100644 --- a/arch/arm64/include/asm/perf_event.h +++ b/arch/arm64/include/asm/perf_event.h @@ -10,10 +10,6 @@ #include #ifdef CONFIG_PERF_EVENTS -struct pt_regs; -extern unsigned long perf_arch_instruction_pointer(struct pt_regs *regs); -extern unsigned long perf_arch_misc_flags(struct pt_regs *regs); -#define perf_arch_misc_flags(regs) perf_arch_misc_flags(regs) #define perf_arch_bpf_user_pt_regs(regs) ®s->user_regs #endif diff --git a/arch/arm64/kernel/perf_callchain.c b/arch/arm64/kernel/perf_callchain.c index 62a9200c044e..0542f7b344bb 100644 --- a/arch/arm64/kernel/perf_callchain.c +++ b/arch/arm64/kernel/perf_callchain.c @@ -148,31 +148,3 @@ void perf_callchain_kernel(struct perf_callchain_entry_ctx *entry, arch_stack_walk(callchain_trace, entry, current, regs); } - -unsigned long perf_arch_instruction_pointer(struct pt_regs *regs) -{ - if (perf_guest_state()) - return perf_guest_get_ip(); - - return instruction_pointer(regs); -} - -unsigned long perf_arch_misc_flags(struct pt_regs *regs) -{ - unsigned int guest_state = perf_guest_state(); - int misc = 0; - - if (guest_state) { - if (guest_state & PERF_GUEST_USER) - misc |= PERF_RECORD_MISC_GUEST_USER; - else - misc |= PERF_RECORD_MISC_GUEST_KERNEL; - } else { - if (user_mode(regs)) - misc |= PERF_RECORD_MISC_USER; - else - misc |= PERF_RECORD_MISC_KERNEL; - } - - return misc; -} diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c index ee0022a6b0e8..96640f15c23b 100644 --- a/arch/x86/events/core.c +++ b/arch/x86/events/core.c @@ -3110,9 +3110,6 @@ static unsigned long code_segment_base(struct pt_regs *regs) unsigned long perf_arch_instruction_pointer(struct pt_regs *regs) { - if (perf_guest_state()) - return perf_guest_get_ip(); - return regs->ip + code_segment_base(regs); } diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h index e78ec55752c7..2bc74fcdca60 100644 --- a/include/linux/perf_event.h +++ b/include/linux/perf_event.h @@ -1732,8 +1732,9 @@ extern void perf_tp_event(u16 event_type, u64 count, void *record, struct task_struct *task); extern void perf_bp_event(struct perf_event *event, void *data); -extern unsigned long perf_misc_flags(struct pt_regs *regs); -extern unsigned long perf_instruction_pointer(struct pt_regs *regs); +extern unsigned long perf_misc_flags(struct perf_event *event, struct pt_regs *regs); +extern unsigned long perf_instruction_pointer(struct perf_event *event, + struct pt_regs *regs); #ifndef perf_arch_misc_flags # define perf_arch_misc_flags(regs) \ @@ -1744,6 +1745,22 @@ extern unsigned long perf_instruction_pointer(struct pt_regs *regs); # define perf_arch_bpf_user_pt_regs(regs) regs #endif +#ifndef perf_arch_guest_misc_flags +static inline unsigned long perf_arch_guest_misc_flags(struct pt_regs *regs) +{ + unsigned long guest_state = perf_guest_state(); + + if (!(guest_state & PERF_GUEST_ACTIVE)) + return 0; + + if (guest_state & PERF_GUEST_USER) + return PERF_RECORD_MISC_GUEST_USER; + else + return PERF_RECORD_MISC_GUEST_KERNEL; +} +# define perf_arch_guest_misc_flags(regs) perf_arch_guest_misc_flags(regs) +#endif + static inline bool needs_branch_stack(struct perf_event *event) { return event->attr.branch_sample_type != 0; diff --git a/kernel/events/core.c b/kernel/events/core.c index 68b4c378d8ac..4e859cba3d36 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -7258,13 +7258,26 @@ void perf_unregister_guest_info_callbacks(struct perf_guest_info_callbacks *cbs) EXPORT_SYMBOL_GPL(perf_unregister_guest_info_callbacks); #endif -unsigned long perf_misc_flags(struct pt_regs *regs) +static bool should_sample_guest(struct perf_event *event) { + return !event->attr.exclude_guest && perf_guest_state(); +} + +unsigned long perf_misc_flags(struct perf_event *event, + struct pt_regs *regs) +{ + if (should_sample_guest(event)) + return perf_arch_guest_misc_flags(regs); + return perf_arch_misc_flags(regs); } -unsigned long perf_instruction_pointer(struct pt_regs *regs) +unsigned long perf_instruction_pointer(struct perf_event *event, + struct pt_regs *regs) { + if (should_sample_guest(event)) + return perf_guest_get_ip(); + return perf_arch_instruction_pointer(regs); } @@ -8087,7 +8100,7 @@ void perf_prepare_sample(struct perf_sample_data *data, __perf_event_header__init_id(data, event, filtered_sample_type); if (filtered_sample_type & PERF_SAMPLE_IP) { - data->ip = perf_instruction_pointer(regs); + data->ip = perf_instruction_pointer(event, regs); data->sample_flags |= PERF_SAMPLE_IP; } @@ -8251,7 +8264,7 @@ void perf_prepare_header(struct perf_event_header *header, { header->type = PERF_RECORD_SAMPLE; header->size = perf_sample_data_size(data, event); - header->misc = perf_misc_flags(regs); + header->misc = perf_misc_flags(event, regs); /* * If you're adding more sample types here, you likely need to do -- Gitee From 0a6cbde720da4fec43f93a7ce0238ee87bb40949 Mon Sep 17 00:00:00 2001 From: Dapeng Mi Date: Tue, 16 Jun 2026 12:46:47 +0800 Subject: [PATCH 06/20] perf/x86/intel: Remove anythread_deprecated bit from perf_capabilities ANBZ: #45489 commit 8767b4d73018bd3143f4c55b672064fad292f11b upstream. AnyThread mode deprecation is enumerated by CPUID.0AH:EDX[15] instead of PERF_CAPABILITIES MSR. It's not a good practice to define a bit to represent "anythread deprecation" in perf_capabilities. It leads to the anythread_deprecated bit could be overwritten by the real value of PERF_CAPABILITIES MSR, just like the below code in update_pmu_cap() does. if (!intel_pmu_broken_perf_cap()) { /* Perf Metric (Bit 15) and PEBS via PT (Bit 16) are hybrid enumeration */ rdmsrq(MSR_IA32_PERF_CAPABILITIES, hybrid(pmu, intel_cap).capabilities); } It leads to the anythread_deprecated bit is cleared to 0 and the "any" attribute is incorrectly shown in the /sys/devices/cpu/format/ folder on these support Perfmon v6 platforms, like Clearwater Forest. $ grep . /sys/devices/cpu/format/* /sys/devices/cpu/format/acr_mask:config2:0-63 /sys/devices/cpu/format/any:config:21 /sys/devices/cpu/format/cmask:config:24-31 So remove the anythread_deprecated bit from perf_capabilities structure and directly depends on CPUID.0AH:EDX[15] to judge if anythread is deprecated. Fixes: cadbaa039b99 ("perf/x86/intel: Make anythread filter support conditional") Reported-by: Namhyung Kim Signed-off-by: Dapeng Mi Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Zide Chen Reviewed-by: Thomas Falcon Acked-by: Namhyung Kim Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20260616044654.3468742-2-dapeng1.mi@linux.intel.com Conflicts: arch/x86/events/intel/core.c [jz: resolve context conflict] Signed-off-by: Jason Zeng --- arch/x86/events/intel/core.c | 10 +++------- arch/x86/events/perf_event.h | 2 +- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c index 613f5261bbc9..9f95924ae6c1 100644 --- a/arch/x86/events/intel/core.c +++ b/arch/x86/events/intel/core.c @@ -7800,12 +7800,6 @@ __init int intel_pmu_init(void) x86_add_quirk(intel_arch_events_quirk); /* Install first, so it runs last */ - if (version >= 5) { - x86_pmu.intel_cap.anythread_deprecated = edx.split.anythread_deprecated; - if (x86_pmu.intel_cap.anythread_deprecated) - pr_cont(" AnyThread deprecated, "); - } - /* The perf side of core PMU is ready to support the mediated vPMU. */ x86_get_pmu(smp_processor_id())->capabilities |= PERF_PMU_CAP_MEDIATED_VPMU; @@ -8620,8 +8614,10 @@ __init int intel_pmu_init(void) &x86_pmu.intel_ctrl); /* AnyThread may be deprecated on arch perfmon v5 or later */ - if (x86_pmu.intel_cap.anythread_deprecated) + if (version >= 5 && edx.split.anythread_deprecated) { x86_pmu.format_attrs = intel_arch_formats_attr; + pr_cont("AnyThread deprecated, "); + } intel_pmu_check_event_constraints_all(NULL); diff --git a/arch/x86/events/perf_event.h b/arch/x86/events/perf_event.h index 25503bc83125..bd7a1e996501 100644 --- a/arch/x86/events/perf_event.h +++ b/arch/x86/events/perf_event.h @@ -667,7 +667,7 @@ union perf_capabilities { u64 perf_metrics:1; u64 pebs_output_pt_available:1; u64 pebs_timing_info:1; - u64 anythread_deprecated:1; + u64 __reserved:1; u64 rdpmc_metrics_clear:1; }; u64 capabilities; -- Gitee From ee12feaede7412dd3b3f5de828679c39f1668725 Mon Sep 17 00:00:00 2001 From: Dapeng Mi Date: Tue, 16 Jun 2026 12:46:48 +0800 Subject: [PATCH 07/20] perf/x86/intel: Keep cap_user_rdpmc in sync with RDPMC user-disable state ANBZ: #45489 commit 3c4ec9b2a5db56b60127bfaf933ecdeea7a1f10a upstream. After introducing the RDPMC user disable feature, user-space RDPMC may return 0 instead of the actual event count. This creates an inconsistency with cap_user_rdpmc, where cap_user_rdpmc is set, but user-space RDPMC only returns 0. To accurately represent the user-space RDPMC capability, update cap_user_rdpmc (depending on PERF_EVENT_FLAG_USER_READ_CNT) according to the RDPMC user disable state. If RDPMC user disable is enabled, cap_user_rdpmc is updated to false eventually, allowing user-space programs to fall back to the read() syscall to obtain the real event count. Because PERF_EVENT_FLAG_USER_READ_CNT is evaluated in x86_pmu_event_init(), move intel_pmu_update_rdpmc_user_disable() earlier into intel_pmu_hw_config(). This ensures that the user-disable state is updated before updating PERF_EVENT_FLAG_USER_READ_CNT. Note that since event->ctx is not yet assigned at this stage, use the PERF_ATTACH_TASK flag to detect whether the event is task-attached. While at it, fix the indentation of x86_pmu_has_rdpmc_user_disable() to adhere to the kernel coding style. Fixes: 59af95e028d4 ("perf/x86/intel: Add support for rdpmc user disable feature") Signed-off-by: Dapeng Mi Signed-off-by: Peter Zijlstra (Intel) Link: https://patch.msgid.link/20260616044654.3468742-3-dapeng1.mi@linux.intel.com Signed-off-by: Jason Zeng --- arch/x86/events/core.c | 3 ++- arch/x86/events/intel/core.c | 6 +++--- arch/x86/events/perf_event.h | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c index 96640f15c23b..242c051b1447 100644 --- a/arch/x86/events/core.c +++ b/arch/x86/events/core.c @@ -2536,7 +2536,8 @@ static int x86_pmu_event_init(struct perf_event *event) } if (READ_ONCE(x86_pmu.attr_rdpmc) && - !(event->hw.flags & PERF_X86_EVENT_LARGE_PEBS)) + !(event->hw.flags & PERF_X86_EVENT_LARGE_PEBS) && + !(event->hw.config & ARCH_PERFMON_EVENTSEL_RDPMC_USER_DISABLE)) event->hw.flags |= PERF_EVENT_FLAG_USER_READ_CNT; return err; diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c index 9f95924ae6c1..349241938b49 100644 --- a/arch/x86/events/intel/core.c +++ b/arch/x86/events/intel/core.c @@ -3461,7 +3461,7 @@ static void intel_pmu_update_rdpmc_user_disable(struct perf_event *event) */ if (x86_pmu.attr_rdpmc == X86_USER_RDPMC_ALWAYS_ENABLE || (x86_pmu.attr_rdpmc == X86_USER_RDPMC_CONDITIONAL_ENABLE && - event->ctx->task)) + (event->attach_state & PERF_ATTACH_TASK))) event->hw.config &= ~ARCH_PERFMON_EVENTSEL_RDPMC_USER_DISABLE; else event->hw.config |= ARCH_PERFMON_EVENTSEL_RDPMC_USER_DISABLE; @@ -3475,8 +3475,6 @@ static void intel_pmu_enable_event(struct perf_event *event) struct hw_perf_event *hwc = &event->hw; int idx = hwc->idx; - intel_pmu_update_rdpmc_user_disable(event); - if (unlikely(event->attr.precise_ip)) static_call(x86_pmu_pebs_enable)(event); @@ -5070,6 +5068,8 @@ static int intel_pmu_hw_config(struct perf_event *event) leader->hw.flags |= PERF_X86_EVENT_ACR; } + intel_pmu_update_rdpmc_user_disable(event); + if ((event->attr.type == PERF_TYPE_HARDWARE) || (event->attr.type == PERF_TYPE_HW_CACHE)) return 0; diff --git a/arch/x86/events/perf_event.h b/arch/x86/events/perf_event.h index bd7a1e996501..efd3ab5d8fcb 100644 --- a/arch/x86/events/perf_event.h +++ b/arch/x86/events/perf_event.h @@ -1353,7 +1353,7 @@ static inline u64 x86_pmu_get_event_config(struct perf_event *event) static inline bool x86_pmu_has_rdpmc_user_disable(struct pmu *pmu) { return !!(hybrid(pmu, config_mask) & - ARCH_PERFMON_EVENTSEL_RDPMC_USER_DISABLE); + ARCH_PERFMON_EVENTSEL_RDPMC_USER_DISABLE); } extern struct event_constraint emptyconstraint; -- Gitee From 75047af64a25f5b14ceda6e5e66a7327325ded18 Mon Sep 17 00:00:00 2001 From: Dapeng Mi Date: Tue, 16 Jun 2026 12:46:49 +0800 Subject: [PATCH 08/20] perf/x86/intel: Fallback to sw branch type decoding if no hw decoding ANBZ: #45489 commit 170cc6b02e3d5203ccaa49ffea1ee5a7ab08c885 upstream. intel_pmu_lbr_filter() currently assumes arch-LBR provides hardware branch-type decoding and skips software decoding on that path. However, arch-LBR may not always expose branch-type information. In that case, treating entries as hardware-decoded can misclassify sampled branches (for example, defaulting to JCC), which breaks branch-type filtering results. Fix this by using software branch-type decoding when hardware branch-type decoding is unavailable (that is, when x86_lbr_type is not enabled). This keeps branch classification and filtering behavior correct across arch-LBR configurations. Since x86_lbr_type is only set to true when arch-LBR is supported, it's unnecessary to check if the CPU has the arch-LBR feature. Signed-off-by: Dapeng Mi Signed-off-by: Peter Zijlstra (Intel) Link: https://patch.msgid.link/20260616044654.3468742-4-dapeng1.mi@linux.intel.com Signed-off-by: Jason Zeng --- arch/x86/events/intel/lbr.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/events/intel/lbr.c b/arch/x86/events/intel/lbr.c index 91fa2154323e..f08dc380c8d1 100644 --- a/arch/x86/events/intel/lbr.c +++ b/arch/x86/events/intel/lbr.c @@ -1221,7 +1221,7 @@ intel_pmu_lbr_filter(struct cpu_hw_events *cpuc) * Doesn't support OTHER_BRANCH decoding for now. * OTHER_BRANCH branch type still rely on software decoding. */ - if (static_cpu_has(X86_FEATURE_ARCH_LBR) && + if (static_branch_likely(&x86_lbr_type) && type <= ARCH_LBR_BR_TYPE_KNOWN_MAX) { to_plm = kernel_ip(to) ? X86_BR_KERNEL : X86_BR_USER; type = arch_lbr_br_type_map[type] | to_plm; -- Gitee From 366eb62149083949d4a8326a0eea414f38633708 Mon Sep 17 00:00:00 2001 From: Dapeng Mi Date: Tue, 16 Jun 2026 12:46:50 +0800 Subject: [PATCH 09/20] perf/x86/intel: Fix kernel address leakages in LBR stack ANBZ: #45489 commit e2b0575900ff72aa82748af96e7bd564ade5157a upstream. Before Arch LBR gained CPL filtering support, a user-only branch stack could still contain kernel addresses. As a result, kernel branch records may be exposed to user space even when PERF_SAMPLE_BRANCH_USER is requested. For example, on Intel Tiger Lake, the following command can still report SYSRET/ERET entries with kernel-space from addresses: $ ./perf record -e cycles:p -o - --branch-filter any,save_type,u -- \ ./perf bench syscall basic --loop 1000 | \ ./perf script -i - --fields brstack|tr ' ' '\n'| \ grep -E '0x[89a-f][0-9a-f]{15}' Total time: 0.000 [sec] 0.219000 usecs/op 4,566,210 ops/sec [ perf record: Woken up 1 times to write data ] [ perf record: Captured and wrote 0.551 MB - ] 0xffffffff93c001c8/0x7f12a2b1d647/P/-/-/16959/SYSRET/- 0xffffffff93c001c8/0x7f12a2b1d5c2/P/-/-/17535/SYSRET/- 0xffffffff93c01928/0x7f12a2861000/P/-/-/6719/ERET/- 0xffffffff93c01928/0x7f12a297a000/P/-/-/8575/ERET/- The problem is that intel_pmu_lbr_filter() does not fully validate the privilege level of sampled entries. It filters some mismatches based on the branch type and the to address, but it does not reject entries whose from address violates the requested branch privilege filter. Fix this by extending software filtering to validate both from and to addresses against br_sel. Any LBR entry contains kernel address does not match the requested user filter is dropped. This prevents kernel addresses from appearing in user-only branch stacks. Fixes: 47125db27e47 ("perf/x86/intel/lbr: Support Architectural LBR") Reported-by: Ian Rogers Signed-off-by: Dapeng Mi Signed-off-by: Peter Zijlstra (Intel) Cc: stable@vger.kernel.org Link: https://patch.msgid.link/20260616044654.3468742-5-dapeng1.mi@linux.intel.com Signed-off-by: Jason Zeng --- arch/x86/events/intel/lbr.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/arch/x86/events/intel/lbr.c b/arch/x86/events/intel/lbr.c index f08dc380c8d1..26644a65ab55 100644 --- a/arch/x86/events/intel/lbr.c +++ b/arch/x86/events/intel/lbr.c @@ -1202,7 +1202,7 @@ intel_pmu_lbr_filter(struct cpu_hw_events *cpuc) { u64 from, to; int br_sel = cpuc->br_sel; - int i, j, type, to_plm; + int i, j, type, from_plm, to_plm; bool compress = false; /* if sampling all branches, then nothing to filter */ @@ -1234,8 +1234,14 @@ intel_pmu_lbr_filter(struct cpu_hw_events *cpuc) type |= X86_BR_NO_TX; } - /* if type does not correspond, then discard */ - if (type == X86_BR_NONE || (br_sel & type) != type) { + from_plm = kernel_ip(from) ? X86_BR_KERNEL : X86_BR_USER; + /* + * If type does not correspond, then discard. + * Specifically reject entries whose from address is in + * kernel space when only X86_BR_USER is requested. + */ + if (type == X86_BR_NONE || (br_sel & type) != type || + (!(br_sel & X86_BR_KERNEL) && (from_plm & X86_BR_KERNEL))) { cpuc->lbr_entries[i].from = 0; compress = true; } -- Gitee From a0e46433f2e76f3fd99216625d059e1b210d18a8 Mon Sep 17 00:00:00 2001 From: Dapeng Mi Date: Tue, 16 Jun 2026 12:46:51 +0800 Subject: [PATCH 10/20] perf/x86/intel: Validate the return value of intel_pmu_init_hybrid() ANBZ: #45489 commit 01c153956b4436ead05a529dae56abc0ef58beac upstream. The intel_pmu_init_hybrid() function allocates memory for the x86_pmu.hybrid_pmu[] array. If this allocation fails under memory pressure, hybrid PMU initialization will fail. Currently, the caller does not check the return value of intel_pmu_init_hybrid(). This can lead to a null-pointer dereference or invalid memory access when attempting to use the uninitialized array, potentially triggering a system panic. Fix this by validating the return value of intel_pmu_init_hybrid(). Additionally, reset x86_pmu.num_hybrid_pmus to 0 on failure, and defer intel_pmu_arch_lbr_init() until after hybrid PMU initialization succeeds. This reordering avoids the need to explicitly destroy the kmem cache if the memory allocation fails. Signed-off-by: Dapeng Mi Signed-off-by: Peter Zijlstra (Intel) Link: https://patch.msgid.link/20260616044654.3468742-6-dapeng1.mi@linux.intel.com Conflicts: arch/x86/events/intel/core.c [jz: - resolve context conflict - not include code changes for arrowlake/novalake platforms because Anolis doesn't support them yet] Signed-off-by: Jason Zeng --- arch/x86/events/intel/core.c | 36 ++++++++++++++++++++++++------------ 1 file changed, 24 insertions(+), 12 deletions(-) diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c index 349241938b49..307228351d47 100644 --- a/arch/x86/events/intel/core.c +++ b/arch/x86/events/intel/core.c @@ -7556,8 +7556,10 @@ static __always_inline int intel_pmu_init_hybrid(enum hybrid_pmu_type pmus) x86_pmu.hybrid_pmu = kcalloc(x86_pmu.num_hybrid_pmus, sizeof(struct x86_hybrid_pmu), GFP_KERNEL); - if (!x86_pmu.hybrid_pmu) + if (!x86_pmu.hybrid_pmu) { + x86_pmu.num_hybrid_pmus = 0; return -ENOMEM; + } static_branch_enable(&perf_is_hybrid); x86_pmu.filter = intel_pmu_filter; @@ -7722,14 +7724,14 @@ __init int intel_pmu_init(void) struct attribute **td_attr = &empty_attrs; struct attribute **mem_attr = &empty_attrs; struct attribute **tsx_attr = &empty_attrs; + struct x86_hybrid_pmu *pmu; + unsigned int fixed_mask; union cpuid10_edx edx; union cpuid10_eax eax; union cpuid10_ebx ebx; - unsigned int fixed_mask; + int version, i, ret; bool pmem = false; - int version, i; char *name; - struct x86_hybrid_pmu *pmu; if (!cpu_has(&boot_cpu_data, X86_FEATURE_ARCH_PERFMON)) { switch (boot_cpu_data.x86) { @@ -7793,9 +7795,6 @@ __init int intel_pmu_init(void) x86_pmu.lbr_read = intel_pmu_lbr_read_32; } - if (boot_cpu_has(X86_FEATURE_ARCH_LBR)) - intel_pmu_arch_lbr_init(); - intel_pebs_init(); x86_add_quirk(intel_arch_events_quirk); /* Install first, so it runs last */ @@ -8392,7 +8391,9 @@ __init int intel_pmu_init(void) * * Initialize the common PerfMon capabilities here. */ - intel_pmu_init_hybrid(hybrid_big_small); + ret = intel_pmu_init_hybrid(hybrid_big_small); + if (ret) + return ret; x86_pmu.pebs_latency_data = grt_latency_data; x86_pmu.get_event_constraints = adl_get_event_constraints; @@ -8449,7 +8450,9 @@ __init int intel_pmu_init(void) case INTEL_METEORLAKE: case INTEL_METEORLAKE_L: - intel_pmu_init_hybrid(hybrid_big_small); + ret = intel_pmu_init_hybrid(hybrid_big_small); + if (ret) + return ret; x86_pmu.pebs_latency_data = cmt_latency_data; x86_pmu.get_event_constraints = mtl_get_event_constraints; @@ -8479,7 +8482,9 @@ __init int intel_pmu_init(void) pr_cont("Pantherlake Hybrid events, "); name = "pantherlake_hybrid"; - intel_pmu_init_hybrid(hybrid_big_small); + ret = intel_pmu_init_hybrid(hybrid_big_small); + if (ret) + return ret; /* Initialize big core specific PerfMon capabilities.*/ pmu = &x86_pmu.hybrid_pmu[X86_HYBRID_PMU_CORE_IDX]; @@ -8494,7 +8499,9 @@ __init int intel_pmu_init(void) pr_cont("Arrowlake Hybrid events, "); name = "arrowlake_hybrid"; - intel_pmu_init_hybrid(hybrid_big_small); + ret = intel_pmu_init_hybrid(hybrid_big_small); + if (ret) + return ret; /* Initialize big core specific PerfMon capabilities.*/ pmu = &x86_pmu.hybrid_pmu[X86_HYBRID_PMU_CORE_IDX]; @@ -8511,7 +8518,9 @@ __init int intel_pmu_init(void) pr_cont("Lunarlake Hybrid events, "); name = "lunarlake_hybrid"; - intel_pmu_init_hybrid(hybrid_big_small); + ret = intel_pmu_init_hybrid(hybrid_big_small); + if (ret) + return ret; /* Initialize big core specific PerfMon capabilities.*/ pmu = &x86_pmu.hybrid_pmu[X86_HYBRID_PMU_CORE_IDX]; @@ -8619,6 +8628,9 @@ __init int intel_pmu_init(void) pr_cont("AnyThread deprecated, "); } + if (boot_cpu_has(X86_FEATURE_ARCH_LBR)) + intel_pmu_arch_lbr_init(); + intel_pmu_check_event_constraints_all(NULL); /* -- Gitee From 140ddb03f88a6bf40795141cd2c5e307d9c341b3 Mon Sep 17 00:00:00 2001 From: Dapeng Mi Date: Tue, 16 Jun 2026 12:46:52 +0800 Subject: [PATCH 11/20] perf/x86/intel: Drop fixed-counter PEBS constraints for baseline PEBS ANBZ: #45489 commit a6b5fbc33172509fbe991358d718617a8e33ea7e upstream. On Sapphire Rapids (SPR) guests where pebs_baseline is not advertised, running command $ ./perf record -e cpu/event=0x00,umask=0x01,i\ name=INST_RETIRED.PREC_DIST/p -c 10000 sleep 1 can trigger: unchecked MSR access error: WRMSR to 0x3f1 ... in\ intel_pmu_pebs_enable_all() This occurs because SPR-specific PEBS constraints allow fixed-counter scheduling (for example, INST_RETIRED.PREC_DIST on fixed counter 0). In guests lacking pebs_baseline, KVM does not support PEBS sampling on fixed counters, so enabling such events reaches an invalid MSR programming path. Starting with Icelake, regardless of whether Extended PEBS or Architectural PEBS is in use, all counters (including fixed counters) support PEBS sampling, and the PMU_FL_PEBS_ALL flag is set by default. As long as PMU_FL_PEBS_ALL is set, constraint lookup automatically falls back to the corresponding non-PEBS constraints if no matching entry is found in the PEBS constraints table. Since non-PEBS event constraints already contain the same fixed-counter constraints, it is safe to remove these fixed-counter entries from the PEBS constraints table. The fallback mechanism will ensure that fixed PEBS events are scheduled onto the correct fixed counters. So, directly drop the fixed-counter entries from the PEBS constraint table. Without pebs_baseline, these fixed-counter PEBS events will now resolve to empty constraints and will not be scheduled or enabled, thereby avoiding the warning and bypassing the broken guest PEBS path. Reported-by: Yi Lai Signed-off-by: Dapeng Mi Signed-off-by: Peter Zijlstra (Intel) Link: https://patch.msgid.link/20260616044654.3468742-7-dapeng1.mi@linux.intel.com Signed-off-by: Jason Zeng --- arch/x86/events/intel/ds.c | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/arch/x86/events/intel/ds.c b/arch/x86/events/intel/ds.c index 1ca9df95b423..604fa83cbf27 100644 --- a/arch/x86/events/intel/ds.c +++ b/arch/x86/events/intel/ds.c @@ -1341,10 +1341,6 @@ struct event_constraint intel_skl_pebs_event_constraints[] = { }; struct event_constraint intel_icl_pebs_event_constraints[] = { - INTEL_FLAGS_UEVENT_CONSTRAINT(0x01c0, 0x100000000ULL), /* old INST_RETIRED.PREC_DIST */ - INTEL_FLAGS_UEVENT_CONSTRAINT(0x0100, 0x100000000ULL), /* INST_RETIRED.PREC_DIST */ - INTEL_FLAGS_UEVENT_CONSTRAINT(0x0400, 0x800000000ULL), /* SLOTS */ - INTEL_PLD_CONSTRAINT(0x1cd, 0xff), /* MEM_TRANS_RETIRED.LOAD_LATENCY */ INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_LD(0x11d0, 0xf), /* MEM_INST_RETIRED.STLB_MISS_LOADS */ INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_ST(0x12d0, 0xf), /* MEM_INST_RETIRED.STLB_MISS_STORES */ @@ -1367,9 +1363,6 @@ struct event_constraint intel_icl_pebs_event_constraints[] = { }; struct event_constraint intel_glc_pebs_event_constraints[] = { - INTEL_FLAGS_UEVENT_CONSTRAINT(0x100, 0x100000000ULL), /* INST_RETIRED.PREC_DIST */ - INTEL_FLAGS_UEVENT_CONSTRAINT(0x0400, 0x800000000ULL), - INTEL_FLAGS_EVENT_CONSTRAINT(0xc0, 0xfe), INTEL_PLD_CONSTRAINT(0x1cd, 0xfe), INTEL_PSD_CONSTRAINT(0x2cd, 0x1), @@ -1394,9 +1387,6 @@ struct event_constraint intel_glc_pebs_event_constraints[] = { }; struct event_constraint intel_lnc_pebs_event_constraints[] = { - INTEL_FLAGS_UEVENT_CONSTRAINT(0x100, 0x100000000ULL), /* INST_RETIRED.PREC_DIST */ - INTEL_FLAGS_UEVENT_CONSTRAINT(0x0400, 0x800000000ULL), - INTEL_FLAGS_UEVENT_CONSTRAINT(0x012a, 0x1), /* OCR.* events */ INTEL_FLAGS_UEVENT_CONSTRAINT(0x012b, 0x1), /* OCR.* events */ @@ -1428,9 +1418,6 @@ struct event_constraint intel_lnc_pebs_event_constraints[] = { }; struct event_constraint intel_pnc_pebs_event_constraints[] = { - INTEL_FLAGS_UEVENT_CONSTRAINT(0x100, 0x100000000ULL), /* INST_RETIRED.PREC_DIST */ - INTEL_FLAGS_UEVENT_CONSTRAINT(0x0400, 0x800000000ULL), - INTEL_HYBRID_LDLAT_CONSTRAINT(0x1cd, 0xfc), INTEL_HYBRID_STLAT_CONSTRAINT(0x2cd, 0x3), INTEL_FLAGS_UEVENT_CONSTRAINT_DATALA_LD(0x11d0, 0xf), /* MEM_INST_RETIRED.STLB_MISS_LOADS */ -- Gitee From 4472444e99e36957104a249f54e09db428871752 Mon Sep 17 00:00:00 2001 From: Dapeng Mi Date: Tue, 16 Jun 2026 12:46:53 +0800 Subject: [PATCH 12/20] perf/core: Fix kernel register info leak via hardware skid ANBZ: #45489 commit 166f10836a653dfa280d4335603b52f685b8b1ef upstream. An unprivileged hardware perf event using exclude_kernel=1 can leak kernel register data to user space via PERF_SAMPLE_REGS_INTR or PERF_SAMPLE_IP. Due to hardware skid, a PMI may trigger after the CPU has already entered kernel space (Ring 0), bypassing the perf_allow_kernel() privilege barrier. This security vulnerability is severely exacerbated by upcoming support for SIMD register sampling via XSAVES, which could expose sensitive kernel FPU states (such as active cryptographic keys). Fix this by ensuring that sampled register data is dropped if the event's exclude_kernel attribute is set but the PMI catches the CPU in kernel mode. Signed-off-by: Dapeng Mi Signed-off-by: Peter Zijlstra (Intel) Link: https://lore.kernel.org/all/20260529085613.CCAFB1F00893@smtp.kernel.org/ Link: https://patch.msgid.link/20260616044654.3468742-8-dapeng1.mi@linux.intel.com Signed-off-by: Jason Zeng --- kernel/events/core.c | 37 ++++++++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/kernel/events/core.c b/kernel/events/core.c index 4e859cba3d36..9ffd9b96431d 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -7275,10 +7275,20 @@ unsigned long perf_misc_flags(struct perf_event *event, unsigned long perf_instruction_pointer(struct perf_event *event, struct pt_regs *regs) { - if (should_sample_guest(event)) - return perf_guest_get_ip(); + /* + * Hardware skid can lead to a scenario where a PMI is + * delivered after the CPU has already entered kernel mode. + * In that case, user-space sampling must not expose kernel + * register state. + */ + if (should_sample_guest(event)) { + return event->attr.exclude_kernel && + !(perf_guest_state() & PERF_GUEST_USER) ? + 0 : perf_guest_get_ip(); + } - return perf_arch_instruction_pointer(regs); + return event->attr.exclude_kernel && !user_mode(regs) ? + 0 : perf_arch_instruction_pointer(regs); } static void @@ -7312,10 +7322,22 @@ static void perf_sample_regs_user(struct perf_regs *regs_user, } static void perf_sample_regs_intr(struct perf_regs *regs_intr, - struct pt_regs *regs) + struct pt_regs *regs, + bool exclude_kernel) { - regs_intr->regs = regs; - regs_intr->abi = perf_reg_abi(current); + /* + * Hardware skid can lead to a scenario where a PMI is + * delivered after the CPU has already entered kernel mode. + * In that case, user-space sampling must not expose kernel + * register state. + */ + if (exclude_kernel && !user_mode(regs)) { + regs_intr->abi = PERF_SAMPLE_REGS_ABI_NONE; + regs_intr->regs = NULL; + } else { + regs_intr->regs = regs; + regs_intr->abi = perf_reg_abi(current); + } } @@ -8191,7 +8213,8 @@ void perf_prepare_sample(struct perf_sample_data *data, /* regs dump ABI info */ int size = sizeof(u64); - perf_sample_regs_intr(&data->regs_intr, regs); + perf_sample_regs_intr(&data->regs_intr, regs, + event->attr.exclude_kernel); if (data->regs_intr.regs) { u64 mask = event->attr.sample_regs_intr; -- Gitee From 92efe56e2f2f8952eefdae6d97b1901ea75cddd2 Mon Sep 17 00:00:00 2001 From: Dapeng Mi Date: Tue, 16 Jun 2026 12:46:54 +0800 Subject: [PATCH 13/20] perf/core: Check kernel access when kernel callchains are requested ANBZ: #45489 commit a4573a3838ae4fc73b70019cfa1dac9aaea7cc2f upstream. perf_event_open() currently gates perf_allow_kernel() only on !attr.exclude_kernel. However, users can still request kernel callchain collection with attr.exclude_callchain_kernel == 0 even when attr.exclude_kernel == 1. That still requires kernel profiling privilege, but the existing check does not enforce it. Update the permission check to call perf_allow_kernel() when either kernel sampling is requested or kernel callchains are requested. This keeps permission checks aligned with requested data and prevents unprivileged use of kernel callchain capture. Signed-off-by: Dapeng Mi Signed-off-by: Peter Zijlstra (Intel) Link: https://patch.msgid.link/20260616044654.3468742-9-dapeng1.mi@linux.intel.com Conflicts: kernel/events/core.c [jz: keep using perf_allow_kernel() with parameter 'attr' because 9ec84f79c5a7 ("perf: Remove unnecessary parameter of security check") not in Anolis] Signed-off-by: Jason Zeng --- kernel/events/core.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/kernel/events/core.c b/kernel/events/core.c index 9ffd9b96431d..053792af742b 100644 --- a/kernel/events/core.c +++ b/kernel/events/core.c @@ -13063,7 +13063,9 @@ SYSCALL_DEFINE5(perf_event_open, if (err) return err; - if (!attr.exclude_kernel) { + if (!attr.exclude_kernel || + ((attr.sample_type & PERF_SAMPLE_CALLCHAIN) && + !attr.exclude_callchain_kernel)) { err = perf_allow_kernel(&attr); if (err) return err; -- Gitee From f6e8a450ab56de36c9fc18069d6e49ceeba8b478 Mon Sep 17 00:00:00 2001 From: Dapeng Mi Date: Fri, 17 Jul 2026 16:03:35 +0800 Subject: [PATCH 14/20] perf/x86: Unregister PMI handler on PMU init failure ANBZ: #45489 commit 91787047b1dc52b1fee68b07f79af70aae5fce47 upstream. Fix an NMI handler leak in init_hw_perf_events(). When PMU initialization fails after register_nmi_handler(), the error path exits without calling unregister_nmi_handler(), leaving a stale NMI_LOCAL "PMI" handler registered. Add the missing call before clearing x86_pmu state. Signed-off-by: Dapeng Mi Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Thomas Falcon Reviewed-by: Zide Chen Link: https://patch.msgid.link/20260717080342.1879573-2-dapeng1.mi@linux.intel.com Signed-off-by: Jason Zeng --- arch/x86/events/core.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c index 242c051b1447..4d0fcb338a9f 100644 --- a/arch/x86/events/core.c +++ b/arch/x86/events/core.c @@ -2216,7 +2216,7 @@ static int __init init_hw_perf_events(void) err = cpuhp_setup_state(CPUHP_PERF_X86_PREPARE, "perf/x86:prepare", x86_pmu_prepare_cpu, x86_pmu_dead_cpu); if (err) - return err; + goto pmi_unregister; err = cpuhp_setup_state(CPUHP_AP_PERF_X86_STARTING, "perf/x86:starting", x86_pmu_starting_cpu, @@ -2270,6 +2270,8 @@ static int __init init_hw_perf_events(void) cpuhp_remove_state(CPUHP_AP_PERF_X86_STARTING); out: cpuhp_remove_state(CPUHP_PERF_X86_PREPARE); +pmi_unregister: + unregister_nmi_handler(NMI_LOCAL, "PMI"); out_bad_pmu: memset(&x86_pmu, 0, sizeof(x86_pmu)); return err; -- Gitee From 3cfa256149cbe9a8f68d1b6b990fbaa3bfa22016 Mon Sep 17 00:00:00 2001 From: Dapeng Mi Date: Fri, 17 Jul 2026 16:03:36 +0800 Subject: [PATCH 15/20] perf/x86: Free hybrid state on PMU init failure ANBZ: #45489 commit 96746e731e1626545e343974ca4673739dceb31b upstream. If PMU initialization fails, for example in check_hw_exists(), hybrid state can be left partially initialized: x86_pmu.hybrid_pmu is not freed and perf_is_hybrid remains set. This can leak memory and leave stale hybrid state reachable after a failed init path. Add x86_pmu_free_hybrid() and use it on PMU init failure paths so all hybrid-related state is consistently reset. Signed-off-by: Dapeng Mi Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Thomas Falcon Reviewed-by: Zide Chen Link: https://patch.msgid.link/20260717080342.1879573-3-dapeng1.mi@linux.intel.com Signed-off-by: Jason Zeng --- arch/x86/events/core.c | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c index 4d0fcb338a9f..b93e8284e5da 100644 --- a/arch/x86/events/core.c +++ b/arch/x86/events/core.c @@ -2127,6 +2127,17 @@ void x86_pmu_show_pmu_cap(struct pmu *pmu) pr_info("... global_ctrl mask: %016llx\n", hybrid(pmu, intel_ctrl)); } +static void x86_pmu_free_hybrid(void) +{ + if (!x86_pmu.hybrid_pmu) + return; + + static_branch_disable(&perf_is_hybrid); + kfree(x86_pmu.hybrid_pmu); + x86_pmu.hybrid_pmu = NULL; + x86_pmu.num_hybrid_pmus = 0; +} + static int __init init_hw_perf_events(void) { struct x86_pmu_quirk *quirk; @@ -2255,9 +2266,6 @@ static int __init init_hw_perf_events(void) for (j = 0; j < i; j++) perf_pmu_unregister(&x86_pmu.hybrid_pmu[j].pmu); pr_warn("Failed to register hybrid PMUs\n"); - kfree(x86_pmu.hybrid_pmu); - x86_pmu.hybrid_pmu = NULL; - x86_pmu.num_hybrid_pmus = 0; goto out2; } } @@ -2273,6 +2281,7 @@ static int __init init_hw_perf_events(void) pmi_unregister: unregister_nmi_handler(NMI_LOCAL, "PMI"); out_bad_pmu: + x86_pmu_free_hybrid(); memset(&x86_pmu, 0, sizeof(x86_pmu)); return err; } -- Gitee From b36108b1446bd09fb53ca858b277e69fb72b86cc Mon Sep 17 00:00:00 2001 From: Dapeng Mi Date: Fri, 17 Jul 2026 16:03:37 +0800 Subject: [PATCH 16/20] perf/x86: Guard intel_pmu_cpu_dead() against invalid hybrid PMU casts ANBZ: #45489 commit 278a3731c9d08bc6ea489c1987c6b7a7020f5d2b upstream. In failure paths, cpuc->pmu can still point to the global static pmu instead of an embedded x86_hybrid_pmu::pmu. Calling hybrid_pmu() on that pointer causes an invalid container conversion and may lead to out-of-bounds access. This can happen in at least two cases: - init_hybrid_pmu() fails check_hw_exists() and leaves cpuc->pmu as-is. - CPU hotplug fails between CPUHP_PERF_X86_PREPARE and CPUHP_AP_PERF_X86_STARTING, and rollback invokes intel_pmu_cpu_dead(). Fix both paths by: - Clear cpuc->pmu to NULL when check_hw_exists() fails. - Validat that cpuc->pmu is not the global static pmu before calling hybrid_pmu() in intel_pmu_cpu_dead(). A new helper x86_get_static_pmu() is added to get the global static pmu. Signed-off-by: Dapeng Mi Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Thomas Falcon Reviewed-by: Zide Chen Link: https://patch.msgid.link/20260717080342.1879573-4-dapeng1.mi@linux.intel.com Signed-off-by: Jason Zeng --- arch/x86/events/core.c | 5 +++++ arch/x86/events/intel/core.c | 7 +++++-- arch/x86/events/perf_event.h | 1 + 3 files changed, 11 insertions(+), 2 deletions(-) diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c index b93e8284e5da..666b75d435cb 100644 --- a/arch/x86/events/core.c +++ b/arch/x86/events/core.c @@ -789,6 +789,11 @@ int is_x86_event(struct perf_event *event) return false; } +inline struct pmu *x86_get_static_pmu(void) +{ + return &pmu; +} + struct pmu *x86_get_pmu(unsigned int cpu) { struct cpu_hw_events *cpuc = &per_cpu(cpu_hw_events, cpu); diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c index 307228351d47..b6f002dc5906 100644 --- a/arch/x86/events/intel/core.c +++ b/arch/x86/events/intel/core.c @@ -6225,8 +6225,10 @@ static bool init_hybrid_pmu(int cpu) intel_pmu_check_hybrid_pmus(pmu); - if (!check_hw_exists(&pmu->pmu, pmu->cntr_mask, pmu->fixed_cntr_mask)) + if (!check_hw_exists(&pmu->pmu, pmu->cntr_mask, pmu->fixed_cntr_mask)) { + cpuc->pmu = NULL; return false; + } pr_info("%s PMU driver: ", pmu->name); @@ -6374,11 +6376,12 @@ void intel_cpuc_finish(struct cpu_hw_events *cpuc) static void intel_pmu_cpu_dead(int cpu) { struct cpu_hw_events *cpuc = &per_cpu(cpu_hw_events, cpu); + struct pmu *pmu = x86_get_static_pmu(); release_arch_pebs_buf_on_cpu(cpu); intel_cpuc_finish(cpuc); - if (is_hybrid() && cpuc->pmu) + if (is_hybrid() && cpuc->pmu && cpuc->pmu != pmu) cpumask_clear_cpu(cpu, &hybrid_pmu(cpuc->pmu)->supported_cpus); } diff --git a/arch/x86/events/perf_event.h b/arch/x86/events/perf_event.h index efd3ab5d8fcb..a189aab5974a 100644 --- a/arch/x86/events/perf_event.h +++ b/arch/x86/events/perf_event.h @@ -1170,6 +1170,7 @@ static struct perf_pmu_format_hybrid_attr format_attr_hybrid_##_name = {\ .pmu_type = _pmu, \ } +struct pmu *x86_get_static_pmu(void); struct pmu *x86_get_pmu(unsigned int cpu); extern struct x86_pmu x86_pmu __read_mostly; -- Gitee From c1cd7f7d35fb779a82a325ab754409ef3232580d Mon Sep 17 00:00:00 2001 From: Dapeng Mi Date: Fri, 17 Jul 2026 16:03:38 +0800 Subject: [PATCH 17/20] perf/x86/intel: Unwind cpuc state if PEBS buffer setup fails ANBZ: #45489 commit 85182f902afda28ca7ae3408b72f31640a5cfc73 upstream. intel_pmu_cpu_prepare() allocates per-CPU perf state first and then sets up the arch PEBS buffer. If alloc_arch_pebs_buf_on_cpu() fails, the previously allocated cpuc resources are left behind. Make the failure path call intel_cpuc_finish(cpuc) to release the per-CPU state allocated by intel_cpuc_prepare(). Signed-off-by: Dapeng Mi Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Thomas Falcon Reviewed-by: Zide Chen Link: https://patch.msgid.link/20260717080342.1879573-5-dapeng1.mi@linux.intel.com Signed-off-by: Jason Zeng --- arch/x86/events/intel/core.c | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c index b6f002dc5906..b45172654a2d 100644 --- a/arch/x86/events/intel/core.c +++ b/arch/x86/events/intel/core.c @@ -5825,13 +5825,20 @@ int intel_cpuc_prepare(struct cpu_hw_events *cpuc, int cpu) static int intel_pmu_cpu_prepare(int cpu) { + struct cpu_hw_events *cpuc = &per_cpu(cpu_hw_events, cpu); int ret; - ret = intel_cpuc_prepare(&per_cpu(cpu_hw_events, cpu), cpu); + ret = intel_cpuc_prepare(cpuc, cpu); if (ret) return ret; - return alloc_arch_pebs_buf_on_cpu(cpu); + ret = alloc_arch_pebs_buf_on_cpu(cpu); + if (ret) { + intel_cpuc_finish(cpuc); + return ret; + } + + return 0; } static void flip_smm_bit(void *data) -- Gitee From b11c49a21ed436d81b8eadbf10759f0634809bb9 Mon Sep 17 00:00:00 2001 From: Dapeng Mi Date: Fri, 17 Jul 2026 16:03:39 +0800 Subject: [PATCH 18/20] perf/x86: Remove stale fixed counter helper and fix hybrid PMU access ANBZ: #45489 commit 3ba87c5bf11bea80e56abe17730085bc962ecfbe upstream. On hybrid systems, init_hw_perf_events() can call check_hw_exists() with the global PMU pointer after perf_is_hybrid is set. In that case, fixed_counter_disabled() uses hybrid() on a non-hybrid PMU object, so the intel_ctrl access is taken from the wrong layout and can read out of bounds. fixed_counter_disabled() was added in commit 32451614da2a ("perf/x86/intel: Support CPUID 10.ECX to disable fixed counters"), when fixed counters were tracked via num_fixed_counters. Today fixed counters are represented by fixed_cntr_mask, so this helper is obsolete. Remove fixed_counter_disabled() and its callers, and rely directly on the fixed-counter bitmask. With the helper gone, check_hw_exists() no longer needs a PMU argument, so drop that parameter as well. This removes the invalid hybrid access and closes the out-of-bounds read risk. Signed-off-by: Dapeng Mi Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Thomas Falcon Reviewed-by: Zide Chen Link: https://patch.msgid.link/20260717080342.1879573-6-dapeng1.mi@linux.intel.com Conflicts: arch/x86/events/core.c arch/x86/events/intel/core.c [jz: resolve context conflicts] Signed-off-by: Jason Zeng --- arch/x86/events/core.c | 8 ++------ arch/x86/events/intel/core.c | 4 +--- arch/x86/events/perf_event.h | 9 +-------- 3 files changed, 4 insertions(+), 17 deletions(-) diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c index 666b75d435cb..43724d6dfd5d 100644 --- a/arch/x86/events/core.c +++ b/arch/x86/events/core.c @@ -264,7 +264,7 @@ static void release_pmc_hardware(void) {} #endif -bool check_hw_exists(struct pmu *pmu, unsigned long *cntr_mask, +bool check_hw_exists(unsigned long *cntr_mask, unsigned long *fixed_cntr_mask) { u64 val, val_fail = -1, val_new= ~0; @@ -296,8 +296,6 @@ bool check_hw_exists(struct pmu *pmu, unsigned long *cntr_mask, if (ret) goto msr_fail; for_each_set_bit(i, fixed_cntr_mask, X86_PMC_IDX_MAX) { - if (fixed_counter_disabled(i, pmu)) - continue; if (val & (0x03ULL << i*4)) { bios_fail = 1; val_fail = val; @@ -1614,8 +1612,6 @@ void perf_event_print_debug(void) cpu, idx, prev_left); } for_each_set_bit(idx, fixed_cntr_mask, X86_PMC_IDX_MAX) { - if (fixed_counter_disabled(idx, cpuc->pmu)) - continue; rdmsrl(x86_pmu_fixed_ctr_addr(idx), pmc_count); pr_info("CPU#%d: fixed-PMC%d count: %016llx\n", @@ -2177,7 +2173,7 @@ static int __init init_hw_perf_events(void) pmu_check_apic(); /* sanity check that the hardware exists or is emulated */ - if (!check_hw_exists(&pmu, x86_pmu.cntr_mask, x86_pmu.fixed_cntr_mask)) + if (!check_hw_exists(x86_pmu.cntr_mask, x86_pmu.fixed_cntr_mask)) goto out_bad_pmu; pr_cont("%s PMU driver.\n", x86_pmu.name); diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c index b45172654a2d..6ef75eebd735 100644 --- a/arch/x86/events/intel/core.c +++ b/arch/x86/events/intel/core.c @@ -3641,8 +3641,6 @@ static void intel_pmu_reset(void) wrmsrl_safe(x86_pmu_event_addr(idx), 0ull); } for_each_set_bit(idx, fixed_cntr_mask, INTEL_PMC_MAX_FIXED) { - if (fixed_counter_disabled(idx, cpuc->pmu)) - continue; wrmsrl_safe(x86_pmu_fixed_ctr_addr(idx), 0ull); } @@ -6232,7 +6230,7 @@ static bool init_hybrid_pmu(int cpu) intel_pmu_check_hybrid_pmus(pmu); - if (!check_hw_exists(&pmu->pmu, pmu->cntr_mask, pmu->fixed_cntr_mask)) { + if (!check_hw_exists(pmu->cntr_mask, pmu->fixed_cntr_mask)) { cpuc->pmu = NULL; return false; } diff --git a/arch/x86/events/perf_event.h b/arch/x86/events/perf_event.h index a189aab5974a..c9dfd9ec7c76 100644 --- a/arch/x86/events/perf_event.h +++ b/arch/x86/events/perf_event.h @@ -1252,7 +1252,7 @@ static inline int x86_pmu_rdpmc_index(int index) return x86_pmu.rdpmc_index ? x86_pmu.rdpmc_index(index) : index; } -bool check_hw_exists(struct pmu *pmu, unsigned long *cntr_mask, +bool check_hw_exists(unsigned long *cntr_mask, unsigned long *fixed_cntr_mask); int x86_add_exclusive(unsigned int what); @@ -1465,13 +1465,6 @@ ssize_t events_hybrid_sysfs_show(struct device *dev, struct device_attribute *attr, char *page); -static inline bool fixed_counter_disabled(int i, struct pmu *pmu) -{ - u64 intel_ctrl = hybrid(pmu, intel_ctrl); - - return !(intel_ctrl >> (i + INTEL_PMC_IDX_FIXED)); -} - #ifdef CONFIG_CPU_SUP_AMD int amd_pmu_init(void); -- Gitee From 6dc4103b41f7f027b09f305e5941f18488881abd Mon Sep 17 00:00:00 2001 From: Dapeng Mi Date: Fri, 17 Jul 2026 16:03:40 +0800 Subject: [PATCH 19/20] perf/x86/intel: Fix intel_cap handling on hybrid PMUs ANBZ: #45489 commit dd384d661f06e3725aad3a932a53e0ff81fb8805 upstream. intel_cap (IA32_PERF_CAPABILITIES) updates are currently tied to X86_FEATURE_ARCH_PERFMON_EXT, but these are independent feature paths. As a result, hybrid PMU capability state can be updated under the wrong condition. Also, intel_pmu_broken_perf_cap() is too narrow. Per RPL018, the missing PERF_METRICS_AVAILABLE bit affects both Raptor Lake and Meteor Lake parts, not only the currently covered subset. Move intel_cap updates out of the ARCH_PERFMON_EXT-gated path, extend intel_pmu_broken_perf_cap() coverage to both RPL and MTL families, and introduce intel_update_pmu_caps() to centralize PMU capability updates. Signed-off-by: Dapeng Mi Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Thomas Falcon Reviewed-by: Zide Chen Link: https://patch.msgid.link/20260717080342.1879573-7-dapeng1.mi@linux.intel.com Conflicts: arch/x86/events/intel/core.c [jz: - resolve context conflicts - use rdmsrl instead of rdmsrq] Signed-off-by: Jason Zeng --- arch/x86/events/intel/core.c | 40 ++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 11 deletions(-) diff --git a/arch/x86/events/intel/core.c b/arch/x86/events/intel/core.c index 6ef75eebd735..83cacd5c682e 100644 --- a/arch/x86/events/intel/core.c +++ b/arch/x86/events/intel/core.c @@ -6048,8 +6048,14 @@ static void intel_pmu_check_extra_regs(struct extra_reg *extra_regs); static inline bool intel_pmu_broken_perf_cap(void) { - /* The Perf Metric (Bit 15) is always cleared */ - if (boot_cpu_data.x86_vfm == INTEL_METEORLAKE || + /* + * The Perf Metric (Bit 15) is always cleared on P-core of + * RPL and MTL. Details can be found in RPL018 erratum. + */ + if (boot_cpu_data.x86_vfm == INTEL_RAPTORLAKE || + boot_cpu_data.x86_vfm == INTEL_RAPTORLAKE_P || + boot_cpu_data.x86_vfm == INTEL_RAPTORLAKE_S || + boot_cpu_data.x86_vfm == INTEL_METEORLAKE || boot_cpu_data.x86_vfm == INTEL_METEORLAKE_L) return true; @@ -6084,7 +6090,7 @@ static inline void __intel_update_large_pebs_flags(struct pmu *pmu) #define counter_mask(_gp, _fixed) ((_gp) | ((u64)(_fixed) << INTEL_PMC_IDX_FIXED)) -static void update_pmu_cap(struct pmu *pmu) +static void update_pmu_cap_from_perfmonext(struct pmu *pmu) { unsigned int eax, ebx, ecx, edx; union cpuid35_eax eax_0; @@ -6142,10 +6148,24 @@ static void update_pmu_cap(struct pmu *pmu) WARN_ON(x86_pmu.arch_pebs == 1); x86_pmu.arch_pebs = 0; } +} + +static void intel_update_pmu_caps(struct pmu *pmu) +{ + if (this_cpu_has(X86_FEATURE_ARCH_PERFMON_EXT)) + update_pmu_cap_from_perfmonext(pmu); - if (!intel_pmu_broken_perf_cap()) { - /* Perf Metric (Bit 15) and PEBS via PT (Bit 16) are hybrid enumeration */ - rdmsrl(MSR_IA32_PERF_CAPABILITIES, hybrid(pmu, intel_cap).capabilities); + if (is_hybrid() && this_cpu_has(X86_FEATURE_PDCM)) { + rdmsrl(MSR_IA32_PERF_CAPABILITIES, + hybrid(pmu, intel_cap).capabilities); + + /* + * Restore perf_metrics on platforms with broken + * perf_capablities. + */ + if (intel_pmu_broken_perf_cap() && + hybrid_pmu(pmu)->pmu_type == hybrid_big) + hybrid(pmu, intel_cap).perf_metrics = 1; } } @@ -6225,9 +6245,7 @@ static bool init_hybrid_pmu(int cpu) if (!cpumask_empty(&pmu->supported_cpus)) goto end; - if (this_cpu_has(X86_FEATURE_ARCH_PERFMON_EXT)) - update_pmu_cap(&pmu->pmu); - + intel_update_pmu_caps(&pmu->pmu); intel_pmu_check_hybrid_pmus(pmu); if (!check_hw_exists(pmu->cntr_mask, pmu->fixed_cntr_mask)) { @@ -8615,8 +8633,8 @@ __init int intel_pmu_init(void) * from the leaf 0xa. The core specific update will be done later * when a new type is online. */ - if (!is_hybrid() && boot_cpu_has(X86_FEATURE_ARCH_PERFMON_EXT)) - update_pmu_cap(NULL); + if (!is_hybrid()) + intel_update_pmu_caps(NULL); if (x86_pmu.arch_pebs) { static_call_update(intel_pmu_disable_event_ext, -- Gitee From 5a6018a500f0e666ba13e13919878f5c872c06cf Mon Sep 17 00:00:00 2001 From: Dapeng Mi Date: Fri, 17 Jul 2026 16:03:41 +0800 Subject: [PATCH 20/20] perf/x86: Optimize ACR handling in match_prev_assignment() ANBZ: #45489 commit 917d558b151cad5b05991e5eaee22efab33525ca upstream. match_prev_assignment() currently forces a mismatch for ACR events, so ACR counter indices are reprogrammed on every scheduling pass. That causes avoidable overhead because disable and enable paths must touch multiple MSRs. The previous ACR assignment is already cached in acr_cfg_b[]. Use that state to compare the newly computed ACR counter indices in hwc->config1 against the cached value in acr_cfg_b[hwc->idx]. If they match, skip unnecessary disable and enable work. Also tighten is_acr_self_reload_event() so it first verifies the event is an ACR event before testing for the self-reload case. Signed-off-by: Dapeng Mi Signed-off-by: Peter Zijlstra (Intel) Reviewed-by: Thomas Falcon Reviewed-by: Zide Chen Link: https://patch.msgid.link/20260717080342.1879573-8-dapeng1.mi@linux.intel.com Signed-off-by: Jason Zeng --- arch/x86/events/core.c | 13 ++++++++++++- arch/x86/events/perf_event.h | 2 +- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/arch/x86/events/core.c b/arch/x86/events/core.c index 43724d6dfd5d..07396f96b508 100644 --- a/arch/x86/events/core.c +++ b/arch/x86/events/core.c @@ -1296,6 +1296,17 @@ int x86_perf_rdpmc_index(struct perf_event *event) return event->hw.event_base_rdpmc; } +static inline bool acr_match_prev_indices(struct perf_event *event, + struct cpu_hw_events *cpuc) +{ + struct hw_perf_event *hwc = &event->hw; + + if (!is_acr_event_group(event)) + return true; + /* ACR counter indices don't change. */ + return hwc->config1 == cpuc->acr_cfg_b[hwc->idx]; +} + static inline int match_prev_assignment(struct perf_event *event, struct cpu_hw_events *cpuc, int i) @@ -1305,7 +1316,7 @@ static inline int match_prev_assignment(struct perf_event *event, return hwc->idx == cpuc->assign[i] && hwc->last_cpu == smp_processor_id() && hwc->last_tag == cpuc->tags[i] && - !is_acr_event_group(event); + acr_match_prev_indices(event, cpuc); } static void x86_pmu_start(struct perf_event *event, int flags); diff --git a/arch/x86/events/perf_event.h b/arch/x86/events/perf_event.h index c9dfd9ec7c76..2344ac07e649 100644 --- a/arch/x86/events/perf_event.h +++ b/arch/x86/events/perf_event.h @@ -140,7 +140,7 @@ static inline bool is_acr_self_reload_event(struct perf_event *event) { struct hw_perf_event *hwc = &event->hw; - if (hwc->idx < 0) + if (hwc->idx < 0 || !is_acr_event_group(event)) return false; return test_bit(hwc->idx, (unsigned long *)&hwc->config1); -- Gitee