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

riscv: Add support for perf registers sampling

This patch implements the perf registers sampling and validation API
for the riscv arch. The valid registers and their register ID are
defined in perf_regs.h. Perf tool can backtrace in userspace with
unwind library and the registers/user stack dump support.

Signed-off-by: Mao Han <han_mao@c-sky.com>
Cc: Paul Walmsley <paul.walmsley@sifive.com>
Cc: Greentime Hu <green.hu@gmail.com>
Cc: Palmer Dabbelt <palmer@sifive.com>
Cc: linux-riscv <linux-riscv@lists.infradead.org>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Guo Ren <guoren@kernel.org>
Tested-by: Greentime Hu <greentime.hu@sifive.com>
[paul.walmsley@sifive.com: minor patch description fix]
Signed-off-by: Paul Walmsley <paul.walmsley@sifive.com>

authored by

Mao Han and committed by
Paul Walmsley
98a93b0b dbeb90b0

+89
+2
arch/riscv/Kconfig
··· 35 35 select HAVE_DMA_CONTIGUOUS 36 36 select HAVE_FUTEX_CMPXCHG if FUTEX 37 37 select HAVE_PERF_EVENTS 38 + select HAVE_PERF_REGS 39 + select HAVE_PERF_USER_STACK_DUMP 38 40 select HAVE_SYSCALL_TRACEPOINTS 39 41 select IRQ_DOMAIN 40 42 select SPARSE_IRQ
+42
arch/riscv/include/uapi/asm/perf_regs.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */ 2 + /* Copyright (C) 2019 Hangzhou C-SKY Microsystems co.,ltd. */ 3 + 4 + #ifndef _ASM_RISCV_PERF_REGS_H 5 + #define _ASM_RISCV_PERF_REGS_H 6 + 7 + enum perf_event_riscv_regs { 8 + PERF_REG_RISCV_PC, 9 + PERF_REG_RISCV_RA, 10 + PERF_REG_RISCV_SP, 11 + PERF_REG_RISCV_GP, 12 + PERF_REG_RISCV_TP, 13 + PERF_REG_RISCV_T0, 14 + PERF_REG_RISCV_T1, 15 + PERF_REG_RISCV_T2, 16 + PERF_REG_RISCV_S0, 17 + PERF_REG_RISCV_S1, 18 + PERF_REG_RISCV_A0, 19 + PERF_REG_RISCV_A1, 20 + PERF_REG_RISCV_A2, 21 + PERF_REG_RISCV_A3, 22 + PERF_REG_RISCV_A4, 23 + PERF_REG_RISCV_A5, 24 + PERF_REG_RISCV_A6, 25 + PERF_REG_RISCV_A7, 26 + PERF_REG_RISCV_S2, 27 + PERF_REG_RISCV_S3, 28 + PERF_REG_RISCV_S4, 29 + PERF_REG_RISCV_S5, 30 + PERF_REG_RISCV_S6, 31 + PERF_REG_RISCV_S7, 32 + PERF_REG_RISCV_S8, 33 + PERF_REG_RISCV_S9, 34 + PERF_REG_RISCV_S10, 35 + PERF_REG_RISCV_S11, 36 + PERF_REG_RISCV_T3, 37 + PERF_REG_RISCV_T4, 38 + PERF_REG_RISCV_T5, 39 + PERF_REG_RISCV_T6, 40 + PERF_REG_RISCV_MAX, 41 + }; 42 + #endif /* _ASM_RISCV_PERF_REGS_H */
+1
arch/riscv/kernel/Makefile
··· 40 40 41 41 obj-$(CONFIG_PERF_EVENTS) += perf_event.o 42 42 obj-$(CONFIG_PERF_EVENTS) += perf_callchain.o 43 + obj-$(CONFIG_HAVE_PERF_REGS) += perf_regs.o 43 44 44 45 clean:
+44
arch/riscv/kernel/perf_regs.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* Copyright (C) 2019 Hangzhou C-SKY Microsystems co.,ltd. */ 3 + 4 + #include <linux/errno.h> 5 + #include <linux/kernel.h> 6 + #include <linux/perf_event.h> 7 + #include <linux/bug.h> 8 + #include <asm/perf_regs.h> 9 + #include <asm/ptrace.h> 10 + 11 + u64 perf_reg_value(struct pt_regs *regs, int idx) 12 + { 13 + if (WARN_ON_ONCE((u32)idx >= PERF_REG_RISCV_MAX)) 14 + return 0; 15 + 16 + return ((unsigned long *)regs)[idx]; 17 + } 18 + 19 + #define REG_RESERVED (~((1ULL << PERF_REG_RISCV_MAX) - 1)) 20 + 21 + int perf_reg_validate(u64 mask) 22 + { 23 + if (!mask || mask & REG_RESERVED) 24 + return -EINVAL; 25 + 26 + return 0; 27 + } 28 + 29 + u64 perf_reg_abi(struct task_struct *task) 30 + { 31 + #if __riscv_xlen == 64 32 + return PERF_SAMPLE_REGS_ABI_64; 33 + #else 34 + return PERF_SAMPLE_REGS_ABI_32; 35 + #endif 36 + } 37 + 38 + void perf_get_regs_user(struct perf_regs *regs_user, 39 + struct pt_regs *regs, 40 + struct pt_regs *regs_user_copy) 41 + { 42 + regs_user->regs = task_pt_regs(current); 43 + regs_user->abi = perf_reg_abi(current); 44 + }