xref: /linux/arch/parisc/kernel/kprobes.c (revision a65bcad5)
18858ac8eSSven Schnelle // SPDX-License-Identifier: GPL-2.0
28858ac8eSSven Schnelle /*
38858ac8eSSven Schnelle  * arch/parisc/kernel/kprobes.c
48858ac8eSSven Schnelle  *
58858ac8eSSven Schnelle  * PA-RISC kprobes implementation
68858ac8eSSven Schnelle  *
78858ac8eSSven Schnelle  * Copyright (c) 2019 Sven Schnelle <svens@stackframe.org>
89b046d02SHelge Deller  * Copyright (c) 2022 Helge Deller <deller@gmx.de>
98858ac8eSSven Schnelle  */
108858ac8eSSven Schnelle 
118858ac8eSSven Schnelle #include <linux/types.h>
128858ac8eSSven Schnelle #include <linux/kprobes.h>
138858ac8eSSven Schnelle #include <linux/slab.h>
148858ac8eSSven Schnelle #include <asm/cacheflush.h>
158858ac8eSSven Schnelle #include <asm/patch.h>
168858ac8eSSven Schnelle 
178858ac8eSSven Schnelle DEFINE_PER_CPU(struct kprobe *, current_kprobe) = NULL;
188858ac8eSSven Schnelle DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
198858ac8eSSven Schnelle 
arch_prepare_kprobe(struct kprobe * p)208858ac8eSSven Schnelle int __kprobes arch_prepare_kprobe(struct kprobe *p)
218858ac8eSSven Schnelle {
228858ac8eSSven Schnelle 	if ((unsigned long)p->addr & 3UL)
238858ac8eSSven Schnelle 		return -EINVAL;
248858ac8eSSven Schnelle 
258858ac8eSSven Schnelle 	p->ainsn.insn = get_insn_slot();
268858ac8eSSven Schnelle 	if (!p->ainsn.insn)
278858ac8eSSven Schnelle 		return -ENOMEM;
288858ac8eSSven Schnelle 
299b046d02SHelge Deller 	/*
309b046d02SHelge Deller 	 * Set up new instructions. Second break instruction will
319b046d02SHelge Deller 	 * trigger call of parisc_kprobe_ss_handler().
329b046d02SHelge Deller 	 */
338858ac8eSSven Schnelle 	p->opcode = *p->addr;
349b046d02SHelge Deller 	p->ainsn.insn[0] = p->opcode;
359b046d02SHelge Deller 	p->ainsn.insn[1] = PARISC_KPROBES_BREAK_INSN2;
369b046d02SHelge Deller 
378858ac8eSSven Schnelle 	flush_insn_slot(p);
388858ac8eSSven Schnelle 	return 0;
398858ac8eSSven Schnelle }
408858ac8eSSven Schnelle 
arch_remove_kprobe(struct kprobe * p)418858ac8eSSven Schnelle void __kprobes arch_remove_kprobe(struct kprobe *p)
428858ac8eSSven Schnelle {
438858ac8eSSven Schnelle 	if (!p->ainsn.insn)
448858ac8eSSven Schnelle 		return;
458858ac8eSSven Schnelle 
468858ac8eSSven Schnelle 	free_insn_slot(p->ainsn.insn, 0);
478858ac8eSSven Schnelle 	p->ainsn.insn = NULL;
488858ac8eSSven Schnelle }
498858ac8eSSven Schnelle 
arch_arm_kprobe(struct kprobe * p)508858ac8eSSven Schnelle void __kprobes arch_arm_kprobe(struct kprobe *p)
518858ac8eSSven Schnelle {
528858ac8eSSven Schnelle 	patch_text(p->addr, PARISC_KPROBES_BREAK_INSN);
538858ac8eSSven Schnelle }
548858ac8eSSven Schnelle 
arch_disarm_kprobe(struct kprobe * p)558858ac8eSSven Schnelle void __kprobes arch_disarm_kprobe(struct kprobe *p)
568858ac8eSSven Schnelle {
578858ac8eSSven Schnelle 	patch_text(p->addr, p->opcode);
588858ac8eSSven Schnelle }
598858ac8eSSven Schnelle 
save_previous_kprobe(struct kprobe_ctlblk * kcb)608858ac8eSSven Schnelle static void __kprobes save_previous_kprobe(struct kprobe_ctlblk *kcb)
618858ac8eSSven Schnelle {
628858ac8eSSven Schnelle 	kcb->prev_kprobe.kp = kprobe_running();
638858ac8eSSven Schnelle 	kcb->prev_kprobe.status = kcb->kprobe_status;
648858ac8eSSven Schnelle }
658858ac8eSSven Schnelle 
restore_previous_kprobe(struct kprobe_ctlblk * kcb)668858ac8eSSven Schnelle static void __kprobes restore_previous_kprobe(struct kprobe_ctlblk *kcb)
678858ac8eSSven Schnelle {
688858ac8eSSven Schnelle 	__this_cpu_write(current_kprobe, kcb->prev_kprobe.kp);
698858ac8eSSven Schnelle 	kcb->kprobe_status = kcb->prev_kprobe.status;
708858ac8eSSven Schnelle }
718858ac8eSSven Schnelle 
set_current_kprobe(struct kprobe * p)728858ac8eSSven Schnelle static inline void __kprobes set_current_kprobe(struct kprobe *p)
738858ac8eSSven Schnelle {
748858ac8eSSven Schnelle 	__this_cpu_write(current_kprobe, p);
758858ac8eSSven Schnelle }
768858ac8eSSven Schnelle 
setup_singlestep(struct kprobe * p,struct kprobe_ctlblk * kcb,struct pt_regs * regs)778858ac8eSSven Schnelle static void __kprobes setup_singlestep(struct kprobe *p,
788858ac8eSSven Schnelle 		struct kprobe_ctlblk *kcb, struct pt_regs *regs)
798858ac8eSSven Schnelle {
808858ac8eSSven Schnelle 	kcb->iaoq[0] = regs->iaoq[0];
818858ac8eSSven Schnelle 	kcb->iaoq[1] = regs->iaoq[1];
829b046d02SHelge Deller 	instruction_pointer_set(regs, (unsigned long)p->ainsn.insn);
838858ac8eSSven Schnelle }
848858ac8eSSven Schnelle 
parisc_kprobe_break_handler(struct pt_regs * regs)858858ac8eSSven Schnelle int __kprobes parisc_kprobe_break_handler(struct pt_regs *regs)
868858ac8eSSven Schnelle {
878858ac8eSSven Schnelle 	struct kprobe *p;
888858ac8eSSven Schnelle 	struct kprobe_ctlblk *kcb;
898858ac8eSSven Schnelle 
908858ac8eSSven Schnelle 	preempt_disable();
918858ac8eSSven Schnelle 
928858ac8eSSven Schnelle 	kcb = get_kprobe_ctlblk();
938858ac8eSSven Schnelle 	p = get_kprobe((unsigned long *)regs->iaoq[0]);
948858ac8eSSven Schnelle 
958858ac8eSSven Schnelle 	if (!p) {
968858ac8eSSven Schnelle 		preempt_enable_no_resched();
978858ac8eSSven Schnelle 		return 0;
988858ac8eSSven Schnelle 	}
998858ac8eSSven Schnelle 
1008858ac8eSSven Schnelle 	if (kprobe_running()) {
1018858ac8eSSven Schnelle 		/*
1028858ac8eSSven Schnelle 		 * We have reentered the kprobe_handler, since another kprobe
1038858ac8eSSven Schnelle 		 * was hit while within the handler, we save the original
1048858ac8eSSven Schnelle 		 * kprobes and single step on the instruction of the new probe
1058858ac8eSSven Schnelle 		 * without calling any user handlers to avoid recursive
1068858ac8eSSven Schnelle 		 * kprobes.
1078858ac8eSSven Schnelle 		 */
1088858ac8eSSven Schnelle 		save_previous_kprobe(kcb);
1098858ac8eSSven Schnelle 		set_current_kprobe(p);
1108858ac8eSSven Schnelle 		kprobes_inc_nmissed_count(p);
1118858ac8eSSven Schnelle 		setup_singlestep(p, kcb, regs);
1128858ac8eSSven Schnelle 		kcb->kprobe_status = KPROBE_REENTER;
1138858ac8eSSven Schnelle 		return 1;
1148858ac8eSSven Schnelle 	}
1158858ac8eSSven Schnelle 
1168858ac8eSSven Schnelle 	set_current_kprobe(p);
1178858ac8eSSven Schnelle 	kcb->kprobe_status = KPROBE_HIT_ACTIVE;
1188858ac8eSSven Schnelle 
1198858ac8eSSven Schnelle 	/* If we have no pre-handler or it returned 0, we continue with
1208858ac8eSSven Schnelle 	 * normal processing. If we have a pre-handler and it returned
1218858ac8eSSven Schnelle 	 * non-zero - which means user handler setup registers to exit
1228858ac8eSSven Schnelle 	 * to another instruction, we must skip the single stepping.
1238858ac8eSSven Schnelle 	 */
1248858ac8eSSven Schnelle 
1258858ac8eSSven Schnelle 	if (!p->pre_handler || !p->pre_handler(p, regs)) {
1268858ac8eSSven Schnelle 		setup_singlestep(p, kcb, regs);
1278858ac8eSSven Schnelle 		kcb->kprobe_status = KPROBE_HIT_SS;
1288858ac8eSSven Schnelle 	} else {
1298858ac8eSSven Schnelle 		reset_current_kprobe();
1308858ac8eSSven Schnelle 		preempt_enable_no_resched();
1318858ac8eSSven Schnelle 	}
1328858ac8eSSven Schnelle 	return 1;
1338858ac8eSSven Schnelle }
1348858ac8eSSven Schnelle 
parisc_kprobe_ss_handler(struct pt_regs * regs)1358858ac8eSSven Schnelle int __kprobes parisc_kprobe_ss_handler(struct pt_regs *regs)
1368858ac8eSSven Schnelle {
1378858ac8eSSven Schnelle 	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
1388858ac8eSSven Schnelle 	struct kprobe *p = kprobe_running();
1398858ac8eSSven Schnelle 
14059a783dbSHelge Deller 	if (!p)
14159a783dbSHelge Deller 		return 0;
14259a783dbSHelge Deller 
1438858ac8eSSven Schnelle 	if (regs->iaoq[0] != (unsigned long)p->ainsn.insn+4)
1448858ac8eSSven Schnelle 		return 0;
1458858ac8eSSven Schnelle 
1468858ac8eSSven Schnelle 	/* restore back original saved kprobe variables and continue */
1478858ac8eSSven Schnelle 	if (kcb->kprobe_status == KPROBE_REENTER) {
1488858ac8eSSven Schnelle 		restore_previous_kprobe(kcb);
1498858ac8eSSven Schnelle 		return 1;
1508858ac8eSSven Schnelle 	}
1518858ac8eSSven Schnelle 
1528858ac8eSSven Schnelle 	/* for absolute branch instructions we can copy iaoq_b. for relative
1538858ac8eSSven Schnelle 	 * branch instructions we need to calculate the new address based on the
1548858ac8eSSven Schnelle 	 * difference between iaoq_f and iaoq_b. We cannot use iaoq_b without
155a65bcad5SJulia Lawall 	 * modifications because it's based on our ainsn.insn address.
1568858ac8eSSven Schnelle 	 */
1578858ac8eSSven Schnelle 
1588858ac8eSSven Schnelle 	if (p->post_handler)
1598858ac8eSSven Schnelle 		p->post_handler(p, regs, 0);
1608858ac8eSSven Schnelle 
1618858ac8eSSven Schnelle 	switch (regs->iir >> 26) {
1628858ac8eSSven Schnelle 	case 0x38: /* BE */
1638858ac8eSSven Schnelle 	case 0x39: /* BE,L */
1648858ac8eSSven Schnelle 	case 0x3a: /* BV */
1658858ac8eSSven Schnelle 	case 0x3b: /* BVE */
1668858ac8eSSven Schnelle 		/* for absolute branches, regs->iaoq[1] has already the right
1678858ac8eSSven Schnelle 		 * address
1688858ac8eSSven Schnelle 		 */
1698858ac8eSSven Schnelle 		regs->iaoq[0] = kcb->iaoq[1];
1708858ac8eSSven Schnelle 		break;
1718858ac8eSSven Schnelle 	default:
1728858ac8eSSven Schnelle 		regs->iaoq[0] = kcb->iaoq[1];
1739b046d02SHelge Deller 		regs->iaoq[1] = regs->iaoq[0] + 4;
1748858ac8eSSven Schnelle 		break;
1758858ac8eSSven Schnelle 	}
1768858ac8eSSven Schnelle 	kcb->kprobe_status = KPROBE_HIT_SSDONE;
1778858ac8eSSven Schnelle 	reset_current_kprobe();
1788858ac8eSSven Schnelle 	return 1;
1798858ac8eSSven Schnelle }
1808858ac8eSSven Schnelle 
__kretprobe_trampoline(void)181adf8a61aSMasami Hiramatsu void __kretprobe_trampoline(void)
182e0b59b7bSSven Schnelle {
183e0b59b7bSSven Schnelle 	asm volatile("nop");
184e0b59b7bSSven Schnelle 	asm volatile("nop");
185e0b59b7bSSven Schnelle }
186e0b59b7bSSven Schnelle 
187e0b59b7bSSven Schnelle static int __kprobes trampoline_probe_handler(struct kprobe *p,
188e0b59b7bSSven Schnelle 					      struct pt_regs *regs);
189e0b59b7bSSven Schnelle 
190e0b59b7bSSven Schnelle static struct kprobe trampoline_p = {
191e0b59b7bSSven Schnelle 	.pre_handler = trampoline_probe_handler
192e0b59b7bSSven Schnelle };
193e0b59b7bSSven Schnelle 
trampoline_probe_handler(struct kprobe * p,struct pt_regs * regs)194e0b59b7bSSven Schnelle static int __kprobes trampoline_probe_handler(struct kprobe *p,
195e0b59b7bSSven Schnelle 					      struct pt_regs *regs)
196e0b59b7bSSven Schnelle {
1979b046d02SHelge Deller 	__kretprobe_trampoline_handler(regs, NULL);
19816ff6f7aSMasami Hiramatsu 
199e0b59b7bSSven Schnelle 	return 1;
200e0b59b7bSSven Schnelle }
201e0b59b7bSSven Schnelle 
arch_kretprobe_fixup_return(struct pt_regs * regs,kprobe_opcode_t * correct_ret_addr)2029b046d02SHelge Deller void arch_kretprobe_fixup_return(struct pt_regs *regs,
2039b046d02SHelge Deller 				 kprobe_opcode_t *correct_ret_addr)
2049b046d02SHelge Deller {
2059b046d02SHelge Deller 	regs->gr[2] = (unsigned long)correct_ret_addr;
2069b046d02SHelge Deller }
2079b046d02SHelge Deller 
arch_prepare_kretprobe(struct kretprobe_instance * ri,struct pt_regs * regs)208e0b59b7bSSven Schnelle void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri,
209e0b59b7bSSven Schnelle 				      struct pt_regs *regs)
210e0b59b7bSSven Schnelle {
211e0b59b7bSSven Schnelle 	ri->ret_addr = (kprobe_opcode_t *)regs->gr[2];
21216ff6f7aSMasami Hiramatsu 	ri->fp = NULL;
213e0b59b7bSSven Schnelle 
214e0b59b7bSSven Schnelle 	/* Replace the return addr with trampoline addr. */
215e0b59b7bSSven Schnelle 	regs->gr[2] = (unsigned long)trampoline_p.addr;
216e0b59b7bSSven Schnelle }
217e0b59b7bSSven Schnelle 
arch_trampoline_kprobe(struct kprobe * p)218e0b59b7bSSven Schnelle int __kprobes arch_trampoline_kprobe(struct kprobe *p)
219e0b59b7bSSven Schnelle {
220e0b59b7bSSven Schnelle 	return p->addr == trampoline_p.addr;
221e0b59b7bSSven Schnelle }
2228858ac8eSSven Schnelle 
arch_init_kprobes(void)2238858ac8eSSven Schnelle int __init arch_init_kprobes(void)
2248858ac8eSSven Schnelle {
225e0b59b7bSSven Schnelle 	trampoline_p.addr = (kprobe_opcode_t *)
226adf8a61aSMasami Hiramatsu 		dereference_function_descriptor(__kretprobe_trampoline);
227e0b59b7bSSven Schnelle 	return register_kprobe(&trampoline_p);
2288858ac8eSSven Schnelle }
229