parisc: Add initial kernel-side perf_event support

Signed-off-by: Helge Deller <deller@gmx.de>
This commit is contained in:
Helge Deller
2025-10-07 17:08:16 +02:00
parent 912b9fd7c7
commit 610cb23bcc
6 changed files with 162 additions and 1 deletions

View File

@@ -31,6 +31,9 @@ config PARISC
select HAVE_KERNEL_UNCOMPRESSED
select HAVE_PCI
select HAVE_PERF_EVENTS
select HAVE_PERF_REGS
select HAVE_PERF_USER_STACK_DUMP
select PERF_USE_VMALLOC
select HAVE_KERNEL_BZIP2
select HAVE_KERNEL_GZIP
select HAVE_KERNEL_LZ4

View File

@@ -1,6 +1,12 @@
#ifndef __ASM_PARISC_PERF_EVENT_H
#define __ASM_PARISC_PERF_EVENT_H
/* Empty, just to avoid compiling error */
#include <asm/psw.h>
#define perf_arch_fetch_caller_regs(regs, __ip) { \
(regs)->gr[0] = KERNEL_PSW; \
(regs)->iaoq[0] = (__ip); \
asm volatile("copy %%sp, %0\n":"=r"((regs)->gr[30])); \
}
#endif /* __ASM_PARISC_PERF_EVENT_H */

View File

@@ -0,0 +1,63 @@
/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
#ifndef _UAPI_ASM_PARISC_PERF_REGS_H
#define _UAPI_ASM_PARISC_PERF_REGS_H
/* see struct user_regs_struct */
enum perf_event_parisc_regs {
PERF_REG_PARISC_R0, /* PSW is in gr[0] */
PERF_REG_PARISC_R1,
PERF_REG_PARISC_R2,
PERF_REG_PARISC_R3,
PERF_REG_PARISC_R4,
PERF_REG_PARISC_R5,
PERF_REG_PARISC_R6,
PERF_REG_PARISC_R7,
PERF_REG_PARISC_R8,
PERF_REG_PARISC_R9,
PERF_REG_PARISC_R10,
PERF_REG_PARISC_R11,
PERF_REG_PARISC_R12,
PERF_REG_PARISC_R13,
PERF_REG_PARISC_R14,
PERF_REG_PARISC_R15,
PERF_REG_PARISC_R16,
PERF_REG_PARISC_R17,
PERF_REG_PARISC_R18,
PERF_REG_PARISC_R19,
PERF_REG_PARISC_R20,
PERF_REG_PARISC_R21,
PERF_REG_PARISC_R22,
PERF_REG_PARISC_R23,
PERF_REG_PARISC_R24,
PERF_REG_PARISC_R25,
PERF_REG_PARISC_R26,
PERF_REG_PARISC_R27,
PERF_REG_PARISC_R28,
PERF_REG_PARISC_R29,
PERF_REG_PARISC_R30,
PERF_REG_PARISC_R31,
PERF_REG_PARISC_SR0,
PERF_REG_PARISC_SR1,
PERF_REG_PARISC_SR2,
PERF_REG_PARISC_SR3,
PERF_REG_PARISC_SR4,
PERF_REG_PARISC_SR5,
PERF_REG_PARISC_SR6,
PERF_REG_PARISC_SR7,
PERF_REG_PARISC_IAOQ0,
PERF_REG_PARISC_IAOQ1,
PERF_REG_PARISC_IASQ0,
PERF_REG_PARISC_IASQ1,
PERF_REG_PARISC_SAR, /* CR11 */
PERF_REG_PARISC_IIR, /* CR19 */
PERF_REG_PARISC_ISR, /* CR20 */
PERF_REG_PARISC_IOR, /* CR21 */
PERF_REG_PARISC_IPSW, /* CR22 */
PERF_REG_PARISC_MAX
};
#endif /* _UAPI_ASM_PARISC_PERF_REGS_H */

View File

@@ -38,6 +38,7 @@ obj-$(CONFIG_GENERIC_ARCH_TOPOLOGY) += topology.o
obj-$(CONFIG_FUNCTION_TRACER) += ftrace.o
obj-$(CONFIG_FUNCTION_GRAPH_TRACER) += ftrace.o
obj-$(CONFIG_JUMP_LABEL) += jump_label.o
obj-$(CONFIG_PERF_EVENTS) += perf_event.o perf_regs.o
obj-$(CONFIG_KGDB) += kgdb.o
obj-$(CONFIG_KPROBES) += kprobes.o
obj-$(CONFIG_KEXEC_CORE) += kexec.o relocate_kernel.o

View File

@@ -0,0 +1,27 @@
// SPDX-License-Identifier: GPL-2.0
/*
* Performance event support for parisc
*
* Copyright (C) 2025 by Helge Deller <deller@gmx.de>
*/
#include <linux/kernel.h>
#include <linux/perf_event.h>
#include <asm/unwind.h>
void perf_callchain_kernel(struct perf_callchain_entry_ctx *entry,
struct pt_regs *regs)
{
struct unwind_frame_info info;
unwind_frame_init_task(&info, current, NULL);
while (1) {
if (unwind_once(&info) < 0 || info.ip == 0)
break;
if (!__kernel_text_address(info.ip) ||
perf_callchain_store(entry, info.ip))
return;
}
}

View File

@@ -0,0 +1,61 @@
// SPDX-License-Identifier: GPL-2.0
/* Copyright (C) 2025 by Helge Deller <deller@gmx.de> */
#include <linux/perf_event.h>
#include <linux/perf_regs.h>
#include <asm/ptrace.h>
u64 perf_reg_value(struct pt_regs *regs, int idx)
{
switch (idx) {
case PERF_REG_PARISC_R0 ... PERF_REG_PARISC_R31:
return regs->gr[idx - PERF_REG_PARISC_R0];
case PERF_REG_PARISC_SR0 ... PERF_REG_PARISC_SR7:
return regs->sr[idx - PERF_REG_PARISC_SR0];
case PERF_REG_PARISC_IASQ0 ... PERF_REG_PARISC_IASQ1:
return regs->iasq[idx - PERF_REG_PARISC_IASQ0];
case PERF_REG_PARISC_IAOQ0 ... PERF_REG_PARISC_IAOQ1:
return regs->iasq[idx - PERF_REG_PARISC_IAOQ0];
case PERF_REG_PARISC_SAR: /* CR11 */
return regs->sar;
case PERF_REG_PARISC_IIR: /* CR19 */
return regs->iir;
case PERF_REG_PARISC_ISR: /* CR20 */
return regs->isr;
case PERF_REG_PARISC_IOR: /* CR21 */
return regs->ior;
case PERF_REG_PARISC_IPSW: /* CR22 */
return regs->ipsw;
};
WARN_ON_ONCE((u32)idx >= PERF_REG_PARISC_MAX);
return 0;
}
#define REG_RESERVED (~((1ULL << PERF_REG_PARISC_MAX) - 1))
int perf_reg_validate(u64 mask)
{
if (!mask || mask & REG_RESERVED)
return -EINVAL;
return 0;
}
u64 perf_reg_abi(struct task_struct *task)
{
if (!IS_ENABLED(CONFIG_64BIT))
return PERF_SAMPLE_REGS_ABI_32;
if (test_tsk_thread_flag(task, TIF_32BIT))
return PERF_SAMPLE_REGS_ABI_32;
return PERF_SAMPLE_REGS_ABI_64;
}
void perf_get_regs_user(struct perf_regs *regs_user,
struct pt_regs *regs)
{
regs_user->regs = task_pt_regs(current);
regs_user->abi = perf_reg_abi(current);
}