xref: /openbmc/linux/arch/mips/kernel/kprobes.c (revision 4f2c0a4acffbec01079c28f839422e64ddeff004)
1873e65bcSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
2c1bf207dSDavid Daney /*
3c1bf207dSDavid Daney  *  Kernel Probes (KProbes)
4c1bf207dSDavid Daney  *  arch/mips/kernel/kprobes.c
5c1bf207dSDavid Daney  *
6c1bf207dSDavid Daney  *  Copyright 2006 Sony Corp.
7c1bf207dSDavid Daney  *  Copyright 2010 Cavium Networks
8c1bf207dSDavid Daney  *
9c1bf207dSDavid Daney  *  Some portions copied from the powerpc version.
10c1bf207dSDavid Daney  *
11c1bf207dSDavid Daney  *   Copyright (C) IBM Corporation, 2002, 2004
12c1bf207dSDavid Daney  */
13c1bf207dSDavid Daney 
149c89bb8eSMasami Hiramatsu #define pr_fmt(fmt) "kprobes: " fmt
159c89bb8eSMasami Hiramatsu 
16c1bf207dSDavid Daney #include <linux/kprobes.h>
17c1bf207dSDavid Daney #include <linux/preempt.h>
1841dde781SManeesh Soni #include <linux/uaccess.h>
19c1bf207dSDavid Daney #include <linux/kdebug.h>
20c1bf207dSDavid Daney #include <linux/slab.h>
21c1bf207dSDavid Daney 
22c1bf207dSDavid Daney #include <asm/ptrace.h>
236457a396SManeesh Soni #include <asm/branch.h>
24c1bf207dSDavid Daney #include <asm/break.h>
25e3031b32SMarcin Nowakowski 
26e3031b32SMarcin Nowakowski #include "probes-common.h"
27c1bf207dSDavid Daney 
28c1bf207dSDavid Daney static const union mips_instruction breakpoint_insn = {
29c1bf207dSDavid Daney 	.b_format = {
30c1bf207dSDavid Daney 		.opcode = spec_op,
31c1bf207dSDavid Daney 		.code = BRK_KPROBE_BP,
32c1bf207dSDavid Daney 		.func = break_op
33c1bf207dSDavid Daney 	}
34c1bf207dSDavid Daney };
35c1bf207dSDavid Daney 
36c1bf207dSDavid Daney static const union mips_instruction breakpoint2_insn = {
37c1bf207dSDavid Daney 	.b_format = {
38c1bf207dSDavid Daney 		.opcode = spec_op,
39c1bf207dSDavid Daney 		.code = BRK_KPROBE_SSTEPBP,
40c1bf207dSDavid Daney 		.func = break_op
41c1bf207dSDavid Daney 	}
42c1bf207dSDavid Daney };
43c1bf207dSDavid Daney 
44c1bf207dSDavid Daney DEFINE_PER_CPU(struct kprobe *, current_kprobe);
45c1bf207dSDavid Daney DEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk);
46c1bf207dSDavid Daney 
insn_has_delayslot(union mips_instruction insn)47*f5e2d818STiezhu Yang static int insn_has_delayslot(union mips_instruction insn)
48c1bf207dSDavid Daney {
49e3031b32SMarcin Nowakowski 	return __insn_has_delay_slot(insn);
50c1bf207dSDavid Daney }
51*f5e2d818STiezhu Yang NOKPROBE_SYMBOL(insn_has_delayslot);
52c1bf207dSDavid Daney 
539233c1eeSManeesh Soni /*
549233c1eeSManeesh Soni  * insn_has_ll_or_sc function checks whether instruction is ll or sc
559233c1eeSManeesh Soni  * one; putting breakpoint on top of atomic ll/sc pair is bad idea;
569233c1eeSManeesh Soni  * so we need to prevent it and refuse kprobes insertion for such
579233c1eeSManeesh Soni  * instructions; cannot do much about breakpoint in the middle of
589233c1eeSManeesh Soni  * ll/sc pair; it is upto user to avoid those places
599233c1eeSManeesh Soni  */
insn_has_ll_or_sc(union mips_instruction insn)60*f5e2d818STiezhu Yang static int insn_has_ll_or_sc(union mips_instruction insn)
619233c1eeSManeesh Soni {
629233c1eeSManeesh Soni 	int ret = 0;
639233c1eeSManeesh Soni 
649233c1eeSManeesh Soni 	switch (insn.i_format.opcode) {
659233c1eeSManeesh Soni 	case ll_op:
669233c1eeSManeesh Soni 	case lld_op:
679233c1eeSManeesh Soni 	case sc_op:
689233c1eeSManeesh Soni 	case scd_op:
699233c1eeSManeesh Soni 		ret = 1;
709233c1eeSManeesh Soni 		break;
719233c1eeSManeesh Soni 	default:
729233c1eeSManeesh Soni 		break;
739233c1eeSManeesh Soni 	}
749233c1eeSManeesh Soni 	return ret;
759233c1eeSManeesh Soni }
76*f5e2d818STiezhu Yang NOKPROBE_SYMBOL(insn_has_ll_or_sc);
779233c1eeSManeesh Soni 
arch_prepare_kprobe(struct kprobe * p)78*f5e2d818STiezhu Yang int arch_prepare_kprobe(struct kprobe *p)
79c1bf207dSDavid Daney {
80c1bf207dSDavid Daney 	union mips_instruction insn;
81c1bf207dSDavid Daney 	union mips_instruction prev_insn;
82c1bf207dSDavid Daney 	int ret = 0;
83c1bf207dSDavid Daney 
84c1bf207dSDavid Daney 	insn = p->addr[0];
85c1bf207dSDavid Daney 
869233c1eeSManeesh Soni 	if (insn_has_ll_or_sc(insn)) {
879c89bb8eSMasami Hiramatsu 		pr_notice("Kprobes for ll and sc instructions are not supported\n");
889233c1eeSManeesh Soni 		ret = -EINVAL;
899233c1eeSManeesh Soni 		goto out;
909233c1eeSManeesh Soni 	}
919233c1eeSManeesh Soni 
92fe557319SChristoph Hellwig 	if (copy_from_kernel_nofault(&prev_insn, p->addr - 1,
93fe557319SChristoph Hellwig 			sizeof(mips_instruction)) == 0 &&
9441dde781SManeesh Soni 	    insn_has_delayslot(prev_insn)) {
9541dde781SManeesh Soni 		pr_notice("Kprobes for branch delayslot are not supported\n");
96c1bf207dSDavid Daney 		ret = -EINVAL;
97c1bf207dSDavid Daney 		goto out;
98c1bf207dSDavid Daney 	}
99c1bf207dSDavid Daney 
100d05c5130SMarcin Nowakowski 	if (__insn_is_compact_branch(insn)) {
101d05c5130SMarcin Nowakowski 		pr_notice("Kprobes for compact branches are not supported\n");
102d05c5130SMarcin Nowakowski 		ret = -EINVAL;
103d05c5130SMarcin Nowakowski 		goto out;
104d05c5130SMarcin Nowakowski 	}
105d05c5130SMarcin Nowakowski 
106c1bf207dSDavid Daney 	/* insn: must be on special executable page on mips. */
107c1bf207dSDavid Daney 	p->ainsn.insn = get_insn_slot();
108c1bf207dSDavid Daney 	if (!p->ainsn.insn) {
109c1bf207dSDavid Daney 		ret = -ENOMEM;
110c1bf207dSDavid Daney 		goto out;
111c1bf207dSDavid Daney 	}
112c1bf207dSDavid Daney 
113c1bf207dSDavid Daney 	/*
114c1bf207dSDavid Daney 	 * In the kprobe->ainsn.insn[] array we store the original
115c1bf207dSDavid Daney 	 * instruction at index zero and a break trap instruction at
116c1bf207dSDavid Daney 	 * index one.
1176457a396SManeesh Soni 	 *
1186457a396SManeesh Soni 	 * On MIPS arch if the instruction at probed address is a
1196457a396SManeesh Soni 	 * branch instruction, we need to execute the instruction at
1206457a396SManeesh Soni 	 * Branch Delayslot (BD) at the time of probe hit. As MIPS also
1216457a396SManeesh Soni 	 * doesn't have single stepping support, the BD instruction can
1226457a396SManeesh Soni 	 * not be executed in-line and it would be executed on SSOL slot
1236457a396SManeesh Soni 	 * using a normal breakpoint instruction in the next slot.
1246457a396SManeesh Soni 	 * So, read the instruction and save it for later execution.
125c1bf207dSDavid Daney 	 */
1266457a396SManeesh Soni 	if (insn_has_delayslot(insn))
1276457a396SManeesh Soni 		memcpy(&p->ainsn.insn[0], p->addr + 1, sizeof(kprobe_opcode_t));
1286457a396SManeesh Soni 	else
129c1bf207dSDavid Daney 		memcpy(&p->ainsn.insn[0], p->addr, sizeof(kprobe_opcode_t));
1306457a396SManeesh Soni 
131c1bf207dSDavid Daney 	p->ainsn.insn[1] = breakpoint2_insn;
132c1bf207dSDavid Daney 	p->opcode = *p->addr;
133c1bf207dSDavid Daney 
134c1bf207dSDavid Daney out:
135c1bf207dSDavid Daney 	return ret;
136c1bf207dSDavid Daney }
137*f5e2d818STiezhu Yang NOKPROBE_SYMBOL(arch_prepare_kprobe);
138c1bf207dSDavid Daney 
arch_arm_kprobe(struct kprobe * p)139*f5e2d818STiezhu Yang void arch_arm_kprobe(struct kprobe *p)
140c1bf207dSDavid Daney {
141c1bf207dSDavid Daney 	*p->addr = breakpoint_insn;
142c1bf207dSDavid Daney 	flush_insn_slot(p);
143c1bf207dSDavid Daney }
144*f5e2d818STiezhu Yang NOKPROBE_SYMBOL(arch_arm_kprobe);
145c1bf207dSDavid Daney 
arch_disarm_kprobe(struct kprobe * p)146*f5e2d818STiezhu Yang void arch_disarm_kprobe(struct kprobe *p)
147c1bf207dSDavid Daney {
148c1bf207dSDavid Daney 	*p->addr = p->opcode;
149c1bf207dSDavid Daney 	flush_insn_slot(p);
150c1bf207dSDavid Daney }
151*f5e2d818STiezhu Yang NOKPROBE_SYMBOL(arch_disarm_kprobe);
152c1bf207dSDavid Daney 
arch_remove_kprobe(struct kprobe * p)153*f5e2d818STiezhu Yang void arch_remove_kprobe(struct kprobe *p)
154c1bf207dSDavid Daney {
15522047b85SMasami Hiramatsu 	if (p->ainsn.insn) {
156c1bf207dSDavid Daney 		free_insn_slot(p->ainsn.insn, 0);
15722047b85SMasami Hiramatsu 		p->ainsn.insn = NULL;
15822047b85SMasami Hiramatsu 	}
159c1bf207dSDavid Daney }
160*f5e2d818STiezhu Yang NOKPROBE_SYMBOL(arch_remove_kprobe);
161c1bf207dSDavid Daney 
save_previous_kprobe(struct kprobe_ctlblk * kcb)162c1bf207dSDavid Daney static void save_previous_kprobe(struct kprobe_ctlblk *kcb)
163c1bf207dSDavid Daney {
164c1bf207dSDavid Daney 	kcb->prev_kprobe.kp = kprobe_running();
165c1bf207dSDavid Daney 	kcb->prev_kprobe.status = kcb->kprobe_status;
166c1bf207dSDavid Daney 	kcb->prev_kprobe.old_SR = kcb->kprobe_old_SR;
167c1bf207dSDavid Daney 	kcb->prev_kprobe.saved_SR = kcb->kprobe_saved_SR;
168c1bf207dSDavid Daney 	kcb->prev_kprobe.saved_epc = kcb->kprobe_saved_epc;
169c1bf207dSDavid Daney }
170c1bf207dSDavid Daney 
restore_previous_kprobe(struct kprobe_ctlblk * kcb)171c1bf207dSDavid Daney static void restore_previous_kprobe(struct kprobe_ctlblk *kcb)
172c1bf207dSDavid Daney {
17335898716SChristoph Lameter 	__this_cpu_write(current_kprobe, kcb->prev_kprobe.kp);
174c1bf207dSDavid Daney 	kcb->kprobe_status = kcb->prev_kprobe.status;
175c1bf207dSDavid Daney 	kcb->kprobe_old_SR = kcb->prev_kprobe.old_SR;
176c1bf207dSDavid Daney 	kcb->kprobe_saved_SR = kcb->prev_kprobe.saved_SR;
177c1bf207dSDavid Daney 	kcb->kprobe_saved_epc = kcb->prev_kprobe.saved_epc;
178c1bf207dSDavid Daney }
179c1bf207dSDavid Daney 
set_current_kprobe(struct kprobe * p,struct pt_regs * regs,struct kprobe_ctlblk * kcb)180c1bf207dSDavid Daney static void set_current_kprobe(struct kprobe *p, struct pt_regs *regs,
181c1bf207dSDavid Daney 			       struct kprobe_ctlblk *kcb)
182c1bf207dSDavid Daney {
18335898716SChristoph Lameter 	__this_cpu_write(current_kprobe, p);
184c1bf207dSDavid Daney 	kcb->kprobe_saved_SR = kcb->kprobe_old_SR = (regs->cp0_status & ST0_IE);
185c1bf207dSDavid Daney 	kcb->kprobe_saved_epc = regs->cp0_epc;
186c1bf207dSDavid Daney }
187c1bf207dSDavid Daney 
1886457a396SManeesh Soni /**
1896457a396SManeesh Soni  * evaluate_branch_instrucion -
1906457a396SManeesh Soni  *
1916457a396SManeesh Soni  * Evaluate the branch instruction at probed address during probe hit. The
1926457a396SManeesh Soni  * result of evaluation would be the updated epc. The insturction in delayslot
1936457a396SManeesh Soni  * would actually be single stepped using a normal breakpoint) on SSOL slot.
1946457a396SManeesh Soni  *
1956457a396SManeesh Soni  * The result is also saved in the kprobe control block for later use,
1966457a396SManeesh Soni  * in case we need to execute the delayslot instruction. The latter will be
1976457a396SManeesh Soni  * false for NOP instruction in dealyslot and the branch-likely instructions
1986457a396SManeesh Soni  * when the branch is taken. And for those cases we set a flag as
1996457a396SManeesh Soni  * SKIP_DELAYSLOT in the kprobe control block
2006457a396SManeesh Soni  */
evaluate_branch_instruction(struct kprobe * p,struct pt_regs * regs,struct kprobe_ctlblk * kcb)2016457a396SManeesh Soni static int evaluate_branch_instruction(struct kprobe *p, struct pt_regs *regs,
2026457a396SManeesh Soni 					struct kprobe_ctlblk *kcb)
203c1bf207dSDavid Daney {
2046457a396SManeesh Soni 	union mips_instruction insn = p->opcode;
2056457a396SManeesh Soni 	long epc;
2066457a396SManeesh Soni 	int ret = 0;
2076457a396SManeesh Soni 
2086457a396SManeesh Soni 	epc = regs->cp0_epc;
2096457a396SManeesh Soni 	if (epc & 3)
2106457a396SManeesh Soni 		goto unaligned;
2116457a396SManeesh Soni 
2126457a396SManeesh Soni 	if (p->ainsn.insn->word == 0)
2136457a396SManeesh Soni 		kcb->flags |= SKIP_DELAYSLOT;
2146457a396SManeesh Soni 	else
2156457a396SManeesh Soni 		kcb->flags &= ~SKIP_DELAYSLOT;
2166457a396SManeesh Soni 
2176457a396SManeesh Soni 	ret = __compute_return_epc_for_insn(regs, insn);
2186457a396SManeesh Soni 	if (ret < 0)
2196457a396SManeesh Soni 		return ret;
2206457a396SManeesh Soni 
2216457a396SManeesh Soni 	if (ret == BRANCH_LIKELY_TAKEN)
2226457a396SManeesh Soni 		kcb->flags |= SKIP_DELAYSLOT;
2236457a396SManeesh Soni 
2246457a396SManeesh Soni 	kcb->target_epc = regs->cp0_epc;
2256457a396SManeesh Soni 
2266457a396SManeesh Soni 	return 0;
2276457a396SManeesh Soni 
2286457a396SManeesh Soni unaligned:
2299c89bb8eSMasami Hiramatsu 	pr_notice("Failed to emulate branch instruction because of unaligned epc - sending SIGBUS to %s.\n", current->comm);
2303cf5d076SEric W. Biederman 	force_sig(SIGBUS);
2316457a396SManeesh Soni 	return -EFAULT;
2326457a396SManeesh Soni 
2336457a396SManeesh Soni }
2346457a396SManeesh Soni 
prepare_singlestep(struct kprobe * p,struct pt_regs * regs,struct kprobe_ctlblk * kcb)2356457a396SManeesh Soni static void prepare_singlestep(struct kprobe *p, struct pt_regs *regs,
2366457a396SManeesh Soni 						struct kprobe_ctlblk *kcb)
2376457a396SManeesh Soni {
2386457a396SManeesh Soni 	int ret = 0;
2396457a396SManeesh Soni 
240c1bf207dSDavid Daney 	regs->cp0_status &= ~ST0_IE;
241c1bf207dSDavid Daney 
242c1bf207dSDavid Daney 	/* single step inline if the instruction is a break */
243c1bf207dSDavid Daney 	if (p->opcode.word == breakpoint_insn.word ||
244c1bf207dSDavid Daney 	    p->opcode.word == breakpoint2_insn.word)
245c1bf207dSDavid Daney 		regs->cp0_epc = (unsigned long)p->addr;
2466457a396SManeesh Soni 	else if (insn_has_delayslot(p->opcode)) {
2476457a396SManeesh Soni 		ret = evaluate_branch_instruction(p, regs, kcb);
2489c89bb8eSMasami Hiramatsu 		if (ret < 0)
2496457a396SManeesh Soni 			return;
2506457a396SManeesh Soni 	}
251c1bf207dSDavid Daney 	regs->cp0_epc = (unsigned long)&p->ainsn.insn[0];
252c1bf207dSDavid Daney }
253c1bf207dSDavid Daney 
2546457a396SManeesh Soni /*
2556457a396SManeesh Soni  * Called after single-stepping.  p->addr is the address of the
2566457a396SManeesh Soni  * instruction whose first byte has been replaced by the "break 0"
2576457a396SManeesh Soni  * instruction.	 To avoid the SMP problems that can occur when we
2586457a396SManeesh Soni  * temporarily put back the original opcode to single-step, we
2596457a396SManeesh Soni  * single-stepped a copy of the instruction.  The address of this
2606457a396SManeesh Soni  * copy is p->ainsn.insn.
2616457a396SManeesh Soni  *
2626457a396SManeesh Soni  * This function prepares to return from the post-single-step
2636457a396SManeesh Soni  * breakpoint trap. In case of branch instructions, the target
2646457a396SManeesh Soni  * epc to be restored.
2656457a396SManeesh Soni  */
resume_execution(struct kprobe * p,struct pt_regs * regs,struct kprobe_ctlblk * kcb)266*f5e2d818STiezhu Yang static void resume_execution(struct kprobe *p,
2676457a396SManeesh Soni 				       struct pt_regs *regs,
2686457a396SManeesh Soni 				       struct kprobe_ctlblk *kcb)
2696457a396SManeesh Soni {
2706457a396SManeesh Soni 	if (insn_has_delayslot(p->opcode))
2716457a396SManeesh Soni 		regs->cp0_epc = kcb->target_epc;
2726457a396SManeesh Soni 	else {
2736457a396SManeesh Soni 		unsigned long orig_epc = kcb->kprobe_saved_epc;
2746457a396SManeesh Soni 		regs->cp0_epc = orig_epc + 4;
2756457a396SManeesh Soni 	}
2766457a396SManeesh Soni }
277*f5e2d818STiezhu Yang NOKPROBE_SYMBOL(resume_execution);
2786457a396SManeesh Soni 
kprobe_handler(struct pt_regs * regs)279*f5e2d818STiezhu Yang static int kprobe_handler(struct pt_regs *regs)
280c1bf207dSDavid Daney {
281c1bf207dSDavid Daney 	struct kprobe *p;
282c1bf207dSDavid Daney 	int ret = 0;
283c1bf207dSDavid Daney 	kprobe_opcode_t *addr;
284c1bf207dSDavid Daney 	struct kprobe_ctlblk *kcb;
285c1bf207dSDavid Daney 
286c1bf207dSDavid Daney 	addr = (kprobe_opcode_t *) regs->cp0_epc;
287c1bf207dSDavid Daney 
288c1bf207dSDavid Daney 	/*
289c1bf207dSDavid Daney 	 * We don't want to be preempted for the entire
290c1bf207dSDavid Daney 	 * duration of kprobe processing
291c1bf207dSDavid Daney 	 */
292c1bf207dSDavid Daney 	preempt_disable();
293c1bf207dSDavid Daney 	kcb = get_kprobe_ctlblk();
294c1bf207dSDavid Daney 
295c1bf207dSDavid Daney 	/* Check we're not actually recursing */
296c1bf207dSDavid Daney 	if (kprobe_running()) {
297c1bf207dSDavid Daney 		p = get_kprobe(addr);
298c1bf207dSDavid Daney 		if (p) {
299c1bf207dSDavid Daney 			if (kcb->kprobe_status == KPROBE_HIT_SS &&
300c1bf207dSDavid Daney 			    p->ainsn.insn->word == breakpoint_insn.word) {
301c1bf207dSDavid Daney 				regs->cp0_status &= ~ST0_IE;
302c1bf207dSDavid Daney 				regs->cp0_status |= kcb->kprobe_saved_SR;
303c1bf207dSDavid Daney 				goto no_kprobe;
304c1bf207dSDavid Daney 			}
305c1bf207dSDavid Daney 			/*
306c1bf207dSDavid Daney 			 * We have reentered the kprobe_handler(), since
307c1bf207dSDavid Daney 			 * another probe was hit while within the handler.
308c1bf207dSDavid Daney 			 * We here save the original kprobes variables and
309c1bf207dSDavid Daney 			 * just single step on the instruction of the new probe
310c1bf207dSDavid Daney 			 * without calling any user handlers.
311c1bf207dSDavid Daney 			 */
312c1bf207dSDavid Daney 			save_previous_kprobe(kcb);
313c1bf207dSDavid Daney 			set_current_kprobe(p, regs, kcb);
314c1bf207dSDavid Daney 			kprobes_inc_nmissed_count(p);
3156457a396SManeesh Soni 			prepare_singlestep(p, regs, kcb);
316c1bf207dSDavid Daney 			kcb->kprobe_status = KPROBE_REENTER;
3176457a396SManeesh Soni 			if (kcb->flags & SKIP_DELAYSLOT) {
3186457a396SManeesh Soni 				resume_execution(p, regs, kcb);
3196457a396SManeesh Soni 				restore_previous_kprobe(kcb);
3206457a396SManeesh Soni 				preempt_enable_no_resched();
3216457a396SManeesh Soni 			}
322c1bf207dSDavid Daney 			return 1;
3239b85753dSMasami Hiramatsu 		} else if (addr->word != breakpoint_insn.word) {
324c1bf207dSDavid Daney 			/*
325c1bf207dSDavid Daney 			 * The breakpoint instruction was removed by
326c1bf207dSDavid Daney 			 * another cpu right after we hit, no further
327c1bf207dSDavid Daney 			 * handling of this interrupt is appropriate
328c1bf207dSDavid Daney 			 */
329c1bf207dSDavid Daney 			ret = 1;
330c1bf207dSDavid Daney 		}
331c1bf207dSDavid Daney 		goto no_kprobe;
332c1bf207dSDavid Daney 	}
333c1bf207dSDavid Daney 
334c1bf207dSDavid Daney 	p = get_kprobe(addr);
335c1bf207dSDavid Daney 	if (!p) {
336c1bf207dSDavid Daney 		if (addr->word != breakpoint_insn.word) {
337c1bf207dSDavid Daney 			/*
338c1bf207dSDavid Daney 			 * The breakpoint instruction was removed right
339c1bf207dSDavid Daney 			 * after we hit it.  Another cpu has removed
340c1bf207dSDavid Daney 			 * either a probepoint or a debugger breakpoint
341c1bf207dSDavid Daney 			 * at this address.  In either case, no further
342c1bf207dSDavid Daney 			 * handling of this interrupt is appropriate.
343c1bf207dSDavid Daney 			 */
344c1bf207dSDavid Daney 			ret = 1;
345c1bf207dSDavid Daney 		}
346c1bf207dSDavid Daney 		/* Not one of ours: let kernel handle it */
347c1bf207dSDavid Daney 		goto no_kprobe;
348c1bf207dSDavid Daney 	}
349c1bf207dSDavid Daney 
350c1bf207dSDavid Daney 	set_current_kprobe(p, regs, kcb);
351c1bf207dSDavid Daney 	kcb->kprobe_status = KPROBE_HIT_ACTIVE;
352c1bf207dSDavid Daney 
353c1bf207dSDavid Daney 	if (p->pre_handler && p->pre_handler(p, regs)) {
354c1bf207dSDavid Daney 		/* handler has already set things up, so skip ss setup */
355cce188bdSMasami Hiramatsu 		reset_current_kprobe();
356cce188bdSMasami Hiramatsu 		preempt_enable_no_resched();
357c1bf207dSDavid Daney 		return 1;
358c1bf207dSDavid Daney 	}
359c1bf207dSDavid Daney 
3606457a396SManeesh Soni 	prepare_singlestep(p, regs, kcb);
3616457a396SManeesh Soni 	if (kcb->flags & SKIP_DELAYSLOT) {
3626457a396SManeesh Soni 		kcb->kprobe_status = KPROBE_HIT_SSDONE;
3636457a396SManeesh Soni 		if (p->post_handler)
3646457a396SManeesh Soni 			p->post_handler(p, regs, 0);
3656457a396SManeesh Soni 		resume_execution(p, regs, kcb);
3666457a396SManeesh Soni 		preempt_enable_no_resched();
3676457a396SManeesh Soni 	} else
368c1bf207dSDavid Daney 		kcb->kprobe_status = KPROBE_HIT_SS;
3696457a396SManeesh Soni 
370c1bf207dSDavid Daney 	return 1;
371c1bf207dSDavid Daney 
372c1bf207dSDavid Daney no_kprobe:
373c1bf207dSDavid Daney 	preempt_enable_no_resched();
374c1bf207dSDavid Daney 	return ret;
375c1bf207dSDavid Daney 
376c1bf207dSDavid Daney }
377*f5e2d818STiezhu Yang NOKPROBE_SYMBOL(kprobe_handler);
378c1bf207dSDavid Daney 
post_kprobe_handler(struct pt_regs * regs)379c1bf207dSDavid Daney static inline int post_kprobe_handler(struct pt_regs *regs)
380c1bf207dSDavid Daney {
381c1bf207dSDavid Daney 	struct kprobe *cur = kprobe_running();
382c1bf207dSDavid Daney 	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
383c1bf207dSDavid Daney 
384c1bf207dSDavid Daney 	if (!cur)
385c1bf207dSDavid Daney 		return 0;
386c1bf207dSDavid Daney 
387c1bf207dSDavid Daney 	if ((kcb->kprobe_status != KPROBE_REENTER) && cur->post_handler) {
388c1bf207dSDavid Daney 		kcb->kprobe_status = KPROBE_HIT_SSDONE;
389c1bf207dSDavid Daney 		cur->post_handler(cur, regs, 0);
390c1bf207dSDavid Daney 	}
391c1bf207dSDavid Daney 
392c1bf207dSDavid Daney 	resume_execution(cur, regs, kcb);
393c1bf207dSDavid Daney 
394c1bf207dSDavid Daney 	regs->cp0_status |= kcb->kprobe_saved_SR;
395c1bf207dSDavid Daney 
396c1bf207dSDavid Daney 	/* Restore back the original saved kprobes variables and continue. */
397c1bf207dSDavid Daney 	if (kcb->kprobe_status == KPROBE_REENTER) {
398c1bf207dSDavid Daney 		restore_previous_kprobe(kcb);
399c1bf207dSDavid Daney 		goto out;
400c1bf207dSDavid Daney 	}
401c1bf207dSDavid Daney 	reset_current_kprobe();
402c1bf207dSDavid Daney out:
403c1bf207dSDavid Daney 	preempt_enable_no_resched();
404c1bf207dSDavid Daney 
405c1bf207dSDavid Daney 	return 1;
406c1bf207dSDavid Daney }
407c1bf207dSDavid Daney 
kprobe_fault_handler(struct pt_regs * regs,int trapnr)408b98cca44SAnshuman Khandual int kprobe_fault_handler(struct pt_regs *regs, int trapnr)
409c1bf207dSDavid Daney {
410c1bf207dSDavid Daney 	struct kprobe *cur = kprobe_running();
411c1bf207dSDavid Daney 	struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
412c1bf207dSDavid Daney 
413c1bf207dSDavid Daney 	if (kcb->kprobe_status & KPROBE_HIT_SS) {
414c1bf207dSDavid Daney 		resume_execution(cur, regs, kcb);
415c1bf207dSDavid Daney 		regs->cp0_status |= kcb->kprobe_old_SR;
416c1bf207dSDavid Daney 
417c1bf207dSDavid Daney 		reset_current_kprobe();
418c1bf207dSDavid Daney 		preempt_enable_no_resched();
419c1bf207dSDavid Daney 	}
420c1bf207dSDavid Daney 	return 0;
421c1bf207dSDavid Daney }
422c1bf207dSDavid Daney 
423c1bf207dSDavid Daney /*
424c1bf207dSDavid Daney  * Wrapper routine for handling exceptions.
425c1bf207dSDavid Daney  */
kprobe_exceptions_notify(struct notifier_block * self,unsigned long val,void * data)426*f5e2d818STiezhu Yang int kprobe_exceptions_notify(struct notifier_block *self,
427c1bf207dSDavid Daney 				       unsigned long val, void *data)
428c1bf207dSDavid Daney {
429c1bf207dSDavid Daney 
430c1bf207dSDavid Daney 	struct die_args *args = (struct die_args *)data;
431c1bf207dSDavid Daney 	int ret = NOTIFY_DONE;
432c1bf207dSDavid Daney 
433c1bf207dSDavid Daney 	switch (val) {
434c1bf207dSDavid Daney 	case DIE_BREAK:
435c1bf207dSDavid Daney 		if (kprobe_handler(args->regs))
436c1bf207dSDavid Daney 			ret = NOTIFY_STOP;
437c1bf207dSDavid Daney 		break;
438c1bf207dSDavid Daney 	case DIE_SSTEPBP:
439c1bf207dSDavid Daney 		if (post_kprobe_handler(args->regs))
440c1bf207dSDavid Daney 			ret = NOTIFY_STOP;
441c1bf207dSDavid Daney 		break;
442c1bf207dSDavid Daney 
443c1bf207dSDavid Daney 	case DIE_PAGE_FAULT:
444c1bf207dSDavid Daney 		/* kprobe_running() needs smp_processor_id() */
445c1bf207dSDavid Daney 		preempt_disable();
446c1bf207dSDavid Daney 
447c1bf207dSDavid Daney 		if (kprobe_running()
448c1bf207dSDavid Daney 		    && kprobe_fault_handler(args->regs, args->trapnr))
449c1bf207dSDavid Daney 			ret = NOTIFY_STOP;
450c1bf207dSDavid Daney 		preempt_enable();
451c1bf207dSDavid Daney 		break;
452c1bf207dSDavid Daney 	default:
453c1bf207dSDavid Daney 		break;
454c1bf207dSDavid Daney 	}
455c1bf207dSDavid Daney 	return ret;
456c1bf207dSDavid Daney }
457*f5e2d818STiezhu Yang NOKPROBE_SYMBOL(kprobe_exceptions_notify);
458c1bf207dSDavid Daney 
459c1bf207dSDavid Daney /*
460c1bf207dSDavid Daney  * Function return probe trampoline:
461c1bf207dSDavid Daney  *	- init_kprobes() establishes a probepoint here
462c1bf207dSDavid Daney  *	- When the probed function returns, this probe causes the
463c1bf207dSDavid Daney  *	  handlers to fire
464c1bf207dSDavid Daney  */
kretprobe_trampoline_holder(void)465c1bf207dSDavid Daney static void __used kretprobe_trampoline_holder(void)
466c1bf207dSDavid Daney {
467c1bf207dSDavid Daney 	asm volatile(
468c1bf207dSDavid Daney 		".set push\n\t"
469c1bf207dSDavid Daney 		/* Keep the assembler from reordering and placing JR here. */
470c1bf207dSDavid Daney 		".set noreorder\n\t"
471c1bf207dSDavid Daney 		"nop\n\t"
472adf8a61aSMasami Hiramatsu 		".global __kretprobe_trampoline\n"
473adf8a61aSMasami Hiramatsu 		"__kretprobe_trampoline:\n\t"
474c1bf207dSDavid Daney 		"nop\n\t"
475c1bf207dSDavid Daney 		".set pop"
476c1bf207dSDavid Daney 		: : : "memory");
477c1bf207dSDavid Daney }
478c1bf207dSDavid Daney 
479adf8a61aSMasami Hiramatsu void __kretprobe_trampoline(void);
480c1bf207dSDavid Daney 
arch_prepare_kretprobe(struct kretprobe_instance * ri,struct pt_regs * regs)481*f5e2d818STiezhu Yang void arch_prepare_kretprobe(struct kretprobe_instance *ri,
482c1bf207dSDavid Daney 				      struct pt_regs *regs)
483c1bf207dSDavid Daney {
484c1bf207dSDavid Daney 	ri->ret_addr = (kprobe_opcode_t *) regs->regs[31];
4852ef12450SMasami Hiramatsu 	ri->fp = NULL;
486c1bf207dSDavid Daney 
487c1bf207dSDavid Daney 	/* Replace the return addr with trampoline addr */
488adf8a61aSMasami Hiramatsu 	regs->regs[31] = (unsigned long)__kretprobe_trampoline;
489c1bf207dSDavid Daney }
490*f5e2d818STiezhu Yang NOKPROBE_SYMBOL(arch_prepare_kretprobe);
491c1bf207dSDavid Daney 
492c1bf207dSDavid Daney /*
493c1bf207dSDavid Daney  * Called when the probe at kretprobe trampoline is hit
494c1bf207dSDavid Daney  */
trampoline_probe_handler(struct kprobe * p,struct pt_regs * regs)495*f5e2d818STiezhu Yang static int trampoline_probe_handler(struct kprobe *p,
496c1bf207dSDavid Daney 						struct pt_regs *regs)
497c1bf207dSDavid Daney {
49896fed8acSMasami Hiramatsu 	instruction_pointer(regs) = __kretprobe_trampoline_handler(regs, NULL);
499c1bf207dSDavid Daney 	/*
500c1bf207dSDavid Daney 	 * By returning a non-zero value, we are telling
501c1bf207dSDavid Daney 	 * kprobe_handler() that we don't want the post_handler
502c1bf207dSDavid Daney 	 * to run (and have re-enabled preemption)
503c1bf207dSDavid Daney 	 */
504c1bf207dSDavid Daney 	return 1;
505c1bf207dSDavid Daney }
506*f5e2d818STiezhu Yang NOKPROBE_SYMBOL(trampoline_probe_handler);
507c1bf207dSDavid Daney 
arch_trampoline_kprobe(struct kprobe * p)508*f5e2d818STiezhu Yang int arch_trampoline_kprobe(struct kprobe *p)
509c1bf207dSDavid Daney {
510adf8a61aSMasami Hiramatsu 	if (p->addr == (kprobe_opcode_t *)__kretprobe_trampoline)
511c1bf207dSDavid Daney 		return 1;
512c1bf207dSDavid Daney 
513c1bf207dSDavid Daney 	return 0;
514c1bf207dSDavid Daney }
515*f5e2d818STiezhu Yang NOKPROBE_SYMBOL(arch_trampoline_kprobe);
516c1bf207dSDavid Daney 
517c1bf207dSDavid Daney static struct kprobe trampoline_p = {
518adf8a61aSMasami Hiramatsu 	.addr = (kprobe_opcode_t *)__kretprobe_trampoline,
519c1bf207dSDavid Daney 	.pre_handler = trampoline_probe_handler
520c1bf207dSDavid Daney };
521c1bf207dSDavid Daney 
arch_init_kprobes(void)522c1bf207dSDavid Daney int __init arch_init_kprobes(void)
523c1bf207dSDavid Daney {
524c1bf207dSDavid Daney 	return register_kprobe(&trampoline_p);
525c1bf207dSDavid Daney }
526