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(®s, 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, ®s, ppc_inst_read(p->ainsn.insn)) == 1) {
898afafa6fSNaveen N. Rao emulate_update_regs(®s, &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