mirror of
git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-08-05 16:54:27 +00:00

The ARMv9.2 architecture introduces the optional Branch Record Buffer Extension (BRBE), which records information about branches as they are executed into set of branch record registers. BRBE is similar to x86's Last Branch Record (LBR) and PowerPC's Branch History Rolling Buffer (BHRB). BRBE supports filtering by exception level and can filter just the source or target address if excluded to avoid leaking privileged addresses. The h/w filter would be sufficient except when there are multiple events with disjoint filtering requirements. In this case, BRBE is configured with a union of all the events' desired branches, and then the recorded branches are filtered based on each event's filter. For example, with one event capturing kernel events and another event capturing user events, BRBE will be configured to capture both kernel and user branches. When handling event overflow, the branch records have to be filtered by software to only include kernel or user branch addresses for that event. In contrast, x86 simply configures LBR using the last installed event which seems broken. It is possible on x86 to configure branch filter such that no branches are ever recorded (e.g. -j save_type). For BRBE, events with a configuration that will result in no samples are rejected. Recording branches in KVM guests is not supported like x86. However, perf on x86 allows requesting branch recording in guests. The guest events are recorded, but the resulting branches are all from the host. For BRBE, events with branch recording and "exclude_host" set are rejected. Requiring "exclude_guest" to be set did not work. The default for the perf tool does set "exclude_guest" if no exception level options are specified. However, specifying kernel or user events defaults to including both host and guest. In this case, only host branches are recorded. BRBE can support some additional exception branch types compared to x86. On x86, all exceptions other than syscalls are recorded as IRQ. With BRBE, it is possible to better categorize these exceptions. One limitation relative to x86 is we cannot distinguish a syscall return from other exception returns. So all exception returns are recorded as ERET type. The FIQ branch type is omitted as the only FIQ user is Apple platforms which don't support BRBE. The debug branch types are omitted as there is no clear need for them. BRBE records are invalidated whenever events are reconfigured, a new task is scheduled in, or after recording is paused (and the records have been recorded for the event). The architecture allows branch records to be invalidated by the PE under implementation defined conditions. It is expected that these conditions are rare. Cc: Catalin Marinas <catalin.marinas@arm.com> Co-developed-by: Anshuman Khandual <anshuman.khandual@arm.com> Signed-off-by: Anshuman Khandual <anshuman.khandual@arm.com> Co-developed-by: Mark Rutland <mark.rutland@arm.com> Signed-off-by: Mark Rutland <mark.rutland@arm.com> Tested-by: James Clark <james.clark@linaro.org> Signed-off-by: Rob Herring (Arm) <robh@kernel.org> tested-by: Adam Young <admiyo@os.amperecomputing.com> Acked-by: Mark Rutland <mark.rutland@arm.com> Link: https://lore.kernel.org/r/20250611-arm-brbe-v19-v23-4-e7775563036e@kernel.org [will: Fix sparse warnings about mixed declarations and code. Fix C99 comment syntax.] Signed-off-by: Will Deacon <will@kernel.org>
47 lines
1.2 KiB
C
47 lines
1.2 KiB
C
/* SPDX-License-Identifier: GPL-2.0-only */
|
|
/*
|
|
* Branch Record Buffer Extension Helpers.
|
|
*
|
|
* Copyright (C) 2022-2025 ARM Limited
|
|
*
|
|
* Author: Anshuman Khandual <anshuman.khandual@arm.com>
|
|
*/
|
|
|
|
struct arm_pmu;
|
|
struct perf_branch_stack;
|
|
struct perf_event;
|
|
|
|
#ifdef CONFIG_ARM64_BRBE
|
|
void brbe_probe(struct arm_pmu *arm_pmu);
|
|
unsigned int brbe_num_branch_records(const struct arm_pmu *armpmu);
|
|
void brbe_invalidate(void);
|
|
|
|
void brbe_enable(const struct arm_pmu *arm_pmu);
|
|
void brbe_disable(void);
|
|
|
|
bool brbe_branch_attr_valid(struct perf_event *event);
|
|
void brbe_read_filtered_entries(struct perf_branch_stack *branch_stack,
|
|
const struct perf_event *event);
|
|
#else
|
|
static inline void brbe_probe(struct arm_pmu *arm_pmu) { }
|
|
static inline unsigned int brbe_num_branch_records(const struct arm_pmu *armpmu)
|
|
{
|
|
return 0;
|
|
}
|
|
|
|
static inline void brbe_invalidate(void) { }
|
|
|
|
static inline void brbe_enable(const struct arm_pmu *arm_pmu) { };
|
|
static inline void brbe_disable(void) { };
|
|
|
|
static inline bool brbe_branch_attr_valid(struct perf_event *event)
|
|
{
|
|
WARN_ON_ONCE(!has_branch_stack(event));
|
|
return false;
|
|
}
|
|
|
|
static void brbe_read_filtered_entries(struct perf_branch_stack *branch_stack,
|
|
const struct perf_event *event)
|
|
{
|
|
}
|
|
#endif
|