1// SPDX-License-Identifier: GPL-2.0
2#include <asm/insn.h>
3#include <linux/mm.h>
4
5#include "perf_event.h"
6
7static int decode_branch_type(struct insn *insn)
8{
9 int ext;
10
11 if (insn_get_opcode(insn))
12 return X86_BR_ABORT;
13
14 switch (insn->opcode.bytes[0]) {
15 case 0xf:
16 switch (insn->opcode.bytes[1]) {
17 case 0x05: /* syscall */
18 case 0x34: /* sysenter */
19 return X86_BR_SYSCALL;
20 case 0x07: /* sysret */
21 case 0x35: /* sysexit */
22 return X86_BR_SYSRET;
23 case 0x80 ... 0x8f: /* conditional */
24 return X86_BR_JCC;
25 }
26 return X86_BR_NONE;
27 case 0x70 ... 0x7f: /* conditional */
28 return X86_BR_JCC;
29 case 0xc2: /* near ret */
30 case 0xc3: /* near ret */
31 case 0xca: /* far ret */
32 case 0xcb: /* far ret */
33 return X86_BR_RET;
34 case 0xcf: /* iret */
35 return X86_BR_IRET;
36 case 0xcc ... 0xce: /* int */
37 return X86_BR_INT;
38 case 0xe8: /* call near rel */
39 if (insn_get_immediate(insn) || insn->immediate1.value == 0) {
40 /* zero length call */
41 return X86_BR_ZERO_CALL;
42 }
43 fallthrough;
44 case 0x9a: /* call far absolute */
45 return X86_BR_CALL;
46 case 0xe0 ... 0xe3: /* loop jmp */
47 return X86_BR_JCC;
48 case 0xe9 ... 0xeb: /* jmp */
49 return X86_BR_JMP;
50 case 0xff: /* call near absolute, call far absolute ind */
51 if (insn_get_modrm(insn))
52 return X86_BR_ABORT;
53
54 ext = (insn->modrm.bytes[0] >> 3) & 0x7;
55 switch (ext) {
56 case 2: /* near ind call */
57 case 3: /* far ind call */
58 return X86_BR_IND_CALL;
59 case 4:
60 case 5:
61 return X86_BR_IND_JMP;
62 }
63 return X86_BR_NONE;
64 }
65
66 return X86_BR_NONE;
67}
68
69/*
70 * return the type of control flow change at address "from"
71 * instruction is not necessarily a branch (in case of interrupt).
72 *
73 * The branch type returned also includes the priv level of the
74 * target of the control flow change (X86_BR_USER, X86_BR_KERNEL).
75 *
76 * If a branch type is unknown OR the instruction cannot be
77 * decoded (e.g., text page not present), then X86_BR_NONE is
78 * returned.
79 *
80 * While recording branches, some processors can report the "from"
81 * address to be that of an instruction preceding the actual branch
82 * when instruction fusion occurs. If fusion is expected, attempt to
83 * find the type of the first branch instruction within the next
84 * MAX_INSN_SIZE bytes and if found, provide the offset between the
85 * reported "from" address and the actual branch instruction address.
86 */
87static int get_branch_type(unsigned long from, unsigned long to, int abort,
88 bool fused, int *offset)
89{
90 struct insn insn;
91 void *addr;
92 int bytes_read, bytes_left, insn_offset;
93 int ret = X86_BR_NONE;
94 int to_plm, from_plm;
95 u8 buf[MAX_INSN_SIZE];
96 int is64 = 0;
97
98 /* make sure we initialize offset */
99 if (offset)
100 *offset = 0;
101
102 to_plm = kernel_ip(ip: to) ? X86_BR_KERNEL : X86_BR_USER;
103 from_plm = kernel_ip(ip: from) ? X86_BR_KERNEL : X86_BR_USER;
104
105 /*
106 * maybe zero if lbr did not fill up after a reset by the time
107 * we get a PMU interrupt
108 */
109 if (from == 0 || to == 0)
110 return X86_BR_NONE;
111
112 if (abort)
113 return X86_BR_ABORT | to_plm;
114
115 if (from_plm == X86_BR_USER) {
116 /*
117 * can happen if measuring at the user level only
118 * and we interrupt in a kernel thread, e.g., idle.
119 */
120 if (!current->mm)
121 return X86_BR_NONE;
122
123 /* may fail if text not present */
124 bytes_left = copy_from_user_nmi(to: buf, from: (void __user *)from,
125 MAX_INSN_SIZE);
126 bytes_read = MAX_INSN_SIZE - bytes_left;
127 if (!bytes_read)
128 return X86_BR_NONE;
129
130 addr = buf;
131 } else {
132 /*
133 * The LBR logs any address in the IP, even if the IP just
134 * faulted. This means userspace can control the from address.
135 * Ensure we don't blindly read any address by validating it is
136 * a known text address and not a vsyscall address.
137 */
138 if (kernel_text_address(addr: from) && !in_gate_area_no_mm(addr: from)) {
139 addr = (void *)from;
140 /*
141 * Assume we can get the maximum possible size
142 * when grabbing kernel data. This is not
143 * _strictly_ true since we could possibly be
144 * executing up next to a memory hole, but
145 * it is very unlikely to be a problem.
146 */
147 bytes_read = MAX_INSN_SIZE;
148 } else {
149 return X86_BR_NONE;
150 }
151 }
152
153 /*
154 * decoder needs to know the ABI especially
155 * on 64-bit systems running 32-bit apps
156 */
157#ifdef CONFIG_X86_64
158 is64 = kernel_ip(ip: (unsigned long)addr) || any_64bit_mode(current_pt_regs());
159#endif
160 insn_init(insn: &insn, kaddr: addr, buf_len: bytes_read, x86_64: is64);
161 ret = decode_branch_type(insn: &insn);
162 insn_offset = 0;
163
164 /* Check for the possibility of branch fusion */
165 while (fused && ret == X86_BR_NONE) {
166 /* Check for decoding errors */
167 if (insn_get_length(insn: &insn) || !insn.length)
168 break;
169
170 insn_offset += insn.length;
171 bytes_read -= insn.length;
172 if (bytes_read < 0)
173 break;
174
175 insn_init(insn: &insn, kaddr: addr + insn_offset, buf_len: bytes_read, x86_64: is64);
176 ret = decode_branch_type(insn: &insn);
177 }
178
179 if (offset)
180 *offset = insn_offset;
181
182 /*
183 * interrupts, traps, faults (and thus ring transition) may
184 * occur on any instructions. Thus, to classify them correctly,
185 * we need to first look at the from and to priv levels. If they
186 * are different and to is in the kernel, then it indicates
187 * a ring transition. If the from instruction is not a ring
188 * transition instr (syscall, systenter, int), then it means
189 * it was a irq, trap or fault.
190 *
191 * we have no way of detecting kernel to kernel faults.
192 */
193 if (from_plm == X86_BR_USER && to_plm == X86_BR_KERNEL
194 && ret != X86_BR_SYSCALL && ret != X86_BR_INT)
195 ret = X86_BR_IRQ;
196
197 /*
198 * branch priv level determined by target as
199 * is done by HW when LBR_SELECT is implemented
200 */
201 if (ret != X86_BR_NONE)
202 ret |= to_plm;
203
204 return ret;
205}
206
207int branch_type(unsigned long from, unsigned long to, int abort)
208{
209 return get_branch_type(from, to, abort, fused: false, NULL);
210}
211
212int branch_type_fused(unsigned long from, unsigned long to, int abort,
213 int *offset)
214{
215 return get_branch_type(from, to, abort, fused: true, offset);
216}
217
218#define X86_BR_TYPE_MAP_MAX 16
219
220static int branch_map[X86_BR_TYPE_MAP_MAX] = {
221 PERF_BR_CALL, /* X86_BR_CALL */
222 PERF_BR_RET, /* X86_BR_RET */
223 PERF_BR_SYSCALL, /* X86_BR_SYSCALL */
224 PERF_BR_SYSRET, /* X86_BR_SYSRET */
225 PERF_BR_UNKNOWN, /* X86_BR_INT */
226 PERF_BR_ERET, /* X86_BR_IRET */
227 PERF_BR_COND, /* X86_BR_JCC */
228 PERF_BR_UNCOND, /* X86_BR_JMP */
229 PERF_BR_IRQ, /* X86_BR_IRQ */
230 PERF_BR_IND_CALL, /* X86_BR_IND_CALL */
231 PERF_BR_UNKNOWN, /* X86_BR_ABORT */
232 PERF_BR_UNKNOWN, /* X86_BR_IN_TX */
233 PERF_BR_NO_TX, /* X86_BR_NO_TX */
234 PERF_BR_CALL, /* X86_BR_ZERO_CALL */
235 PERF_BR_UNKNOWN, /* X86_BR_CALL_STACK */
236 PERF_BR_IND, /* X86_BR_IND_JMP */
237};
238
239int common_branch_type(int type)
240{
241 int i;
242
243 type >>= 2; /* skip X86_BR_USER and X86_BR_KERNEL */
244
245 if (type) {
246 i = __ffs(type);
247 if (i < X86_BR_TYPE_MAP_MAX)
248 return branch_map[i];
249 }
250
251 return PERF_BR_UNKNOWN;
252}
253

source code of linux/arch/x86/events/utils.c