162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0
262306a36Sopenharmony_ci#include <asm/insn.h>
362306a36Sopenharmony_ci#include <linux/mm.h>
462306a36Sopenharmony_ci
562306a36Sopenharmony_ci#include "perf_event.h"
662306a36Sopenharmony_ci
762306a36Sopenharmony_cistatic int decode_branch_type(struct insn *insn)
862306a36Sopenharmony_ci{
962306a36Sopenharmony_ci	int ext;
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci	if (insn_get_opcode(insn))
1262306a36Sopenharmony_ci		return X86_BR_ABORT;
1362306a36Sopenharmony_ci
1462306a36Sopenharmony_ci	switch (insn->opcode.bytes[0]) {
1562306a36Sopenharmony_ci	case 0xf:
1662306a36Sopenharmony_ci		switch (insn->opcode.bytes[1]) {
1762306a36Sopenharmony_ci		case 0x05: /* syscall */
1862306a36Sopenharmony_ci		case 0x34: /* sysenter */
1962306a36Sopenharmony_ci			return X86_BR_SYSCALL;
2062306a36Sopenharmony_ci		case 0x07: /* sysret */
2162306a36Sopenharmony_ci		case 0x35: /* sysexit */
2262306a36Sopenharmony_ci			return X86_BR_SYSRET;
2362306a36Sopenharmony_ci		case 0x80 ... 0x8f: /* conditional */
2462306a36Sopenharmony_ci			return X86_BR_JCC;
2562306a36Sopenharmony_ci		}
2662306a36Sopenharmony_ci		return X86_BR_NONE;
2762306a36Sopenharmony_ci	case 0x70 ... 0x7f: /* conditional */
2862306a36Sopenharmony_ci		return X86_BR_JCC;
2962306a36Sopenharmony_ci	case 0xc2: /* near ret */
3062306a36Sopenharmony_ci	case 0xc3: /* near ret */
3162306a36Sopenharmony_ci	case 0xca: /* far ret */
3262306a36Sopenharmony_ci	case 0xcb: /* far ret */
3362306a36Sopenharmony_ci		return X86_BR_RET;
3462306a36Sopenharmony_ci	case 0xcf: /* iret */
3562306a36Sopenharmony_ci		return X86_BR_IRET;
3662306a36Sopenharmony_ci	case 0xcc ... 0xce: /* int */
3762306a36Sopenharmony_ci		return X86_BR_INT;
3862306a36Sopenharmony_ci	case 0xe8: /* call near rel */
3962306a36Sopenharmony_ci		if (insn_get_immediate(insn) || insn->immediate1.value == 0) {
4062306a36Sopenharmony_ci			/* zero length call */
4162306a36Sopenharmony_ci			return X86_BR_ZERO_CALL;
4262306a36Sopenharmony_ci		}
4362306a36Sopenharmony_ci		fallthrough;
4462306a36Sopenharmony_ci	case 0x9a: /* call far absolute */
4562306a36Sopenharmony_ci		return X86_BR_CALL;
4662306a36Sopenharmony_ci	case 0xe0 ... 0xe3: /* loop jmp */
4762306a36Sopenharmony_ci		return X86_BR_JCC;
4862306a36Sopenharmony_ci	case 0xe9 ... 0xeb: /* jmp */
4962306a36Sopenharmony_ci		return X86_BR_JMP;
5062306a36Sopenharmony_ci	case 0xff: /* call near absolute, call far absolute ind */
5162306a36Sopenharmony_ci		if (insn_get_modrm(insn))
5262306a36Sopenharmony_ci			return X86_BR_ABORT;
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_ci		ext = (insn->modrm.bytes[0] >> 3) & 0x7;
5562306a36Sopenharmony_ci		switch (ext) {
5662306a36Sopenharmony_ci		case 2: /* near ind call */
5762306a36Sopenharmony_ci		case 3: /* far ind call */
5862306a36Sopenharmony_ci			return X86_BR_IND_CALL;
5962306a36Sopenharmony_ci		case 4:
6062306a36Sopenharmony_ci		case 5:
6162306a36Sopenharmony_ci			return X86_BR_IND_JMP;
6262306a36Sopenharmony_ci		}
6362306a36Sopenharmony_ci		return X86_BR_NONE;
6462306a36Sopenharmony_ci	}
6562306a36Sopenharmony_ci
6662306a36Sopenharmony_ci	return X86_BR_NONE;
6762306a36Sopenharmony_ci}
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci/*
7062306a36Sopenharmony_ci * return the type of control flow change at address "from"
7162306a36Sopenharmony_ci * instruction is not necessarily a branch (in case of interrupt).
7262306a36Sopenharmony_ci *
7362306a36Sopenharmony_ci * The branch type returned also includes the priv level of the
7462306a36Sopenharmony_ci * target of the control flow change (X86_BR_USER, X86_BR_KERNEL).
7562306a36Sopenharmony_ci *
7662306a36Sopenharmony_ci * If a branch type is unknown OR the instruction cannot be
7762306a36Sopenharmony_ci * decoded (e.g., text page not present), then X86_BR_NONE is
7862306a36Sopenharmony_ci * returned.
7962306a36Sopenharmony_ci *
8062306a36Sopenharmony_ci * While recording branches, some processors can report the "from"
8162306a36Sopenharmony_ci * address to be that of an instruction preceding the actual branch
8262306a36Sopenharmony_ci * when instruction fusion occurs. If fusion is expected, attempt to
8362306a36Sopenharmony_ci * find the type of the first branch instruction within the next
8462306a36Sopenharmony_ci * MAX_INSN_SIZE bytes and if found, provide the offset between the
8562306a36Sopenharmony_ci * reported "from" address and the actual branch instruction address.
8662306a36Sopenharmony_ci */
8762306a36Sopenharmony_cistatic int get_branch_type(unsigned long from, unsigned long to, int abort,
8862306a36Sopenharmony_ci			   bool fused, int *offset)
8962306a36Sopenharmony_ci{
9062306a36Sopenharmony_ci	struct insn insn;
9162306a36Sopenharmony_ci	void *addr;
9262306a36Sopenharmony_ci	int bytes_read, bytes_left, insn_offset;
9362306a36Sopenharmony_ci	int ret = X86_BR_NONE;
9462306a36Sopenharmony_ci	int to_plm, from_plm;
9562306a36Sopenharmony_ci	u8 buf[MAX_INSN_SIZE];
9662306a36Sopenharmony_ci	int is64 = 0;
9762306a36Sopenharmony_ci
9862306a36Sopenharmony_ci	/* make sure we initialize offset */
9962306a36Sopenharmony_ci	if (offset)
10062306a36Sopenharmony_ci		*offset = 0;
10162306a36Sopenharmony_ci
10262306a36Sopenharmony_ci	to_plm = kernel_ip(to) ? X86_BR_KERNEL : X86_BR_USER;
10362306a36Sopenharmony_ci	from_plm = kernel_ip(from) ? X86_BR_KERNEL : X86_BR_USER;
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	/*
10662306a36Sopenharmony_ci	 * maybe zero if lbr did not fill up after a reset by the time
10762306a36Sopenharmony_ci	 * we get a PMU interrupt
10862306a36Sopenharmony_ci	 */
10962306a36Sopenharmony_ci	if (from == 0 || to == 0)
11062306a36Sopenharmony_ci		return X86_BR_NONE;
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci	if (abort)
11362306a36Sopenharmony_ci		return X86_BR_ABORT | to_plm;
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci	if (from_plm == X86_BR_USER) {
11662306a36Sopenharmony_ci		/*
11762306a36Sopenharmony_ci		 * can happen if measuring at the user level only
11862306a36Sopenharmony_ci		 * and we interrupt in a kernel thread, e.g., idle.
11962306a36Sopenharmony_ci		 */
12062306a36Sopenharmony_ci		if (!current->mm)
12162306a36Sopenharmony_ci			return X86_BR_NONE;
12262306a36Sopenharmony_ci
12362306a36Sopenharmony_ci		/* may fail if text not present */
12462306a36Sopenharmony_ci		bytes_left = copy_from_user_nmi(buf, (void __user *)from,
12562306a36Sopenharmony_ci						MAX_INSN_SIZE);
12662306a36Sopenharmony_ci		bytes_read = MAX_INSN_SIZE - bytes_left;
12762306a36Sopenharmony_ci		if (!bytes_read)
12862306a36Sopenharmony_ci			return X86_BR_NONE;
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_ci		addr = buf;
13162306a36Sopenharmony_ci	} else {
13262306a36Sopenharmony_ci		/*
13362306a36Sopenharmony_ci		 * The LBR logs any address in the IP, even if the IP just
13462306a36Sopenharmony_ci		 * faulted. This means userspace can control the from address.
13562306a36Sopenharmony_ci		 * Ensure we don't blindly read any address by validating it is
13662306a36Sopenharmony_ci		 * a known text address and not a vsyscall address.
13762306a36Sopenharmony_ci		 */
13862306a36Sopenharmony_ci		if (kernel_text_address(from) && !in_gate_area_no_mm(from)) {
13962306a36Sopenharmony_ci			addr = (void *)from;
14062306a36Sopenharmony_ci			/*
14162306a36Sopenharmony_ci			 * Assume we can get the maximum possible size
14262306a36Sopenharmony_ci			 * when grabbing kernel data.  This is not
14362306a36Sopenharmony_ci			 * _strictly_ true since we could possibly be
14462306a36Sopenharmony_ci			 * executing up next to a memory hole, but
14562306a36Sopenharmony_ci			 * it is very unlikely to be a problem.
14662306a36Sopenharmony_ci			 */
14762306a36Sopenharmony_ci			bytes_read = MAX_INSN_SIZE;
14862306a36Sopenharmony_ci		} else {
14962306a36Sopenharmony_ci			return X86_BR_NONE;
15062306a36Sopenharmony_ci		}
15162306a36Sopenharmony_ci	}
15262306a36Sopenharmony_ci
15362306a36Sopenharmony_ci	/*
15462306a36Sopenharmony_ci	 * decoder needs to know the ABI especially
15562306a36Sopenharmony_ci	 * on 64-bit systems running 32-bit apps
15662306a36Sopenharmony_ci	 */
15762306a36Sopenharmony_ci#ifdef CONFIG_X86_64
15862306a36Sopenharmony_ci	is64 = kernel_ip((unsigned long)addr) || any_64bit_mode(current_pt_regs());
15962306a36Sopenharmony_ci#endif
16062306a36Sopenharmony_ci	insn_init(&insn, addr, bytes_read, is64);
16162306a36Sopenharmony_ci	ret = decode_branch_type(&insn);
16262306a36Sopenharmony_ci	insn_offset = 0;
16362306a36Sopenharmony_ci
16462306a36Sopenharmony_ci	/* Check for the possibility of branch fusion */
16562306a36Sopenharmony_ci	while (fused && ret == X86_BR_NONE) {
16662306a36Sopenharmony_ci		/* Check for decoding errors */
16762306a36Sopenharmony_ci		if (insn_get_length(&insn) || !insn.length)
16862306a36Sopenharmony_ci			break;
16962306a36Sopenharmony_ci
17062306a36Sopenharmony_ci		insn_offset += insn.length;
17162306a36Sopenharmony_ci		bytes_read -= insn.length;
17262306a36Sopenharmony_ci		if (bytes_read < 0)
17362306a36Sopenharmony_ci			break;
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci		insn_init(&insn, addr + insn_offset, bytes_read, is64);
17662306a36Sopenharmony_ci		ret = decode_branch_type(&insn);
17762306a36Sopenharmony_ci	}
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	if (offset)
18062306a36Sopenharmony_ci		*offset = insn_offset;
18162306a36Sopenharmony_ci
18262306a36Sopenharmony_ci	/*
18362306a36Sopenharmony_ci	 * interrupts, traps, faults (and thus ring transition) may
18462306a36Sopenharmony_ci	 * occur on any instructions. Thus, to classify them correctly,
18562306a36Sopenharmony_ci	 * we need to first look at the from and to priv levels. If they
18662306a36Sopenharmony_ci	 * are different and to is in the kernel, then it indicates
18762306a36Sopenharmony_ci	 * a ring transition. If the from instruction is not a ring
18862306a36Sopenharmony_ci	 * transition instr (syscall, systenter, int), then it means
18962306a36Sopenharmony_ci	 * it was a irq, trap or fault.
19062306a36Sopenharmony_ci	 *
19162306a36Sopenharmony_ci	 * we have no way of detecting kernel to kernel faults.
19262306a36Sopenharmony_ci	 */
19362306a36Sopenharmony_ci	if (from_plm == X86_BR_USER && to_plm == X86_BR_KERNEL
19462306a36Sopenharmony_ci	    && ret != X86_BR_SYSCALL && ret != X86_BR_INT)
19562306a36Sopenharmony_ci		ret = X86_BR_IRQ;
19662306a36Sopenharmony_ci
19762306a36Sopenharmony_ci	/*
19862306a36Sopenharmony_ci	 * branch priv level determined by target as
19962306a36Sopenharmony_ci	 * is done by HW when LBR_SELECT is implemented
20062306a36Sopenharmony_ci	 */
20162306a36Sopenharmony_ci	if (ret != X86_BR_NONE)
20262306a36Sopenharmony_ci		ret |= to_plm;
20362306a36Sopenharmony_ci
20462306a36Sopenharmony_ci	return ret;
20562306a36Sopenharmony_ci}
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ciint branch_type(unsigned long from, unsigned long to, int abort)
20862306a36Sopenharmony_ci{
20962306a36Sopenharmony_ci	return get_branch_type(from, to, abort, false, NULL);
21062306a36Sopenharmony_ci}
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ciint branch_type_fused(unsigned long from, unsigned long to, int abort,
21362306a36Sopenharmony_ci		      int *offset)
21462306a36Sopenharmony_ci{
21562306a36Sopenharmony_ci	return get_branch_type(from, to, abort, true, offset);
21662306a36Sopenharmony_ci}
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci#define X86_BR_TYPE_MAP_MAX	16
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_cistatic int branch_map[X86_BR_TYPE_MAP_MAX] = {
22162306a36Sopenharmony_ci	PERF_BR_CALL,		/* X86_BR_CALL */
22262306a36Sopenharmony_ci	PERF_BR_RET,		/* X86_BR_RET */
22362306a36Sopenharmony_ci	PERF_BR_SYSCALL,	/* X86_BR_SYSCALL */
22462306a36Sopenharmony_ci	PERF_BR_SYSRET,		/* X86_BR_SYSRET */
22562306a36Sopenharmony_ci	PERF_BR_UNKNOWN,	/* X86_BR_INT */
22662306a36Sopenharmony_ci	PERF_BR_ERET,		/* X86_BR_IRET */
22762306a36Sopenharmony_ci	PERF_BR_COND,		/* X86_BR_JCC */
22862306a36Sopenharmony_ci	PERF_BR_UNCOND,		/* X86_BR_JMP */
22962306a36Sopenharmony_ci	PERF_BR_IRQ,		/* X86_BR_IRQ */
23062306a36Sopenharmony_ci	PERF_BR_IND_CALL,	/* X86_BR_IND_CALL */
23162306a36Sopenharmony_ci	PERF_BR_UNKNOWN,	/* X86_BR_ABORT */
23262306a36Sopenharmony_ci	PERF_BR_UNKNOWN,	/* X86_BR_IN_TX */
23362306a36Sopenharmony_ci	PERF_BR_NO_TX,		/* X86_BR_NO_TX */
23462306a36Sopenharmony_ci	PERF_BR_CALL,		/* X86_BR_ZERO_CALL */
23562306a36Sopenharmony_ci	PERF_BR_UNKNOWN,	/* X86_BR_CALL_STACK */
23662306a36Sopenharmony_ci	PERF_BR_IND,		/* X86_BR_IND_JMP */
23762306a36Sopenharmony_ci};
23862306a36Sopenharmony_ci
23962306a36Sopenharmony_ciint common_branch_type(int type)
24062306a36Sopenharmony_ci{
24162306a36Sopenharmony_ci	int i;
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_ci	type >>= 2; /* skip X86_BR_USER and X86_BR_KERNEL */
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	if (type) {
24662306a36Sopenharmony_ci		i = __ffs(type);
24762306a36Sopenharmony_ci		if (i < X86_BR_TYPE_MAP_MAX)
24862306a36Sopenharmony_ci			return branch_map[i];
24962306a36Sopenharmony_ci	}
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	return PERF_BR_UNKNOWN;
25262306a36Sopenharmony_ci}
253