Skip to content

Commit

Permalink
ARM64: perf: add support for perf registers API
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Jean Pihet authored and Catalin Marinas committed Mar 13, 2014
1 parent 87366d8 commit 2ee0d7f
Show file tree
Hide file tree
Showing 6 changed files with 90 additions and 1 deletion.
2 changes: 2 additions & 0 deletions arch/arm64/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ config ARM64
select HAVE_MEMBLOCK
select HAVE_PATA_PLATFORM
select HAVE_PERF_EVENTS
select HAVE_PERF_REGS
select HAVE_PERF_USER_STACK_DUMP
select IRQ_DOMAIN
select MODULES_USE_ELF_RELA
select NO_BOOTMEM
Expand Down
1 change: 1 addition & 0 deletions arch/arm64/include/asm/ptrace.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@

/* Architecturally defined mapping between AArch32 and AArch64 registers */
#define compat_usr(x) regs[(x)]
#define compat_fp regs[11]
#define compat_sp regs[13]
#define compat_lr regs[14]
#define compat_sp_hyp regs[15]
Expand Down
1 change: 1 addition & 0 deletions arch/arm64/include/uapi/asm/Kbuild
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ header-y += byteorder.h
header-y += fcntl.h
header-y += hwcap.h
header-y += kvm_para.h
header-y += perf_regs.h
header-y += param.h
header-y += ptrace.h
header-y += setup.h
Expand Down
40 changes: 40 additions & 0 deletions arch/arm64/include/uapi/asm/perf_regs.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#ifndef _ASM_ARM64_PERF_REGS_H
#define _ASM_ARM64_PERF_REGS_H

enum perf_event_arm_regs {
PERF_REG_ARM64_X0,
PERF_REG_ARM64_X1,
PERF_REG_ARM64_X2,
PERF_REG_ARM64_X3,
PERF_REG_ARM64_X4,
PERF_REG_ARM64_X5,
PERF_REG_ARM64_X6,
PERF_REG_ARM64_X7,
PERF_REG_ARM64_X8,
PERF_REG_ARM64_X9,
PERF_REG_ARM64_X10,
PERF_REG_ARM64_X11,
PERF_REG_ARM64_X12,
PERF_REG_ARM64_X13,
PERF_REG_ARM64_X14,
PERF_REG_ARM64_X15,
PERF_REG_ARM64_X16,
PERF_REG_ARM64_X17,
PERF_REG_ARM64_X18,
PERF_REG_ARM64_X19,
PERF_REG_ARM64_X20,
PERF_REG_ARM64_X21,
PERF_REG_ARM64_X22,
PERF_REG_ARM64_X23,
PERF_REG_ARM64_X24,
PERF_REG_ARM64_X25,
PERF_REG_ARM64_X26,
PERF_REG_ARM64_X27,
PERF_REG_ARM64_X28,
PERF_REG_ARM64_X29,
PERF_REG_ARM64_LR,
PERF_REG_ARM64_SP,
PERF_REG_ARM64_PC,
PERF_REG_ARM64_MAX,
};
#endif /* _ASM_ARM64_PERF_REGS_H */
3 changes: 2 additions & 1 deletion arch/arm64/kernel/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,9 @@ arm64-obj-$(CONFIG_COMPAT) += sys32.o kuser32.o signal32.o \
sys_compat.o
arm64-obj-$(CONFIG_MODULES) += arm64ksyms.o module.o
arm64-obj-$(CONFIG_SMP) += smp.o smp_spin_table.o topology.o
arm64-obj-$(CONFIG_PERF_EVENTS) += perf_regs.o
arm64-obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o
arm64-obj-$(CONFIG_HAVE_HW_BREAKPOINT)+= hw_breakpoint.o
arm64-obj-$(CONFIG_HAVE_HW_BREAKPOINT) += hw_breakpoint.o
arm64-obj-$(CONFIG_EARLY_PRINTK) += early_printk.o
arm64-obj-$(CONFIG_ARM64_CPU_SUSPEND) += sleep.o suspend.o
arm64-obj-$(CONFIG_JUMP_LABEL) += jump_label.o
Expand Down
44 changes: 44 additions & 0 deletions arch/arm64/kernel/perf_regs.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
#include <linux/errno.h>
#include <linux/kernel.h>
#include <linux/perf_event.h>
#include <linux/bug.h>
#include <asm/perf_regs.h>
#include <asm/ptrace.h>

u64 perf_reg_value(struct pt_regs *regs, int idx)
{
if (WARN_ON_ONCE((u32)idx >= PERF_REG_ARM64_MAX))
return 0;

/*
* Compat (i.e. 32 bit) mode:
* - PC has been set in the pt_regs struct in kernel_entry,
* - Handle SP and LR here.
*/
if (compat_user_mode(regs)) {
if ((u32)idx == PERF_REG_ARM64_SP)
return regs->compat_sp;
if ((u32)idx == PERF_REG_ARM64_LR)
return regs->compat_lr;
}

return regs->regs[idx];
}

#define REG_RESERVED (~((1ULL << PERF_REG_ARM64_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_compat_thread(task_thread_info(task)))
return PERF_SAMPLE_REGS_ABI_32;
else
return PERF_SAMPLE_REGS_ABI_64;
}

0 comments on commit 2ee0d7f

Please sign in to comment.