Commit | Line | Data |
---|---|---|
ed4a4ef8 A |
1 | /* |
2 | * Copyright 2016 Anju T, IBM Corporation. | |
3 | * | |
4 | * This program is free software; you can redistribute it and/or | |
5 | * modify it under the terms of the GNU General Public License | |
6 | * as published by the Free Software Foundation; either version | |
7 | * 2 of the License, or (at your option) any later version. | |
8 | */ | |
9 | ||
10 | #include <linux/errno.h> | |
11 | #include <linux/kernel.h> | |
12 | #include <linux/sched.h> | |
13 | #include <linux/perf_event.h> | |
14 | #include <linux/bug.h> | |
15 | #include <linux/stddef.h> | |
16 | #include <asm/ptrace.h> | |
17 | #include <asm/perf_regs.h> | |
18 | ||
19 | #define PT_REGS_OFFSET(id, r) [id] = offsetof(struct pt_regs, r) | |
20 | ||
21 | #define REG_RESERVED (~((1ULL << PERF_REG_POWERPC_MAX) - 1)) | |
22 | ||
23 | static unsigned int pt_regs_offset[PERF_REG_POWERPC_MAX] = { | |
24 | PT_REGS_OFFSET(PERF_REG_POWERPC_R0, gpr[0]), | |
25 | PT_REGS_OFFSET(PERF_REG_POWERPC_R1, gpr[1]), | |
26 | PT_REGS_OFFSET(PERF_REG_POWERPC_R2, gpr[2]), | |
27 | PT_REGS_OFFSET(PERF_REG_POWERPC_R3, gpr[3]), | |
28 | PT_REGS_OFFSET(PERF_REG_POWERPC_R4, gpr[4]), | |
29 | PT_REGS_OFFSET(PERF_REG_POWERPC_R5, gpr[5]), | |
30 | PT_REGS_OFFSET(PERF_REG_POWERPC_R6, gpr[6]), | |
31 | PT_REGS_OFFSET(PERF_REG_POWERPC_R7, gpr[7]), | |
32 | PT_REGS_OFFSET(PERF_REG_POWERPC_R8, gpr[8]), | |
33 | PT_REGS_OFFSET(PERF_REG_POWERPC_R9, gpr[9]), | |
34 | PT_REGS_OFFSET(PERF_REG_POWERPC_R10, gpr[10]), | |
35 | PT_REGS_OFFSET(PERF_REG_POWERPC_R11, gpr[11]), | |
36 | PT_REGS_OFFSET(PERF_REG_POWERPC_R12, gpr[12]), | |
37 | PT_REGS_OFFSET(PERF_REG_POWERPC_R13, gpr[13]), | |
38 | PT_REGS_OFFSET(PERF_REG_POWERPC_R14, gpr[14]), | |
39 | PT_REGS_OFFSET(PERF_REG_POWERPC_R15, gpr[15]), | |
40 | PT_REGS_OFFSET(PERF_REG_POWERPC_R16, gpr[16]), | |
41 | PT_REGS_OFFSET(PERF_REG_POWERPC_R17, gpr[17]), | |
42 | PT_REGS_OFFSET(PERF_REG_POWERPC_R18, gpr[18]), | |
43 | PT_REGS_OFFSET(PERF_REG_POWERPC_R19, gpr[19]), | |
44 | PT_REGS_OFFSET(PERF_REG_POWERPC_R20, gpr[20]), | |
45 | PT_REGS_OFFSET(PERF_REG_POWERPC_R21, gpr[21]), | |
46 | PT_REGS_OFFSET(PERF_REG_POWERPC_R22, gpr[22]), | |
47 | PT_REGS_OFFSET(PERF_REG_POWERPC_R23, gpr[23]), | |
48 | PT_REGS_OFFSET(PERF_REG_POWERPC_R24, gpr[24]), | |
49 | PT_REGS_OFFSET(PERF_REG_POWERPC_R25, gpr[25]), | |
50 | PT_REGS_OFFSET(PERF_REG_POWERPC_R26, gpr[26]), | |
51 | PT_REGS_OFFSET(PERF_REG_POWERPC_R27, gpr[27]), | |
52 | PT_REGS_OFFSET(PERF_REG_POWERPC_R28, gpr[28]), | |
53 | PT_REGS_OFFSET(PERF_REG_POWERPC_R29, gpr[29]), | |
54 | PT_REGS_OFFSET(PERF_REG_POWERPC_R30, gpr[30]), | |
55 | PT_REGS_OFFSET(PERF_REG_POWERPC_R31, gpr[31]), | |
56 | PT_REGS_OFFSET(PERF_REG_POWERPC_NIP, nip), | |
57 | PT_REGS_OFFSET(PERF_REG_POWERPC_MSR, msr), | |
58 | PT_REGS_OFFSET(PERF_REG_POWERPC_ORIG_R3, orig_gpr3), | |
59 | PT_REGS_OFFSET(PERF_REG_POWERPC_CTR, ctr), | |
60 | PT_REGS_OFFSET(PERF_REG_POWERPC_LINK, link), | |
61 | PT_REGS_OFFSET(PERF_REG_POWERPC_XER, xer), | |
62 | PT_REGS_OFFSET(PERF_REG_POWERPC_CCR, ccr), | |
63 | #ifdef CONFIG_PPC64 | |
64 | PT_REGS_OFFSET(PERF_REG_POWERPC_SOFTE, softe), | |
65 | #else | |
66 | PT_REGS_OFFSET(PERF_REG_POWERPC_SOFTE, mq), | |
67 | #endif | |
68 | PT_REGS_OFFSET(PERF_REG_POWERPC_TRAP, trap), | |
69 | PT_REGS_OFFSET(PERF_REG_POWERPC_DAR, dar), | |
70 | PT_REGS_OFFSET(PERF_REG_POWERPC_DSISR, dsisr), | |
71 | }; | |
72 | ||
73 | u64 perf_reg_value(struct pt_regs *regs, int idx) | |
74 | { | |
75 | if (WARN_ON_ONCE(idx >= PERF_REG_POWERPC_MAX)) | |
76 | return 0; | |
77 | ||
78 | return regs_get_register(regs, pt_regs_offset[idx]); | |
79 | } | |
80 | ||
81 | int perf_reg_validate(u64 mask) | |
82 | { | |
83 | if (!mask || mask & REG_RESERVED) | |
84 | return -EINVAL; | |
85 | return 0; | |
86 | } | |
87 | ||
88 | u64 perf_reg_abi(struct task_struct *task) | |
89 | { | |
90 | #ifdef CONFIG_PPC64 | |
91 | if (!test_tsk_thread_flag(task, TIF_32BIT)) | |
92 | return PERF_SAMPLE_REGS_ABI_64; | |
93 | else | |
94 | #endif | |
95 | return PERF_SAMPLE_REGS_ABI_32; | |
96 | } | |
97 | ||
98 | void perf_get_regs_user(struct perf_regs *regs_user, | |
99 | struct pt_regs *regs, | |
100 | struct pt_regs *regs_user_copy) | |
101 | { | |
102 | regs_user->regs = task_pt_regs(current); | |
103 | regs_user->abi = perf_reg_abi(current); | |
104 | } |