xref: /openbmc/linux/arch/powerpc/kernel/optprobes.c (revision 7ae9fb1b7ecbb5d85d07857943f677fd1a559b18)
12874c5fdSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-or-later
251c9c084SAnju T /*
351c9c084SAnju T  * Code for Kernel probes Jump optimization.
451c9c084SAnju T  *
551c9c084SAnju T  * Copyright 2017, Anju T, IBM Corp.
651c9c084SAnju T  */
751c9c084SAnju T 
851c9c084SAnju T #include <linux/kprobes.h>
951c9c084SAnju T #include <linux/jump_label.h>
1051c9c084SAnju T #include <linux/types.h>
1151c9c084SAnju T #include <linux/slab.h>
1251c9c084SAnju T #include <linux/list.h>
1351c9c084SAnju T #include <asm/kprobes.h>
1451c9c084SAnju T #include <asm/ptrace.h>
1551c9c084SAnju T #include <asm/cacheflush.h>
1651c9c084SAnju T #include <asm/code-patching.h>
1751c9c084SAnju T #include <asm/sstep.h>
1851c9c084SAnju T #include <asm/ppc-opcode.h>
1975346251SJordan Niethe #include <asm/inst.h>
2051c9c084SAnju T 
21f38adf86SChristophe Leroy #define TMPL_CALL_HDLR_IDX	(optprobe_template_call_handler - optprobe_template_entry)
22f38adf86SChristophe Leroy #define TMPL_EMULATE_IDX	(optprobe_template_call_emulate - optprobe_template_entry)
23f38adf86SChristophe Leroy #define TMPL_RET_IDX		(optprobe_template_ret - optprobe_template_entry)
24f38adf86SChristophe Leroy #define TMPL_OP_IDX		(optprobe_template_op_address - optprobe_template_entry)
25f38adf86SChristophe Leroy #define TMPL_INSN_IDX		(optprobe_template_insn - optprobe_template_entry)
26f38adf86SChristophe Leroy #define TMPL_END_IDX		(optprobe_template_end - optprobe_template_entry)
2751c9c084SAnju T 
2851c9c084SAnju T static bool insn_page_in_use;
2951c9c084SAnju T 
alloc_optinsn_page(void)30b73c8cccSChristophe Leroy void *alloc_optinsn_page(void)
3151c9c084SAnju T {
3251c9c084SAnju T 	if (insn_page_in_use)
3351c9c084SAnju T 		return NULL;
3451c9c084SAnju T 	insn_page_in_use = true;
3551c9c084SAnju T 	return &optinsn_slot;
3651c9c084SAnju T }
3751c9c084SAnju T 
free_optinsn_page(void * page)38b73c8cccSChristophe Leroy void free_optinsn_page(void *page)
3951c9c084SAnju T {
4051c9c084SAnju T 	insn_page_in_use = false;
4151c9c084SAnju T }
4251c9c084SAnju T 
4351c9c084SAnju T /*
4451c9c084SAnju T  * Check if we can optimize this probe. Returns NIP post-emulation if this can
4551c9c084SAnju T  * be optimized and 0 otherwise.
4651c9c084SAnju T  */
can_optimize(struct kprobe * p)4751c9c084SAnju T static unsigned long can_optimize(struct kprobe *p)
4851c9c084SAnju T {
4951c9c084SAnju T 	struct pt_regs regs;
5051c9c084SAnju T 	struct instruction_op op;
5151c9c084SAnju T 	unsigned long nip = 0;
52afd3287cSChristophe Leroy 	unsigned long addr = (unsigned long)p->addr;
5351c9c084SAnju T 
5451c9c084SAnju T 	/*
5551c9c084SAnju T 	 * kprobe placed for kretprobe during boot time
56762df10bSAnju T 	 * has a 'nop' instruction, which can be emulated.
57762df10bSAnju T 	 * So further checks can be skipped.
5851c9c084SAnju T 	 */
59adf8a61aSMasami Hiramatsu 	if (p->addr == (kprobe_opcode_t *)&__kretprobe_trampoline)
60afd3287cSChristophe Leroy 		return addr + sizeof(kprobe_opcode_t);
6151c9c084SAnju T 
6251c9c084SAnju T 	/*
6351c9c084SAnju T 	 * We only support optimizing kernel addresses, but not
6451c9c084SAnju T 	 * module addresses.
6551c9c084SAnju T 	 *
6651c9c084SAnju T 	 * FIXME: Optimize kprobes placed in module addresses.
6751c9c084SAnju T 	 */
68afd3287cSChristophe Leroy 	if (!is_kernel_addr(addr))
6951c9c084SAnju T 		return 0;
7051c9c084SAnju T 
7151c9c084SAnju T 	memset(&regs, 0, sizeof(struct pt_regs));
72afd3287cSChristophe Leroy 	regs.nip = addr;
7351c9c084SAnju T 	regs.trap = 0x0;
7451c9c084SAnju T 	regs.msr = MSR_KERNEL;
7551c9c084SAnju T 
7651c9c084SAnju T 	/*
7751c9c084SAnju T 	 * Kprobe placed in conditional branch instructions are
7851c9c084SAnju T 	 * not optimized, as we can't predict the nip prior with
7951c9c084SAnju T 	 * dummy pt_regs and can not ensure that the return branch
8051c9c084SAnju T 	 * from detour buffer falls in the range of address (i.e 32MB).
8151c9c084SAnju T 	 * A branch back from trampoline is set up in the detour buffer
8251c9c084SAnju T 	 * to the nip returned by the analyse_instr() here.
8351c9c084SAnju T 	 *
8451c9c084SAnju T 	 * Ensure that the instruction is not a conditional branch,
8551c9c084SAnju T 	 * and that can be emulated.
8651c9c084SAnju T 	 */
8769d4d6e5SChristophe Leroy 	if (!is_conditional_branch(ppc_inst_read(p->ainsn.insn)) &&
8869d4d6e5SChristophe Leroy 	    analyse_instr(&op, &regs, ppc_inst_read(p->ainsn.insn)) == 1) {
898afafa6fSNaveen N. Rao 		emulate_update_regs(&regs, &op);
9051c9c084SAnju T 		nip = regs.nip;
918afafa6fSNaveen N. Rao 	}
9251c9c084SAnju T 
9351c9c084SAnju T 	return nip;
9451c9c084SAnju T }
9551c9c084SAnju T 
optimized_callback(struct optimized_kprobe * op,struct pt_regs * regs)9651c9c084SAnju T static void optimized_callback(struct optimized_kprobe *op,
9751c9c084SAnju T 			       struct pt_regs *regs)
9851c9c084SAnju T {
9951c9c084SAnju T 	/* This is possible if op is under delayed unoptimizing */
10051c9c084SAnju T 	if (kprobe_disabled(&op->kp))
10151c9c084SAnju T 		return;
10251c9c084SAnju T 
1038a2d71a3SNaveen N. Rao 	preempt_disable();
10451c9c084SAnju T 
10551c9c084SAnju T 	if (kprobe_running()) {
10651c9c084SAnju T 		kprobes_inc_nmissed_count(&op->kp);
10751c9c084SAnju T 	} else {
10851c9c084SAnju T 		__this_cpu_write(current_kprobe, &op->kp);
10959dc5bfcSNicholas Piggin 		regs_set_return_ip(regs, (unsigned long)op->kp.addr);
1108a2d71a3SNaveen N. Rao 		get_kprobe_ctlblk()->kprobe_status = KPROBE_HIT_ACTIVE;
11151c9c084SAnju T 		opt_pre_handler(&op->kp, regs);
11251c9c084SAnju T 		__this_cpu_write(current_kprobe, NULL);
11351c9c084SAnju T 	}
11451c9c084SAnju T 
115*04ec5d57SNaveen N. Rao 	preempt_enable();
11651c9c084SAnju T }
11751c9c084SAnju T NOKPROBE_SYMBOL(optimized_callback);
11851c9c084SAnju T 
arch_remove_optimized_kprobe(struct optimized_kprobe * op)11951c9c084SAnju T void arch_remove_optimized_kprobe(struct optimized_kprobe *op)
12051c9c084SAnju T {
12151c9c084SAnju T 	if (op->optinsn.insn) {
122b73c8cccSChristophe Leroy 		free_optinsn_slot(op->optinsn.insn, 1);
12351c9c084SAnju T 		op->optinsn.insn = NULL;
12451c9c084SAnju T 	}
12551c9c084SAnju T }
12651c9c084SAnju T 
patch_imm32_load_insns(unsigned long val,int reg,kprobe_opcode_t * addr)127eacf4c02SChristophe Leroy static void patch_imm32_load_insns(unsigned long val, int reg, kprobe_opcode_t *addr)
128eacf4c02SChristophe Leroy {
1290e628ad2SChristophe Leroy 	patch_instruction(addr++, ppc_inst(PPC_RAW_LIS(reg, PPC_HI(val))));
1300e628ad2SChristophe Leroy 	patch_instruction(addr, ppc_inst(PPC_RAW_ORI(reg, reg, PPC_LO(val))));
131eacf4c02SChristophe Leroy }
132eacf4c02SChristophe Leroy 
13351c9c084SAnju T /*
13451c9c084SAnju T  * Generate instructions to load provided immediate 64-bit value
1357a8818e0SJordan Niethe  * to register 'reg' and patch these instructions at 'addr'.
13651c9c084SAnju T  */
patch_imm64_load_insns(unsigned long long val,int reg,kprobe_opcode_t * addr)137eacf4c02SChristophe Leroy static void patch_imm64_load_insns(unsigned long long val, int reg, kprobe_opcode_t *addr)
13851c9c084SAnju T {
1390e628ad2SChristophe Leroy 	patch_instruction(addr++, ppc_inst(PPC_RAW_LIS(reg, PPC_HIGHEST(val))));
1400e628ad2SChristophe Leroy 	patch_instruction(addr++, ppc_inst(PPC_RAW_ORI(reg, reg, PPC_HIGHER(val))));
1410e628ad2SChristophe Leroy 	patch_instruction(addr++, ppc_inst(PPC_RAW_SLDI(reg, reg, 32)));
1420e628ad2SChristophe Leroy 	patch_instruction(addr++, ppc_inst(PPC_RAW_ORIS(reg, reg, PPC_HI(val))));
1430e628ad2SChristophe Leroy 	patch_instruction(addr, ppc_inst(PPC_RAW_ORI(reg, reg, PPC_LO(val))));
14451c9c084SAnju T }
14551c9c084SAnju T 
patch_imm_load_insns(unsigned long val,int reg,kprobe_opcode_t * addr)146eacf4c02SChristophe Leroy static void patch_imm_load_insns(unsigned long val, int reg, kprobe_opcode_t *addr)
147eacf4c02SChristophe Leroy {
148eacf4c02SChristophe Leroy 	if (IS_ENABLED(CONFIG_PPC64))
149eacf4c02SChristophe Leroy 		patch_imm64_load_insns(val, reg, addr);
150eacf4c02SChristophe Leroy 	else
151eacf4c02SChristophe Leroy 		patch_imm32_load_insns(val, reg, addr);
152eacf4c02SChristophe Leroy }
153eacf4c02SChristophe Leroy 
arch_prepare_optimized_kprobe(struct optimized_kprobe * op,struct kprobe * p)15451c9c084SAnju T int arch_prepare_optimized_kprobe(struct optimized_kprobe *op, struct kprobe *p)
15551c9c084SAnju T {
156c545b9f0SChristophe Leroy 	ppc_inst_t branch_op_callback, branch_emulate_step, temp;
157afd3287cSChristophe Leroy 	unsigned long op_callback_addr, emulate_step_addr;
158afd3287cSChristophe Leroy 	kprobe_opcode_t *buff;
15951c9c084SAnju T 	long b_offset;
160f3eca956SBalbir Singh 	unsigned long nip, size;
161f3eca956SBalbir Singh 	int rc, i;
16251c9c084SAnju T 
16351c9c084SAnju T 	nip = can_optimize(p);
16451c9c084SAnju T 	if (!nip)
16551c9c084SAnju T 		return -EILSEQ;
16651c9c084SAnju T 
16751c9c084SAnju T 	/* Allocate instruction slot for detour buffer */
168b73c8cccSChristophe Leroy 	buff = get_optinsn_slot();
16951c9c084SAnju T 	if (!buff)
17051c9c084SAnju T 		return -ENOMEM;
17151c9c084SAnju T 
17251c9c084SAnju T 	/*
17351c9c084SAnju T 	 * OPTPROBE uses 'b' instruction to branch to optinsn.insn.
17451c9c084SAnju T 	 *
17551c9c084SAnju T 	 * The target address has to be relatively nearby, to permit use
17651c9c084SAnju T 	 * of branch instruction in powerpc, because the address is specified
17751c9c084SAnju T 	 * in an immediate field in the instruction opcode itself, ie 24 bits
17851c9c084SAnju T 	 * in the opcode specify the address. Therefore the address should
17951c9c084SAnju T 	 * be within 32MB on either side of the current instruction.
18051c9c084SAnju T 	 */
18151c9c084SAnju T 	b_offset = (unsigned long)buff - (unsigned long)p->addr;
18251c9c084SAnju T 	if (!is_offset_in_branch_range(b_offset))
18351c9c084SAnju T 		goto error;
18451c9c084SAnju T 
18551c9c084SAnju T 	/* Check if the return address is also within 32MB range */
186afd3287cSChristophe Leroy 	b_offset = (unsigned long)(buff + TMPL_RET_IDX) - nip;
18751c9c084SAnju T 	if (!is_offset_in_branch_range(b_offset))
18851c9c084SAnju T 		goto error;
18951c9c084SAnju T 
19051c9c084SAnju T 	/* Setup template */
191f3eca956SBalbir Singh 	/* We can optimize this via patch_instruction_window later */
192f3eca956SBalbir Singh 	size = (TMPL_END_IDX * sizeof(kprobe_opcode_t)) / sizeof(int);
193f3eca956SBalbir Singh 	pr_devel("Copying template to %p, size %lu\n", buff, size);
194f3eca956SBalbir Singh 	for (i = 0; i < size; i++) {
19569d4d6e5SChristophe Leroy 		rc = patch_instruction(buff + i, ppc_inst(*(optprobe_template_entry + i)));
196f3eca956SBalbir Singh 		if (rc < 0)
197f3eca956SBalbir Singh 			goto error;
198f3eca956SBalbir Singh 	}
19951c9c084SAnju T 
20051c9c084SAnju T 	/*
20151c9c084SAnju T 	 * Fixup the template with instructions to:
20251c9c084SAnju T 	 * 1. load the address of the actual probepoint
20351c9c084SAnju T 	 */
204eacf4c02SChristophe Leroy 	patch_imm_load_insns((unsigned long)op, 3, buff + TMPL_OP_IDX);
20551c9c084SAnju T 
20651c9c084SAnju T 	/*
20751c9c084SAnju T 	 * 2. branch to optimized_callback() and emulate_step()
20851c9c084SAnju T 	 */
209afd3287cSChristophe Leroy 	op_callback_addr = ppc_kallsyms_lookup_name("optimized_callback");
210afd3287cSChristophe Leroy 	emulate_step_addr = ppc_kallsyms_lookup_name("emulate_step");
21151c9c084SAnju T 	if (!op_callback_addr || !emulate_step_addr) {
2121b32cd17SNaveen N. Rao 		WARN(1, "Unable to lookup optimized_callback()/emulate_step()\n");
21351c9c084SAnju T 		goto error;
21451c9c084SAnju T 	}
21551c9c084SAnju T 
21669d4d6e5SChristophe Leroy 	rc = create_branch(&branch_op_callback, buff + TMPL_CALL_HDLR_IDX,
217afd3287cSChristophe Leroy 			   op_callback_addr, BRANCH_SET_LINK);
21851c9c084SAnju T 
21969d4d6e5SChristophe Leroy 	rc |= create_branch(&branch_emulate_step, buff + TMPL_EMULATE_IDX,
220afd3287cSChristophe Leroy 			    emulate_step_addr, BRANCH_SET_LINK);
22151c9c084SAnju T 
2227c95d889SJordan Niethe 	if (rc)
22351c9c084SAnju T 		goto error;
22451c9c084SAnju T 
22569d4d6e5SChristophe Leroy 	patch_instruction(buff + TMPL_CALL_HDLR_IDX, branch_op_callback);
22669d4d6e5SChristophe Leroy 	patch_instruction(buff + TMPL_EMULATE_IDX, branch_emulate_step);
22751c9c084SAnju T 
22851c9c084SAnju T 	/*
22951c9c084SAnju T 	 * 3. load instruction to be emulated into relevant register, and
23051c9c084SAnju T 	 */
23169d4d6e5SChristophe Leroy 	temp = ppc_inst_read(p->ainsn.insn);
232eacf4c02SChristophe Leroy 	patch_imm_load_insns(ppc_inst_as_ulong(temp), 4, buff + TMPL_INSN_IDX);
23351c9c084SAnju T 
23451c9c084SAnju T 	/*
23551c9c084SAnju T 	 * 4. branch back from trampoline
23651c9c084SAnju T 	 */
23769d4d6e5SChristophe Leroy 	patch_branch(buff + TMPL_RET_IDX, nip, 0);
23851c9c084SAnju T 
239f38adf86SChristophe Leroy 	flush_icache_range((unsigned long)buff, (unsigned long)(&buff[TMPL_END_IDX]));
24051c9c084SAnju T 
24151c9c084SAnju T 	op->optinsn.insn = buff;
24251c9c084SAnju T 
24351c9c084SAnju T 	return 0;
24451c9c084SAnju T 
24551c9c084SAnju T error:
246b73c8cccSChristophe Leroy 	free_optinsn_slot(buff, 0);
24751c9c084SAnju T 	return -ERANGE;
24851c9c084SAnju T 
24951c9c084SAnju T }
25051c9c084SAnju T 
arch_prepared_optinsn(struct arch_optimized_insn * optinsn)25151c9c084SAnju T int arch_prepared_optinsn(struct arch_optimized_insn *optinsn)
25251c9c084SAnju T {
25351c9c084SAnju T 	return optinsn->insn != NULL;
25451c9c084SAnju T }
25551c9c084SAnju T 
25651c9c084SAnju T /*
25751c9c084SAnju T  * On powerpc, Optprobes always replaces one instruction (4 bytes
25851c9c084SAnju T  * aligned and 4 bytes long). It is impossible to encounter another
25951c9c084SAnju T  * kprobe in this address range. So always return 0.
26051c9c084SAnju T  */
arch_check_optimized_kprobe(struct optimized_kprobe * op)26151c9c084SAnju T int arch_check_optimized_kprobe(struct optimized_kprobe *op)
26251c9c084SAnju T {
26351c9c084SAnju T 	return 0;
26451c9c084SAnju T }
26551c9c084SAnju T 
arch_optimize_kprobes(struct list_head * oplist)26651c9c084SAnju T void arch_optimize_kprobes(struct list_head *oplist)
26751c9c084SAnju T {
268c545b9f0SChristophe Leroy 	ppc_inst_t instr;
26951c9c084SAnju T 	struct optimized_kprobe *op;
27051c9c084SAnju T 	struct optimized_kprobe *tmp;
27151c9c084SAnju T 
27251c9c084SAnju T 	list_for_each_entry_safe(op, tmp, oplist, list) {
27351c9c084SAnju T 		/*
27451c9c084SAnju T 		 * Backup instructions which will be replaced
27551c9c084SAnju T 		 * by jump address
27651c9c084SAnju T 		 */
277f38adf86SChristophe Leroy 		memcpy(op->optinsn.copied_insn, op->kp.addr, RELATIVEJUMP_SIZE);
278f38adf86SChristophe Leroy 		create_branch(&instr, op->kp.addr, (unsigned long)op->optinsn.insn, 0);
27969d4d6e5SChristophe Leroy 		patch_instruction(op->kp.addr, instr);
28051c9c084SAnju T 		list_del_init(&op->list);
28151c9c084SAnju T 	}
28251c9c084SAnju T }
28351c9c084SAnju T 
arch_unoptimize_kprobe(struct optimized_kprobe * op)28451c9c084SAnju T void arch_unoptimize_kprobe(struct optimized_kprobe *op)
28551c9c084SAnju T {
28651c9c084SAnju T 	arch_arm_kprobe(&op->kp);
28751c9c084SAnju T }
28851c9c084SAnju T 
arch_unoptimize_kprobes(struct list_head * oplist,struct list_head * done_list)289f38adf86SChristophe Leroy void arch_unoptimize_kprobes(struct list_head *oplist, struct list_head *done_list)
29051c9c084SAnju T {
29151c9c084SAnju T 	struct optimized_kprobe *op;
29251c9c084SAnju T 	struct optimized_kprobe *tmp;
29351c9c084SAnju T 
29451c9c084SAnju T 	list_for_each_entry_safe(op, tmp, oplist, list) {
29551c9c084SAnju T 		arch_unoptimize_kprobe(op);
29651c9c084SAnju T 		list_move(&op->list, done_list);
29751c9c084SAnju T 	}
29851c9c084SAnju T }
29951c9c084SAnju T 
arch_within_optimized_kprobe(struct optimized_kprobe * op,kprobe_opcode_t * addr)300c42421e2SMasami Hiramatsu int arch_within_optimized_kprobe(struct optimized_kprobe *op, kprobe_opcode_t *addr)
30151c9c084SAnju T {
302c42421e2SMasami Hiramatsu 	return (op->kp.addr <= addr &&
303c42421e2SMasami Hiramatsu 		op->kp.addr + (RELATIVEJUMP_SIZE / sizeof(kprobe_opcode_t)) > addr);
30451c9c084SAnju T }
305