1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
2c5e63197SJiri Olsa #include <linux/errno.h>
3c5e63197SJiri Olsa #include <linux/kernel.h>
44018994fSJiri Olsa #include <linux/sched.h>
568db0cf1SIngo Molnar #include <linux/sched/task_stack.h>
64018994fSJiri Olsa #include <linux/perf_event.h>
7c5e63197SJiri Olsa #include <linux/bug.h>
8c5e63197SJiri Olsa #include <linux/stddef.h>
9c5e63197SJiri Olsa #include <asm/perf_regs.h>
10c5e63197SJiri Olsa #include <asm/ptrace.h>
11c5e63197SJiri Olsa
12c5e63197SJiri Olsa #ifdef CONFIG_X86_32
13c5e63197SJiri Olsa #define PERF_REG_X86_MAX PERF_REG_X86_32_MAX
14c5e63197SJiri Olsa #else
15c5e63197SJiri Olsa #define PERF_REG_X86_MAX PERF_REG_X86_64_MAX
16c5e63197SJiri Olsa #endif
17c5e63197SJiri Olsa
18c5e63197SJiri Olsa #define PT_REGS_OFFSET(id, r) [id] = offsetof(struct pt_regs, r)
19c5e63197SJiri Olsa
20c5e63197SJiri Olsa static unsigned int pt_regs_offset[PERF_REG_X86_MAX] = {
21c5e63197SJiri Olsa PT_REGS_OFFSET(PERF_REG_X86_AX, ax),
22c5e63197SJiri Olsa PT_REGS_OFFSET(PERF_REG_X86_BX, bx),
23c5e63197SJiri Olsa PT_REGS_OFFSET(PERF_REG_X86_CX, cx),
24c5e63197SJiri Olsa PT_REGS_OFFSET(PERF_REG_X86_DX, dx),
25c5e63197SJiri Olsa PT_REGS_OFFSET(PERF_REG_X86_SI, si),
26c5e63197SJiri Olsa PT_REGS_OFFSET(PERF_REG_X86_DI, di),
27c5e63197SJiri Olsa PT_REGS_OFFSET(PERF_REG_X86_BP, bp),
28c5e63197SJiri Olsa PT_REGS_OFFSET(PERF_REG_X86_SP, sp),
29c5e63197SJiri Olsa PT_REGS_OFFSET(PERF_REG_X86_IP, ip),
30c5e63197SJiri Olsa PT_REGS_OFFSET(PERF_REG_X86_FLAGS, flags),
31c5e63197SJiri Olsa PT_REGS_OFFSET(PERF_REG_X86_CS, cs),
32c5e63197SJiri Olsa PT_REGS_OFFSET(PERF_REG_X86_SS, ss),
33c5e63197SJiri Olsa #ifdef CONFIG_X86_32
34c5e63197SJiri Olsa PT_REGS_OFFSET(PERF_REG_X86_DS, ds),
35c5e63197SJiri Olsa PT_REGS_OFFSET(PERF_REG_X86_ES, es),
36c5e63197SJiri Olsa PT_REGS_OFFSET(PERF_REG_X86_FS, fs),
37c5e63197SJiri Olsa PT_REGS_OFFSET(PERF_REG_X86_GS, gs),
38c5e63197SJiri Olsa #else
39c5e63197SJiri Olsa /*
40c5e63197SJiri Olsa * The pt_regs struct does not store
41c5e63197SJiri Olsa * ds, es, fs, gs in 64 bit mode.
42c5e63197SJiri Olsa */
43c5e63197SJiri Olsa (unsigned int) -1,
44c5e63197SJiri Olsa (unsigned int) -1,
45c5e63197SJiri Olsa (unsigned int) -1,
46c5e63197SJiri Olsa (unsigned int) -1,
47c5e63197SJiri Olsa #endif
48c5e63197SJiri Olsa #ifdef CONFIG_X86_64
49c5e63197SJiri Olsa PT_REGS_OFFSET(PERF_REG_X86_R8, r8),
50c5e63197SJiri Olsa PT_REGS_OFFSET(PERF_REG_X86_R9, r9),
51c5e63197SJiri Olsa PT_REGS_OFFSET(PERF_REG_X86_R10, r10),
52c5e63197SJiri Olsa PT_REGS_OFFSET(PERF_REG_X86_R11, r11),
53c5e63197SJiri Olsa PT_REGS_OFFSET(PERF_REG_X86_R12, r12),
54c5e63197SJiri Olsa PT_REGS_OFFSET(PERF_REG_X86_R13, r13),
55c5e63197SJiri Olsa PT_REGS_OFFSET(PERF_REG_X86_R14, r14),
56c5e63197SJiri Olsa PT_REGS_OFFSET(PERF_REG_X86_R15, r15),
57c5e63197SJiri Olsa #endif
58c5e63197SJiri Olsa };
59c5e63197SJiri Olsa
perf_reg_value(struct pt_regs * regs,int idx)60c5e63197SJiri Olsa u64 perf_reg_value(struct pt_regs *regs, int idx)
61c5e63197SJiri Olsa {
62878068eaSKan Liang struct x86_perf_regs *perf_regs;
63878068eaSKan Liang
64878068eaSKan Liang if (idx >= PERF_REG_X86_XMM0 && idx < PERF_REG_X86_XMM_MAX) {
65878068eaSKan Liang perf_regs = container_of(regs, struct x86_perf_regs, regs);
66878068eaSKan Liang if (!perf_regs->xmm_regs)
67878068eaSKan Liang return 0;
68878068eaSKan Liang return perf_regs->xmm_regs[idx - PERF_REG_X86_XMM0];
69878068eaSKan Liang }
70878068eaSKan Liang
711e6dd8adSDan Carpenter if (WARN_ON_ONCE(idx >= ARRAY_SIZE(pt_regs_offset)))
72c5e63197SJiri Olsa return 0;
73c5e63197SJiri Olsa
74c5e63197SJiri Olsa return regs_get_register(regs, pt_regs_offset[idx]);
75c5e63197SJiri Olsa }
76c5e63197SJiri Olsa
7790d42491SKan Liang #define PERF_REG_X86_RESERVED (((1ULL << PERF_REG_X86_XMM0) - 1) & \
7890d42491SKan Liang ~((1ULL << PERF_REG_X86_MAX) - 1))
7990d42491SKan Liang
80c5e63197SJiri Olsa #ifdef CONFIG_X86_32
81878068eaSKan Liang #define REG_NOSUPPORT ((1ULL << PERF_REG_X86_R8) | \
82878068eaSKan Liang (1ULL << PERF_REG_X86_R9) | \
83878068eaSKan Liang (1ULL << PERF_REG_X86_R10) | \
84878068eaSKan Liang (1ULL << PERF_REG_X86_R11) | \
85878068eaSKan Liang (1ULL << PERF_REG_X86_R12) | \
86878068eaSKan Liang (1ULL << PERF_REG_X86_R13) | \
87878068eaSKan Liang (1ULL << PERF_REG_X86_R14) | \
88878068eaSKan Liang (1ULL << PERF_REG_X86_R15))
89878068eaSKan Liang
perf_reg_validate(u64 mask)90c5e63197SJiri Olsa int perf_reg_validate(u64 mask)
91c5e63197SJiri Olsa {
9290d42491SKan Liang if (!mask || (mask & (REG_NOSUPPORT | PERF_REG_X86_RESERVED)))
93c5e63197SJiri Olsa return -EINVAL;
94c5e63197SJiri Olsa
95c5e63197SJiri Olsa return 0;
96c5e63197SJiri Olsa }
974018994fSJiri Olsa
perf_reg_abi(struct task_struct * task)984018994fSJiri Olsa u64 perf_reg_abi(struct task_struct *task)
994018994fSJiri Olsa {
1004018994fSJiri Olsa return PERF_SAMPLE_REGS_ABI_32;
1014018994fSJiri Olsa }
10288a7c26aSAndy Lutomirski
perf_get_regs_user(struct perf_regs * regs_user,struct pt_regs * regs)10388a7c26aSAndy Lutomirski void perf_get_regs_user(struct perf_regs *regs_user,
104*76a4efa8SPeter Zijlstra struct pt_regs *regs)
10588a7c26aSAndy Lutomirski {
10688a7c26aSAndy Lutomirski regs_user->regs = task_pt_regs(current);
10788a7c26aSAndy Lutomirski regs_user->abi = perf_reg_abi(current);
10888a7c26aSAndy Lutomirski }
109c5e63197SJiri Olsa #else /* CONFIG_X86_64 */
110c5e63197SJiri Olsa #define REG_NOSUPPORT ((1ULL << PERF_REG_X86_DS) | \
111c5e63197SJiri Olsa (1ULL << PERF_REG_X86_ES) | \
112c5e63197SJiri Olsa (1ULL << PERF_REG_X86_FS) | \
113c5e63197SJiri Olsa (1ULL << PERF_REG_X86_GS))
114c5e63197SJiri Olsa
perf_reg_validate(u64 mask)115c5e63197SJiri Olsa int perf_reg_validate(u64 mask)
116c5e63197SJiri Olsa {
11790d42491SKan Liang if (!mask || (mask & (REG_NOSUPPORT | PERF_REG_X86_RESERVED)))
118c5e63197SJiri Olsa return -EINVAL;
119c5e63197SJiri Olsa
120c5e63197SJiri Olsa return 0;
121c5e63197SJiri Olsa }
1224018994fSJiri Olsa
perf_reg_abi(struct task_struct * task)1234018994fSJiri Olsa u64 perf_reg_abi(struct task_struct *task)
1244018994fSJiri Olsa {
125375d4bfdSGabriel Krisman Bertazi if (!user_64bit_mode(task_pt_regs(task)))
1264018994fSJiri Olsa return PERF_SAMPLE_REGS_ABI_32;
1274018994fSJiri Olsa else
1284018994fSJiri Olsa return PERF_SAMPLE_REGS_ABI_64;
1294018994fSJiri Olsa }
13088a7c26aSAndy Lutomirski
131*76a4efa8SPeter Zijlstra static DEFINE_PER_CPU(struct pt_regs, nmi_user_regs);
132*76a4efa8SPeter Zijlstra
perf_get_regs_user(struct perf_regs * regs_user,struct pt_regs * regs)13388a7c26aSAndy Lutomirski void perf_get_regs_user(struct perf_regs *regs_user,
134*76a4efa8SPeter Zijlstra struct pt_regs *regs)
13588a7c26aSAndy Lutomirski {
136*76a4efa8SPeter Zijlstra struct pt_regs *regs_user_copy = this_cpu_ptr(&nmi_user_regs);
13786c269feSAndy Lutomirski struct pt_regs *user_regs = task_pt_regs(current);
13886c269feSAndy Lutomirski
139*76a4efa8SPeter Zijlstra if (!in_nmi()) {
140*76a4efa8SPeter Zijlstra regs_user->regs = user_regs;
141*76a4efa8SPeter Zijlstra regs_user->abi = perf_reg_abi(current);
142*76a4efa8SPeter Zijlstra return;
143*76a4efa8SPeter Zijlstra }
144*76a4efa8SPeter Zijlstra
14586c269feSAndy Lutomirski /*
14686c269feSAndy Lutomirski * If we're in an NMI that interrupted task_pt_regs setup, then
14786c269feSAndy Lutomirski * we can't sample user regs at all. This check isn't really
14886c269feSAndy Lutomirski * sufficient, though, as we could be in an NMI inside an interrupt
14986c269feSAndy Lutomirski * that happened during task_pt_regs setup.
15086c269feSAndy Lutomirski */
15186c269feSAndy Lutomirski if (regs->sp > (unsigned long)&user_regs->r11 &&
15286c269feSAndy Lutomirski regs->sp <= (unsigned long)(user_regs + 1)) {
15386c269feSAndy Lutomirski regs_user->abi = PERF_SAMPLE_REGS_ABI_NONE;
15486c269feSAndy Lutomirski regs_user->regs = NULL;
15586c269feSAndy Lutomirski return;
15686c269feSAndy Lutomirski }
15786c269feSAndy Lutomirski
15886c269feSAndy Lutomirski /*
159aa21df04SDenys Vlasenko * These registers are always saved on 64-bit syscall entry.
160aa21df04SDenys Vlasenko * On 32-bit entry points, they are saved too except r8..r11.
16186c269feSAndy Lutomirski */
16286c269feSAndy Lutomirski regs_user_copy->ip = user_regs->ip;
1633b75232dSDenys Vlasenko regs_user_copy->ax = user_regs->ax;
16486c269feSAndy Lutomirski regs_user_copy->cx = user_regs->cx;
16586c269feSAndy Lutomirski regs_user_copy->dx = user_regs->dx;
16686c269feSAndy Lutomirski regs_user_copy->si = user_regs->si;
16786c269feSAndy Lutomirski regs_user_copy->di = user_regs->di;
16886c269feSAndy Lutomirski regs_user_copy->r8 = user_regs->r8;
16986c269feSAndy Lutomirski regs_user_copy->r9 = user_regs->r9;
17086c269feSAndy Lutomirski regs_user_copy->r10 = user_regs->r10;
17186c269feSAndy Lutomirski regs_user_copy->r11 = user_regs->r11;
17286c269feSAndy Lutomirski regs_user_copy->orig_ax = user_regs->orig_ax;
17386c269feSAndy Lutomirski regs_user_copy->flags = user_regs->flags;
174aa21df04SDenys Vlasenko regs_user_copy->sp = user_regs->sp;
175aa21df04SDenys Vlasenko regs_user_copy->cs = user_regs->cs;
176aa21df04SDenys Vlasenko regs_user_copy->ss = user_regs->ss;
17786c269feSAndy Lutomirski /*
17810b11050SAlexey Budankov * Store user space frame-pointer value on sample
17910b11050SAlexey Budankov * to facilitate stack unwinding for cases when
18010b11050SAlexey Budankov * user space executable code has such support
18110b11050SAlexey Budankov * enabled at compile time:
18286c269feSAndy Lutomirski */
18310b11050SAlexey Budankov regs_user_copy->bp = user_regs->bp;
18410b11050SAlexey Budankov
18586c269feSAndy Lutomirski regs_user_copy->bx = -1;
18686c269feSAndy Lutomirski regs_user_copy->r12 = -1;
18786c269feSAndy Lutomirski regs_user_copy->r13 = -1;
18886c269feSAndy Lutomirski regs_user_copy->r14 = -1;
18986c269feSAndy Lutomirski regs_user_copy->r15 = -1;
19086c269feSAndy Lutomirski /*
19186c269feSAndy Lutomirski * For this to be at all useful, we need a reasonable guess for
192aa21df04SDenys Vlasenko * the ABI. Be careful: we're in NMI context, and we're
19386c269feSAndy Lutomirski * considering current to be the current task, so we should
19486c269feSAndy Lutomirski * be careful not to look at any other percpu variables that might
19586c269feSAndy Lutomirski * change during context switches.
19686c269feSAndy Lutomirski */
19786c269feSAndy Lutomirski regs_user->abi = user_64bit_mode(user_regs) ?
19886c269feSAndy Lutomirski PERF_SAMPLE_REGS_ABI_64 : PERF_SAMPLE_REGS_ABI_32;
19986c269feSAndy Lutomirski
20086c269feSAndy Lutomirski regs_user->regs = regs_user_copy;
20188a7c26aSAndy Lutomirski }
202c5e63197SJiri Olsa #endif /* CONFIG_X86_32 */
203