1 // SPDX-License-Identifier: GPL-2.0 2 3 #include <linux/bits.h> 4 #include <linux/perf_event.h> 5 #include <linux/sched/task_stack.h> 6 #include <asm/perf_regs.h> 7 8 #define REG(idx, field) \ 9 [PERF_REG_ALPHA_##idx] = offsetof(struct pt_regs, field) 10 11 #define REG_RESERVED (~GENMASK_ULL(PERF_REG_ALPHA_MAX - 1, 0) | \ 12 GENMASK_ULL(PERF_REG_ALPHA_R15, PERF_REG_ALPHA_R9)) 13 14 static const unsigned int pt_regs_offset[PERF_REG_ALPHA_MAX] = { 15 REG(R0, r0), REG(R1, r1), REG(R2, r2), REG(R3, r3), 16 REG(R4, r4), REG(R5, r5), REG(R6, r6), REG(R7, r7), 17 REG(R8, r8), REG(R16, r16), REG(R17, r17), REG(R18, r18), 18 REG(R19, r19), REG(R20, r20), REG(R21, r21), REG(R22, r22), 19 REG(R23, r23), REG(R24, r24), REG(R25, r25), REG(R26, r26), 20 REG(R27, r27), REG(R28, r28), REG(GP, gp), REG(PC, pc), 21 }; 22 23 u64 perf_reg_value(struct pt_regs *regs, int idx) 24 { 25 if (idx == PERF_REG_ALPHA_SP) { 26 if (user_mode(regs)) 27 return user_stack_pointer(regs); 28 /* 29 * Software events built by perf_fetch_caller_regs() use a 30 * per-CPU pt_regs rather than a trap frame, and pt_regs has 31 * nowhere to record sp, so report none. 32 */ 33 if (!object_is_on_stack(regs)) 34 return 0; 35 /* Same kernel sp approximation as stacktrace.c. */ 36 return (unsigned long)(regs + 1); 37 } 38 39 if (WARN_ON_ONCE((u32)idx >= PERF_REG_ALPHA_MAX || 40 BIT_ULL(idx) & REG_RESERVED)) 41 return 0; 42 43 return *(unsigned long *)((void *)regs + pt_regs_offset[idx]); 44 } 45 46 int perf_reg_validate(u64 mask) 47 { 48 if (!mask || mask & REG_RESERVED) 49 return -EINVAL; 50 51 return 0; 52 } 53 54 u64 perf_reg_abi(struct task_struct *task) 55 { 56 return PERF_SAMPLE_REGS_ABI_64; 57 } 58 59 void perf_get_regs_user(struct perf_regs *regs_user, 60 struct pt_regs *regs) 61 { 62 regs_user->regs = task_pt_regs(current); 63 regs_user->abi = perf_reg_abi(current); 64 } 65