xref: /openbmc/linux/arch/x86/kernel/perf_regs.c (revision 375d4bfd)
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,
10488a7c26aSAndy Lutomirski 			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 }
10988a7c26aSAndy Lutomirski #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 {
117c5e63197SJiri Olsa 	if (!mask || (mask & (REG_NOSUPPORT | PERF_REG_X86_RESERVED)))
11890d42491SKan Liang 		return -EINVAL;
119c5e63197SJiri Olsa 
120c5e63197SJiri Olsa 	return 0;
121c5e63197SJiri Olsa }
122c5e63197SJiri Olsa 
perf_reg_abi(struct task_struct * task)1234018994fSJiri Olsa u64 perf_reg_abi(struct task_struct *task)
1244018994fSJiri Olsa {
1254018994fSJiri Olsa 	if (!user_64bit_mode(task_pt_regs(task)))
126*375d4bfdSGabriel Krisman Bertazi 		return PERF_SAMPLE_REGS_ABI_32;
1274018994fSJiri Olsa 	else
1284018994fSJiri Olsa 		return PERF_SAMPLE_REGS_ABI_64;
1294018994fSJiri Olsa }
1304018994fSJiri Olsa 
13188a7c26aSAndy Lutomirski static DEFINE_PER_CPU(struct pt_regs, nmi_user_regs);
13288a7c26aSAndy Lutomirski 
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,
13488a7c26aSAndy Lutomirski 			struct pt_regs *regs)
13588a7c26aSAndy Lutomirski {
13686c269feSAndy Lutomirski 	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 
13986c269feSAndy Lutomirski 	if (!in_nmi()) {
14086c269feSAndy Lutomirski 		regs_user->regs = user_regs;
14186c269feSAndy Lutomirski 		regs_user->abi = perf_reg_abi(current);
14286c269feSAndy Lutomirski 		return;
14386c269feSAndy Lutomirski 	}
14486c269feSAndy Lutomirski 
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 &&
152aa21df04SDenys Vlasenko 	    regs->sp <= (unsigned long)(user_regs + 1)) {
153aa21df04SDenys Vlasenko 		regs_user->abi = PERF_SAMPLE_REGS_ABI_NONE;
15486c269feSAndy Lutomirski 		regs_user->regs = NULL;
15586c269feSAndy Lutomirski 		return;
1563b75232dSDenys Vlasenko 	}
15786c269feSAndy Lutomirski 
15886c269feSAndy Lutomirski 	/*
15986c269feSAndy Lutomirski 	 * These registers are always saved on 64-bit syscall entry.
16086c269feSAndy Lutomirski 	 * On 32-bit entry points, they are saved too except r8..r11.
16186c269feSAndy Lutomirski 	 */
16286c269feSAndy Lutomirski 	regs_user_copy->ip = user_regs->ip;
16386c269feSAndy Lutomirski 	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;
167aa21df04SDenys Vlasenko 	regs_user_copy->di = user_regs->di;
168aa21df04SDenys Vlasenko 	regs_user_copy->r8 = user_regs->r8;
169aa21df04SDenys Vlasenko 	regs_user_copy->r9 = user_regs->r9;
17086c269feSAndy Lutomirski 	regs_user_copy->r10 = user_regs->r10;
17110b11050SAlexey Budankov 	regs_user_copy->r11 = user_regs->r11;
17210b11050SAlexey Budankov 	regs_user_copy->orig_ax = user_regs->orig_ax;
17310b11050SAlexey Budankov 	regs_user_copy->flags = user_regs->flags;
17410b11050SAlexey Budankov 	regs_user_copy->sp = user_regs->sp;
17586c269feSAndy Lutomirski 	regs_user_copy->cs = user_regs->cs;
17610b11050SAlexey Budankov 	regs_user_copy->ss = user_regs->ss;
17710b11050SAlexey Budankov 	/*
17886c269feSAndy Lutomirski 	 * Store user space frame-pointer value on sample
17986c269feSAndy Lutomirski 	 * to facilitate stack unwinding for cases when
18086c269feSAndy Lutomirski 	 * user space executable code has such support
18186c269feSAndy Lutomirski 	 * enabled at compile time:
18286c269feSAndy Lutomirski 	 */
18386c269feSAndy Lutomirski 	regs_user_copy->bp = user_regs->bp;
18486c269feSAndy Lutomirski 
185aa21df04SDenys Vlasenko 	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
19286c269feSAndy Lutomirski 	 * the ABI.  Be careful: we're in NMI context, and we're
19386c269feSAndy Lutomirski 	 * considering current to be the current task, so we should
19488a7c26aSAndy Lutomirski 	 * be careful not to look at any other percpu variables that might
195c5e63197SJiri Olsa 	 * change during context switches.
196 	 */
197 	regs_user->abi = user_64bit_mode(user_regs) ?
198 		PERF_SAMPLE_REGS_ABI_64 : PERF_SAMPLE_REGS_ABI_32;
199 
200 	regs_user->regs = regs_user_copy;
201 }
202 #endif /* CONFIG_X86_32 */
203