xref: /openbmc/linux/arch/x86/kernel/perf_regs.c (revision 68db0cf1)
1c5e63197SJiri Olsa #include <linux/errno.h>
2c5e63197SJiri Olsa #include <linux/kernel.h>
34018994fSJiri Olsa #include <linux/sched.h>
468db0cf1SIngo Molnar #include <linux/sched/task_stack.h>
54018994fSJiri Olsa #include <linux/perf_event.h>
6c5e63197SJiri Olsa #include <linux/bug.h>
7c5e63197SJiri Olsa #include <linux/stddef.h>
8c5e63197SJiri Olsa #include <asm/perf_regs.h>
9c5e63197SJiri Olsa #include <asm/ptrace.h>
10c5e63197SJiri Olsa 
11c5e63197SJiri Olsa #ifdef CONFIG_X86_32
12c5e63197SJiri Olsa #define PERF_REG_X86_MAX PERF_REG_X86_32_MAX
13c5e63197SJiri Olsa #else
14c5e63197SJiri Olsa #define PERF_REG_X86_MAX PERF_REG_X86_64_MAX
15c5e63197SJiri Olsa #endif
16c5e63197SJiri Olsa 
17c5e63197SJiri Olsa #define PT_REGS_OFFSET(id, r) [id] = offsetof(struct pt_regs, r)
18c5e63197SJiri Olsa 
19c5e63197SJiri Olsa static unsigned int pt_regs_offset[PERF_REG_X86_MAX] = {
20c5e63197SJiri Olsa 	PT_REGS_OFFSET(PERF_REG_X86_AX, ax),
21c5e63197SJiri Olsa 	PT_REGS_OFFSET(PERF_REG_X86_BX, bx),
22c5e63197SJiri Olsa 	PT_REGS_OFFSET(PERF_REG_X86_CX, cx),
23c5e63197SJiri Olsa 	PT_REGS_OFFSET(PERF_REG_X86_DX, dx),
24c5e63197SJiri Olsa 	PT_REGS_OFFSET(PERF_REG_X86_SI, si),
25c5e63197SJiri Olsa 	PT_REGS_OFFSET(PERF_REG_X86_DI, di),
26c5e63197SJiri Olsa 	PT_REGS_OFFSET(PERF_REG_X86_BP, bp),
27c5e63197SJiri Olsa 	PT_REGS_OFFSET(PERF_REG_X86_SP, sp),
28c5e63197SJiri Olsa 	PT_REGS_OFFSET(PERF_REG_X86_IP, ip),
29c5e63197SJiri Olsa 	PT_REGS_OFFSET(PERF_REG_X86_FLAGS, flags),
30c5e63197SJiri Olsa 	PT_REGS_OFFSET(PERF_REG_X86_CS, cs),
31c5e63197SJiri Olsa 	PT_REGS_OFFSET(PERF_REG_X86_SS, ss),
32c5e63197SJiri Olsa #ifdef CONFIG_X86_32
33c5e63197SJiri Olsa 	PT_REGS_OFFSET(PERF_REG_X86_DS, ds),
34c5e63197SJiri Olsa 	PT_REGS_OFFSET(PERF_REG_X86_ES, es),
35c5e63197SJiri Olsa 	PT_REGS_OFFSET(PERF_REG_X86_FS, fs),
36c5e63197SJiri Olsa 	PT_REGS_OFFSET(PERF_REG_X86_GS, gs),
37c5e63197SJiri Olsa #else
38c5e63197SJiri Olsa 	/*
39c5e63197SJiri Olsa 	 * The pt_regs struct does not store
40c5e63197SJiri Olsa 	 * ds, es, fs, gs in 64 bit mode.
41c5e63197SJiri Olsa 	 */
42c5e63197SJiri Olsa 	(unsigned int) -1,
43c5e63197SJiri Olsa 	(unsigned int) -1,
44c5e63197SJiri Olsa 	(unsigned int) -1,
45c5e63197SJiri Olsa 	(unsigned int) -1,
46c5e63197SJiri Olsa #endif
47c5e63197SJiri Olsa #ifdef CONFIG_X86_64
48c5e63197SJiri Olsa 	PT_REGS_OFFSET(PERF_REG_X86_R8, r8),
49c5e63197SJiri Olsa 	PT_REGS_OFFSET(PERF_REG_X86_R9, r9),
50c5e63197SJiri Olsa 	PT_REGS_OFFSET(PERF_REG_X86_R10, r10),
51c5e63197SJiri Olsa 	PT_REGS_OFFSET(PERF_REG_X86_R11, r11),
52c5e63197SJiri Olsa 	PT_REGS_OFFSET(PERF_REG_X86_R12, r12),
53c5e63197SJiri Olsa 	PT_REGS_OFFSET(PERF_REG_X86_R13, r13),
54c5e63197SJiri Olsa 	PT_REGS_OFFSET(PERF_REG_X86_R14, r14),
55c5e63197SJiri Olsa 	PT_REGS_OFFSET(PERF_REG_X86_R15, r15),
56c5e63197SJiri Olsa #endif
57c5e63197SJiri Olsa };
58c5e63197SJiri Olsa 
59c5e63197SJiri Olsa u64 perf_reg_value(struct pt_regs *regs, int idx)
60c5e63197SJiri Olsa {
611e6dd8adSDan Carpenter 	if (WARN_ON_ONCE(idx >= ARRAY_SIZE(pt_regs_offset)))
62c5e63197SJiri Olsa 		return 0;
63c5e63197SJiri Olsa 
64c5e63197SJiri Olsa 	return regs_get_register(regs, pt_regs_offset[idx]);
65c5e63197SJiri Olsa }
66c5e63197SJiri Olsa 
67c5e63197SJiri Olsa #define REG_RESERVED (~((1ULL << PERF_REG_X86_MAX) - 1ULL))
68c5e63197SJiri Olsa 
69c5e63197SJiri Olsa #ifdef CONFIG_X86_32
70c5e63197SJiri Olsa int perf_reg_validate(u64 mask)
71c5e63197SJiri Olsa {
72c5e63197SJiri Olsa 	if (!mask || mask & REG_RESERVED)
73c5e63197SJiri Olsa 		return -EINVAL;
74c5e63197SJiri Olsa 
75c5e63197SJiri Olsa 	return 0;
76c5e63197SJiri Olsa }
774018994fSJiri Olsa 
784018994fSJiri Olsa u64 perf_reg_abi(struct task_struct *task)
794018994fSJiri Olsa {
804018994fSJiri Olsa 	return PERF_SAMPLE_REGS_ABI_32;
814018994fSJiri Olsa }
8288a7c26aSAndy Lutomirski 
8388a7c26aSAndy Lutomirski void perf_get_regs_user(struct perf_regs *regs_user,
8488a7c26aSAndy Lutomirski 			struct pt_regs *regs,
8588a7c26aSAndy Lutomirski 			struct pt_regs *regs_user_copy)
8688a7c26aSAndy Lutomirski {
8788a7c26aSAndy Lutomirski 	regs_user->regs = task_pt_regs(current);
8888a7c26aSAndy Lutomirski 	regs_user->abi = perf_reg_abi(current);
8988a7c26aSAndy Lutomirski }
90c5e63197SJiri Olsa #else /* CONFIG_X86_64 */
91c5e63197SJiri Olsa #define REG_NOSUPPORT ((1ULL << PERF_REG_X86_DS) | \
92c5e63197SJiri Olsa 		       (1ULL << PERF_REG_X86_ES) | \
93c5e63197SJiri Olsa 		       (1ULL << PERF_REG_X86_FS) | \
94c5e63197SJiri Olsa 		       (1ULL << PERF_REG_X86_GS))
95c5e63197SJiri Olsa 
96c5e63197SJiri Olsa int perf_reg_validate(u64 mask)
97c5e63197SJiri Olsa {
98c5e63197SJiri Olsa 	if (!mask || mask & REG_RESERVED)
99c5e63197SJiri Olsa 		return -EINVAL;
100c5e63197SJiri Olsa 
101c5e63197SJiri Olsa 	if (mask & REG_NOSUPPORT)
102c5e63197SJiri Olsa 		return -EINVAL;
103c5e63197SJiri Olsa 
104c5e63197SJiri Olsa 	return 0;
105c5e63197SJiri Olsa }
1064018994fSJiri Olsa 
1074018994fSJiri Olsa u64 perf_reg_abi(struct task_struct *task)
1084018994fSJiri Olsa {
1094018994fSJiri Olsa 	if (test_tsk_thread_flag(task, TIF_IA32))
1104018994fSJiri Olsa 		return PERF_SAMPLE_REGS_ABI_32;
1114018994fSJiri Olsa 	else
1124018994fSJiri Olsa 		return PERF_SAMPLE_REGS_ABI_64;
1134018994fSJiri Olsa }
11488a7c26aSAndy Lutomirski 
11588a7c26aSAndy Lutomirski void perf_get_regs_user(struct perf_regs *regs_user,
11688a7c26aSAndy Lutomirski 			struct pt_regs *regs,
11788a7c26aSAndy Lutomirski 			struct pt_regs *regs_user_copy)
11888a7c26aSAndy Lutomirski {
11986c269feSAndy Lutomirski 	struct pt_regs *user_regs = task_pt_regs(current);
12086c269feSAndy Lutomirski 
12186c269feSAndy Lutomirski 	/*
12286c269feSAndy Lutomirski 	 * If we're in an NMI that interrupted task_pt_regs setup, then
12386c269feSAndy Lutomirski 	 * we can't sample user regs at all.  This check isn't really
12486c269feSAndy Lutomirski 	 * sufficient, though, as we could be in an NMI inside an interrupt
12586c269feSAndy Lutomirski 	 * that happened during task_pt_regs setup.
12686c269feSAndy Lutomirski 	 */
12786c269feSAndy Lutomirski 	if (regs->sp > (unsigned long)&user_regs->r11 &&
12886c269feSAndy Lutomirski 	    regs->sp <= (unsigned long)(user_regs + 1)) {
12986c269feSAndy Lutomirski 		regs_user->abi = PERF_SAMPLE_REGS_ABI_NONE;
13086c269feSAndy Lutomirski 		regs_user->regs = NULL;
13186c269feSAndy Lutomirski 		return;
13286c269feSAndy Lutomirski 	}
13386c269feSAndy Lutomirski 
13486c269feSAndy Lutomirski 	/*
135aa21df04SDenys Vlasenko 	 * These registers are always saved on 64-bit syscall entry.
136aa21df04SDenys Vlasenko 	 * On 32-bit entry points, they are saved too except r8..r11.
13786c269feSAndy Lutomirski 	 */
13886c269feSAndy Lutomirski 	regs_user_copy->ip = user_regs->ip;
1393b75232dSDenys Vlasenko 	regs_user_copy->ax = user_regs->ax;
14086c269feSAndy Lutomirski 	regs_user_copy->cx = user_regs->cx;
14186c269feSAndy Lutomirski 	regs_user_copy->dx = user_regs->dx;
14286c269feSAndy Lutomirski 	regs_user_copy->si = user_regs->si;
14386c269feSAndy Lutomirski 	regs_user_copy->di = user_regs->di;
14486c269feSAndy Lutomirski 	regs_user_copy->r8 = user_regs->r8;
14586c269feSAndy Lutomirski 	regs_user_copy->r9 = user_regs->r9;
14686c269feSAndy Lutomirski 	regs_user_copy->r10 = user_regs->r10;
14786c269feSAndy Lutomirski 	regs_user_copy->r11 = user_regs->r11;
14886c269feSAndy Lutomirski 	regs_user_copy->orig_ax = user_regs->orig_ax;
14986c269feSAndy Lutomirski 	regs_user_copy->flags = user_regs->flags;
150aa21df04SDenys Vlasenko 	regs_user_copy->sp = user_regs->sp;
151aa21df04SDenys Vlasenko 	regs_user_copy->cs = user_regs->cs;
152aa21df04SDenys Vlasenko 	regs_user_copy->ss = user_regs->ss;
15386c269feSAndy Lutomirski 
15486c269feSAndy Lutomirski 	/*
155aa21df04SDenys Vlasenko 	 * Most system calls don't save these registers, don't report them.
15686c269feSAndy Lutomirski 	 */
15786c269feSAndy Lutomirski 	regs_user_copy->bx = -1;
15886c269feSAndy Lutomirski 	regs_user_copy->bp = -1;
15986c269feSAndy Lutomirski 	regs_user_copy->r12 = -1;
16086c269feSAndy Lutomirski 	regs_user_copy->r13 = -1;
16186c269feSAndy Lutomirski 	regs_user_copy->r14 = -1;
16286c269feSAndy Lutomirski 	regs_user_copy->r15 = -1;
16386c269feSAndy Lutomirski 
16486c269feSAndy Lutomirski 	/*
16586c269feSAndy Lutomirski 	 * For this to be at all useful, we need a reasonable guess for
166aa21df04SDenys Vlasenko 	 * the ABI.  Be careful: we're in NMI context, and we're
16786c269feSAndy Lutomirski 	 * considering current to be the current task, so we should
16886c269feSAndy Lutomirski 	 * be careful not to look at any other percpu variables that might
16986c269feSAndy Lutomirski 	 * change during context switches.
17086c269feSAndy Lutomirski 	 */
17186c269feSAndy Lutomirski 	regs_user->abi = user_64bit_mode(user_regs) ?
17286c269feSAndy Lutomirski 		PERF_SAMPLE_REGS_ABI_64 : PERF_SAMPLE_REGS_ABI_32;
17386c269feSAndy Lutomirski 
17486c269feSAndy Lutomirski 	regs_user->regs = regs_user_copy;
17588a7c26aSAndy Lutomirski }
176c5e63197SJiri Olsa #endif /* CONFIG_X86_32 */
177