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

ARM64: perf: add support for perf registers API

This patch implements the functions required for the perf registers API,
allowing the perf tool to interface kernel register dumps with libunwind
in order to provide userspace backtracing.
Compat mode is also supported.

Only the general purpose user space registers are exported, i.e.:
PERF_REG_ARM_X0,
...
PERF_REG_ARM_X28,
PERF_REG_ARM_FP,
PERF_REG_ARM_LR,
PERF_REG_ARM_SP,
PERF_REG_ARM_PC
and not the PERF_REG_ARM_V* registers.

Signed-off-by: Jean Pihet <jean.pihet@linaro.org>
Acked-by: Will Deacon <will.deacon@arm.com>
Signed-off-by: Catalin Marinas <catalin.marinas@arm.com>

authored by

Jean Pihet and committed by
Catalin Marinas
2ee0d7fd 87366d8c

+90 -1
+2
arch/arm64/Kconfig
··· 39 39 select HAVE_MEMBLOCK 40 40 select HAVE_PATA_PLATFORM 41 41 select HAVE_PERF_EVENTS 42 + select HAVE_PERF_REGS 43 + select HAVE_PERF_USER_STACK_DUMP 42 44 select IRQ_DOMAIN 43 45 select MODULES_USE_ELF_RELA 44 46 select NO_BOOTMEM
+1
arch/arm64/include/asm/ptrace.h
··· 68 68 69 69 /* Architecturally defined mapping between AArch32 and AArch64 registers */ 70 70 #define compat_usr(x) regs[(x)] 71 + #define compat_fp regs[11] 71 72 #define compat_sp regs[13] 72 73 #define compat_lr regs[14] 73 74 #define compat_sp_hyp regs[15]
+1
arch/arm64/include/uapi/asm/Kbuild
··· 9 9 header-y += fcntl.h 10 10 header-y += hwcap.h 11 11 header-y += kvm_para.h 12 + header-y += perf_regs.h 12 13 header-y += param.h 13 14 header-y += ptrace.h 14 15 header-y += setup.h
+40
arch/arm64/include/uapi/asm/perf_regs.h
··· 1 + #ifndef _ASM_ARM64_PERF_REGS_H 2 + #define _ASM_ARM64_PERF_REGS_H 3 + 4 + enum perf_event_arm_regs { 5 + PERF_REG_ARM64_X0, 6 + PERF_REG_ARM64_X1, 7 + PERF_REG_ARM64_X2, 8 + PERF_REG_ARM64_X3, 9 + PERF_REG_ARM64_X4, 10 + PERF_REG_ARM64_X5, 11 + PERF_REG_ARM64_X6, 12 + PERF_REG_ARM64_X7, 13 + PERF_REG_ARM64_X8, 14 + PERF_REG_ARM64_X9, 15 + PERF_REG_ARM64_X10, 16 + PERF_REG_ARM64_X11, 17 + PERF_REG_ARM64_X12, 18 + PERF_REG_ARM64_X13, 19 + PERF_REG_ARM64_X14, 20 + PERF_REG_ARM64_X15, 21 + PERF_REG_ARM64_X16, 22 + PERF_REG_ARM64_X17, 23 + PERF_REG_ARM64_X18, 24 + PERF_REG_ARM64_X19, 25 + PERF_REG_ARM64_X20, 26 + PERF_REG_ARM64_X21, 27 + PERF_REG_ARM64_X22, 28 + PERF_REG_ARM64_X23, 29 + PERF_REG_ARM64_X24, 30 + PERF_REG_ARM64_X25, 31 + PERF_REG_ARM64_X26, 32 + PERF_REG_ARM64_X27, 33 + PERF_REG_ARM64_X28, 34 + PERF_REG_ARM64_X29, 35 + PERF_REG_ARM64_LR, 36 + PERF_REG_ARM64_SP, 37 + PERF_REG_ARM64_PC, 38 + PERF_REG_ARM64_MAX, 39 + }; 40 + #endif /* _ASM_ARM64_PERF_REGS_H */
+2 -1
arch/arm64/kernel/Makefile
··· 15 15 sys_compat.o 16 16 arm64-obj-$(CONFIG_MODULES) += arm64ksyms.o module.o 17 17 arm64-obj-$(CONFIG_SMP) += smp.o smp_spin_table.o topology.o 18 + arm64-obj-$(CONFIG_PERF_EVENTS) += perf_regs.o 18 19 arm64-obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o 19 - arm64-obj-$(CONFIG_HAVE_HW_BREAKPOINT)+= hw_breakpoint.o 20 + arm64-obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o 20 21 arm64-obj-$(CONFIG_EARLY_PRINTK) += early_printk.o 21 22 arm64-obj-$(CONFIG_ARM64_CPU_SUSPEND) += sleep.o suspend.o 22 23 arm64-obj-$(CONFIG_JUMP_LABEL) += jump_label.o
+44
arch/arm64/kernel/perf_regs.c
··· 1 + #include <linux/errno.h> 2 + #include <linux/kernel.h> 3 + #include <linux/perf_event.h> 4 + #include <linux/bug.h> 5 + #include <asm/perf_regs.h> 6 + #include <asm/ptrace.h> 7 + 8 + u64 perf_reg_value(struct pt_regs *regs, int idx) 9 + { 10 + if (WARN_ON_ONCE((u32)idx >= PERF_REG_ARM64_MAX)) 11 + return 0; 12 + 13 + /* 14 + * Compat (i.e. 32 bit) mode: 15 + * - PC has been set in the pt_regs struct in kernel_entry, 16 + * - Handle SP and LR here. 17 + */ 18 + if (compat_user_mode(regs)) { 19 + if ((u32)idx == PERF_REG_ARM64_SP) 20 + return regs->compat_sp; 21 + if ((u32)idx == PERF_REG_ARM64_LR) 22 + return regs->compat_lr; 23 + } 24 + 25 + return regs->regs[idx]; 26 + } 27 + 28 + #define REG_RESERVED (~((1ULL << PERF_REG_ARM64_MAX) - 1)) 29 + 30 + int perf_reg_validate(u64 mask) 31 + { 32 + if (!mask || mask & REG_RESERVED) 33 + return -EINVAL; 34 + 35 + return 0; 36 + } 37 + 38 + u64 perf_reg_abi(struct task_struct *task) 39 + { 40 + if (is_compat_thread(task_thread_info(task))) 41 + return PERF_SAMPLE_REGS_ABI_32; 42 + else 43 + return PERF_SAMPLE_REGS_ABI_64; 44 + }