File Index
Files and directories
Sign in
FILE

utils.c

File preview with syntax highlighting.

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