162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Kernel Probes (KProbes) 462306a36Sopenharmony_ci * arch/mips/kernel/kprobes.c 562306a36Sopenharmony_ci * 662306a36Sopenharmony_ci * Copyright 2006 Sony Corp. 762306a36Sopenharmony_ci * Copyright 2010 Cavium Networks 862306a36Sopenharmony_ci * 962306a36Sopenharmony_ci * Some portions copied from the powerpc version. 1062306a36Sopenharmony_ci * 1162306a36Sopenharmony_ci * Copyright (C) IBM Corporation, 2002, 2004 1262306a36Sopenharmony_ci */ 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#define pr_fmt(fmt) "kprobes: " fmt 1562306a36Sopenharmony_ci 1662306a36Sopenharmony_ci#include <linux/kprobes.h> 1762306a36Sopenharmony_ci#include <linux/preempt.h> 1862306a36Sopenharmony_ci#include <linux/uaccess.h> 1962306a36Sopenharmony_ci#include <linux/kdebug.h> 2062306a36Sopenharmony_ci#include <linux/slab.h> 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci#include <asm/ptrace.h> 2362306a36Sopenharmony_ci#include <asm/branch.h> 2462306a36Sopenharmony_ci#include <asm/break.h> 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci#include "probes-common.h" 2762306a36Sopenharmony_ci 2862306a36Sopenharmony_cistatic const union mips_instruction breakpoint_insn = { 2962306a36Sopenharmony_ci .b_format = { 3062306a36Sopenharmony_ci .opcode = spec_op, 3162306a36Sopenharmony_ci .code = BRK_KPROBE_BP, 3262306a36Sopenharmony_ci .func = break_op 3362306a36Sopenharmony_ci } 3462306a36Sopenharmony_ci}; 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_cistatic const union mips_instruction breakpoint2_insn = { 3762306a36Sopenharmony_ci .b_format = { 3862306a36Sopenharmony_ci .opcode = spec_op, 3962306a36Sopenharmony_ci .code = BRK_KPROBE_SSTEPBP, 4062306a36Sopenharmony_ci .func = break_op 4162306a36Sopenharmony_ci } 4262306a36Sopenharmony_ci}; 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ciDEFINE_PER_CPU(struct kprobe *, current_kprobe); 4562306a36Sopenharmony_ciDEFINE_PER_CPU(struct kprobe_ctlblk, kprobe_ctlblk); 4662306a36Sopenharmony_ci 4762306a36Sopenharmony_cistatic int insn_has_delayslot(union mips_instruction insn) 4862306a36Sopenharmony_ci{ 4962306a36Sopenharmony_ci return __insn_has_delay_slot(insn); 5062306a36Sopenharmony_ci} 5162306a36Sopenharmony_ciNOKPROBE_SYMBOL(insn_has_delayslot); 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_ci/* 5462306a36Sopenharmony_ci * insn_has_ll_or_sc function checks whether instruction is ll or sc 5562306a36Sopenharmony_ci * one; putting breakpoint on top of atomic ll/sc pair is bad idea; 5662306a36Sopenharmony_ci * so we need to prevent it and refuse kprobes insertion for such 5762306a36Sopenharmony_ci * instructions; cannot do much about breakpoint in the middle of 5862306a36Sopenharmony_ci * ll/sc pair; it is upto user to avoid those places 5962306a36Sopenharmony_ci */ 6062306a36Sopenharmony_cistatic int insn_has_ll_or_sc(union mips_instruction insn) 6162306a36Sopenharmony_ci{ 6262306a36Sopenharmony_ci int ret = 0; 6362306a36Sopenharmony_ci 6462306a36Sopenharmony_ci switch (insn.i_format.opcode) { 6562306a36Sopenharmony_ci case ll_op: 6662306a36Sopenharmony_ci case lld_op: 6762306a36Sopenharmony_ci case sc_op: 6862306a36Sopenharmony_ci case scd_op: 6962306a36Sopenharmony_ci ret = 1; 7062306a36Sopenharmony_ci break; 7162306a36Sopenharmony_ci default: 7262306a36Sopenharmony_ci break; 7362306a36Sopenharmony_ci } 7462306a36Sopenharmony_ci return ret; 7562306a36Sopenharmony_ci} 7662306a36Sopenharmony_ciNOKPROBE_SYMBOL(insn_has_ll_or_sc); 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_ciint arch_prepare_kprobe(struct kprobe *p) 7962306a36Sopenharmony_ci{ 8062306a36Sopenharmony_ci union mips_instruction insn; 8162306a36Sopenharmony_ci union mips_instruction prev_insn; 8262306a36Sopenharmony_ci int ret = 0; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci insn = p->addr[0]; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci if (insn_has_ll_or_sc(insn)) { 8762306a36Sopenharmony_ci pr_notice("Kprobes for ll and sc instructions are not supported\n"); 8862306a36Sopenharmony_ci ret = -EINVAL; 8962306a36Sopenharmony_ci goto out; 9062306a36Sopenharmony_ci } 9162306a36Sopenharmony_ci 9262306a36Sopenharmony_ci if (copy_from_kernel_nofault(&prev_insn, p->addr - 1, 9362306a36Sopenharmony_ci sizeof(mips_instruction)) == 0 && 9462306a36Sopenharmony_ci insn_has_delayslot(prev_insn)) { 9562306a36Sopenharmony_ci pr_notice("Kprobes for branch delayslot are not supported\n"); 9662306a36Sopenharmony_ci ret = -EINVAL; 9762306a36Sopenharmony_ci goto out; 9862306a36Sopenharmony_ci } 9962306a36Sopenharmony_ci 10062306a36Sopenharmony_ci if (__insn_is_compact_branch(insn)) { 10162306a36Sopenharmony_ci pr_notice("Kprobes for compact branches are not supported\n"); 10262306a36Sopenharmony_ci ret = -EINVAL; 10362306a36Sopenharmony_ci goto out; 10462306a36Sopenharmony_ci } 10562306a36Sopenharmony_ci 10662306a36Sopenharmony_ci /* insn: must be on special executable page on mips. */ 10762306a36Sopenharmony_ci p->ainsn.insn = get_insn_slot(); 10862306a36Sopenharmony_ci if (!p->ainsn.insn) { 10962306a36Sopenharmony_ci ret = -ENOMEM; 11062306a36Sopenharmony_ci goto out; 11162306a36Sopenharmony_ci } 11262306a36Sopenharmony_ci 11362306a36Sopenharmony_ci /* 11462306a36Sopenharmony_ci * In the kprobe->ainsn.insn[] array we store the original 11562306a36Sopenharmony_ci * instruction at index zero and a break trap instruction at 11662306a36Sopenharmony_ci * index one. 11762306a36Sopenharmony_ci * 11862306a36Sopenharmony_ci * On MIPS arch if the instruction at probed address is a 11962306a36Sopenharmony_ci * branch instruction, we need to execute the instruction at 12062306a36Sopenharmony_ci * Branch Delayslot (BD) at the time of probe hit. As MIPS also 12162306a36Sopenharmony_ci * doesn't have single stepping support, the BD instruction can 12262306a36Sopenharmony_ci * not be executed in-line and it would be executed on SSOL slot 12362306a36Sopenharmony_ci * using a normal breakpoint instruction in the next slot. 12462306a36Sopenharmony_ci * So, read the instruction and save it for later execution. 12562306a36Sopenharmony_ci */ 12662306a36Sopenharmony_ci if (insn_has_delayslot(insn)) 12762306a36Sopenharmony_ci memcpy(&p->ainsn.insn[0], p->addr + 1, sizeof(kprobe_opcode_t)); 12862306a36Sopenharmony_ci else 12962306a36Sopenharmony_ci memcpy(&p->ainsn.insn[0], p->addr, sizeof(kprobe_opcode_t)); 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci p->ainsn.insn[1] = breakpoint2_insn; 13262306a36Sopenharmony_ci p->opcode = *p->addr; 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ciout: 13562306a36Sopenharmony_ci return ret; 13662306a36Sopenharmony_ci} 13762306a36Sopenharmony_ciNOKPROBE_SYMBOL(arch_prepare_kprobe); 13862306a36Sopenharmony_ci 13962306a36Sopenharmony_civoid arch_arm_kprobe(struct kprobe *p) 14062306a36Sopenharmony_ci{ 14162306a36Sopenharmony_ci *p->addr = breakpoint_insn; 14262306a36Sopenharmony_ci flush_insn_slot(p); 14362306a36Sopenharmony_ci} 14462306a36Sopenharmony_ciNOKPROBE_SYMBOL(arch_arm_kprobe); 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_civoid arch_disarm_kprobe(struct kprobe *p) 14762306a36Sopenharmony_ci{ 14862306a36Sopenharmony_ci *p->addr = p->opcode; 14962306a36Sopenharmony_ci flush_insn_slot(p); 15062306a36Sopenharmony_ci} 15162306a36Sopenharmony_ciNOKPROBE_SYMBOL(arch_disarm_kprobe); 15262306a36Sopenharmony_ci 15362306a36Sopenharmony_civoid arch_remove_kprobe(struct kprobe *p) 15462306a36Sopenharmony_ci{ 15562306a36Sopenharmony_ci if (p->ainsn.insn) { 15662306a36Sopenharmony_ci free_insn_slot(p->ainsn.insn, 0); 15762306a36Sopenharmony_ci p->ainsn.insn = NULL; 15862306a36Sopenharmony_ci } 15962306a36Sopenharmony_ci} 16062306a36Sopenharmony_ciNOKPROBE_SYMBOL(arch_remove_kprobe); 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_cistatic void save_previous_kprobe(struct kprobe_ctlblk *kcb) 16362306a36Sopenharmony_ci{ 16462306a36Sopenharmony_ci kcb->prev_kprobe.kp = kprobe_running(); 16562306a36Sopenharmony_ci kcb->prev_kprobe.status = kcb->kprobe_status; 16662306a36Sopenharmony_ci kcb->prev_kprobe.old_SR = kcb->kprobe_old_SR; 16762306a36Sopenharmony_ci kcb->prev_kprobe.saved_SR = kcb->kprobe_saved_SR; 16862306a36Sopenharmony_ci kcb->prev_kprobe.saved_epc = kcb->kprobe_saved_epc; 16962306a36Sopenharmony_ci} 17062306a36Sopenharmony_ci 17162306a36Sopenharmony_cistatic void restore_previous_kprobe(struct kprobe_ctlblk *kcb) 17262306a36Sopenharmony_ci{ 17362306a36Sopenharmony_ci __this_cpu_write(current_kprobe, kcb->prev_kprobe.kp); 17462306a36Sopenharmony_ci kcb->kprobe_status = kcb->prev_kprobe.status; 17562306a36Sopenharmony_ci kcb->kprobe_old_SR = kcb->prev_kprobe.old_SR; 17662306a36Sopenharmony_ci kcb->kprobe_saved_SR = kcb->prev_kprobe.saved_SR; 17762306a36Sopenharmony_ci kcb->kprobe_saved_epc = kcb->prev_kprobe.saved_epc; 17862306a36Sopenharmony_ci} 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_cistatic void set_current_kprobe(struct kprobe *p, struct pt_regs *regs, 18162306a36Sopenharmony_ci struct kprobe_ctlblk *kcb) 18262306a36Sopenharmony_ci{ 18362306a36Sopenharmony_ci __this_cpu_write(current_kprobe, p); 18462306a36Sopenharmony_ci kcb->kprobe_saved_SR = kcb->kprobe_old_SR = (regs->cp0_status & ST0_IE); 18562306a36Sopenharmony_ci kcb->kprobe_saved_epc = regs->cp0_epc; 18662306a36Sopenharmony_ci} 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_ci/** 18962306a36Sopenharmony_ci * evaluate_branch_instrucion - 19062306a36Sopenharmony_ci * 19162306a36Sopenharmony_ci * Evaluate the branch instruction at probed address during probe hit. The 19262306a36Sopenharmony_ci * result of evaluation would be the updated epc. The insturction in delayslot 19362306a36Sopenharmony_ci * would actually be single stepped using a normal breakpoint) on SSOL slot. 19462306a36Sopenharmony_ci * 19562306a36Sopenharmony_ci * The result is also saved in the kprobe control block for later use, 19662306a36Sopenharmony_ci * in case we need to execute the delayslot instruction. The latter will be 19762306a36Sopenharmony_ci * false for NOP instruction in dealyslot and the branch-likely instructions 19862306a36Sopenharmony_ci * when the branch is taken. And for those cases we set a flag as 19962306a36Sopenharmony_ci * SKIP_DELAYSLOT in the kprobe control block 20062306a36Sopenharmony_ci */ 20162306a36Sopenharmony_cistatic int evaluate_branch_instruction(struct kprobe *p, struct pt_regs *regs, 20262306a36Sopenharmony_ci struct kprobe_ctlblk *kcb) 20362306a36Sopenharmony_ci{ 20462306a36Sopenharmony_ci union mips_instruction insn = p->opcode; 20562306a36Sopenharmony_ci long epc; 20662306a36Sopenharmony_ci int ret = 0; 20762306a36Sopenharmony_ci 20862306a36Sopenharmony_ci epc = regs->cp0_epc; 20962306a36Sopenharmony_ci if (epc & 3) 21062306a36Sopenharmony_ci goto unaligned; 21162306a36Sopenharmony_ci 21262306a36Sopenharmony_ci if (p->ainsn.insn->word == 0) 21362306a36Sopenharmony_ci kcb->flags |= SKIP_DELAYSLOT; 21462306a36Sopenharmony_ci else 21562306a36Sopenharmony_ci kcb->flags &= ~SKIP_DELAYSLOT; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci ret = __compute_return_epc_for_insn(regs, insn); 21862306a36Sopenharmony_ci if (ret < 0) 21962306a36Sopenharmony_ci return ret; 22062306a36Sopenharmony_ci 22162306a36Sopenharmony_ci if (ret == BRANCH_LIKELY_TAKEN) 22262306a36Sopenharmony_ci kcb->flags |= SKIP_DELAYSLOT; 22362306a36Sopenharmony_ci 22462306a36Sopenharmony_ci kcb->target_epc = regs->cp0_epc; 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_ci return 0; 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ciunaligned: 22962306a36Sopenharmony_ci pr_notice("Failed to emulate branch instruction because of unaligned epc - sending SIGBUS to %s.\n", current->comm); 23062306a36Sopenharmony_ci force_sig(SIGBUS); 23162306a36Sopenharmony_ci return -EFAULT; 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci} 23462306a36Sopenharmony_ci 23562306a36Sopenharmony_cistatic void prepare_singlestep(struct kprobe *p, struct pt_regs *regs, 23662306a36Sopenharmony_ci struct kprobe_ctlblk *kcb) 23762306a36Sopenharmony_ci{ 23862306a36Sopenharmony_ci int ret = 0; 23962306a36Sopenharmony_ci 24062306a36Sopenharmony_ci regs->cp0_status &= ~ST0_IE; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci /* single step inline if the instruction is a break */ 24362306a36Sopenharmony_ci if (p->opcode.word == breakpoint_insn.word || 24462306a36Sopenharmony_ci p->opcode.word == breakpoint2_insn.word) 24562306a36Sopenharmony_ci regs->cp0_epc = (unsigned long)p->addr; 24662306a36Sopenharmony_ci else if (insn_has_delayslot(p->opcode)) { 24762306a36Sopenharmony_ci ret = evaluate_branch_instruction(p, regs, kcb); 24862306a36Sopenharmony_ci if (ret < 0) 24962306a36Sopenharmony_ci return; 25062306a36Sopenharmony_ci } 25162306a36Sopenharmony_ci regs->cp0_epc = (unsigned long)&p->ainsn.insn[0]; 25262306a36Sopenharmony_ci} 25362306a36Sopenharmony_ci 25462306a36Sopenharmony_ci/* 25562306a36Sopenharmony_ci * Called after single-stepping. p->addr is the address of the 25662306a36Sopenharmony_ci * instruction whose first byte has been replaced by the "break 0" 25762306a36Sopenharmony_ci * instruction. To avoid the SMP problems that can occur when we 25862306a36Sopenharmony_ci * temporarily put back the original opcode to single-step, we 25962306a36Sopenharmony_ci * single-stepped a copy of the instruction. The address of this 26062306a36Sopenharmony_ci * copy is p->ainsn.insn. 26162306a36Sopenharmony_ci * 26262306a36Sopenharmony_ci * This function prepares to return from the post-single-step 26362306a36Sopenharmony_ci * breakpoint trap. In case of branch instructions, the target 26462306a36Sopenharmony_ci * epc to be restored. 26562306a36Sopenharmony_ci */ 26662306a36Sopenharmony_cistatic void resume_execution(struct kprobe *p, 26762306a36Sopenharmony_ci struct pt_regs *regs, 26862306a36Sopenharmony_ci struct kprobe_ctlblk *kcb) 26962306a36Sopenharmony_ci{ 27062306a36Sopenharmony_ci if (insn_has_delayslot(p->opcode)) 27162306a36Sopenharmony_ci regs->cp0_epc = kcb->target_epc; 27262306a36Sopenharmony_ci else { 27362306a36Sopenharmony_ci unsigned long orig_epc = kcb->kprobe_saved_epc; 27462306a36Sopenharmony_ci regs->cp0_epc = orig_epc + 4; 27562306a36Sopenharmony_ci } 27662306a36Sopenharmony_ci} 27762306a36Sopenharmony_ciNOKPROBE_SYMBOL(resume_execution); 27862306a36Sopenharmony_ci 27962306a36Sopenharmony_cistatic int kprobe_handler(struct pt_regs *regs) 28062306a36Sopenharmony_ci{ 28162306a36Sopenharmony_ci struct kprobe *p; 28262306a36Sopenharmony_ci int ret = 0; 28362306a36Sopenharmony_ci kprobe_opcode_t *addr; 28462306a36Sopenharmony_ci struct kprobe_ctlblk *kcb; 28562306a36Sopenharmony_ci 28662306a36Sopenharmony_ci addr = (kprobe_opcode_t *) regs->cp0_epc; 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci /* 28962306a36Sopenharmony_ci * We don't want to be preempted for the entire 29062306a36Sopenharmony_ci * duration of kprobe processing 29162306a36Sopenharmony_ci */ 29262306a36Sopenharmony_ci preempt_disable(); 29362306a36Sopenharmony_ci kcb = get_kprobe_ctlblk(); 29462306a36Sopenharmony_ci 29562306a36Sopenharmony_ci /* Check we're not actually recursing */ 29662306a36Sopenharmony_ci if (kprobe_running()) { 29762306a36Sopenharmony_ci p = get_kprobe(addr); 29862306a36Sopenharmony_ci if (p) { 29962306a36Sopenharmony_ci if (kcb->kprobe_status == KPROBE_HIT_SS && 30062306a36Sopenharmony_ci p->ainsn.insn->word == breakpoint_insn.word) { 30162306a36Sopenharmony_ci regs->cp0_status &= ~ST0_IE; 30262306a36Sopenharmony_ci regs->cp0_status |= kcb->kprobe_saved_SR; 30362306a36Sopenharmony_ci goto no_kprobe; 30462306a36Sopenharmony_ci } 30562306a36Sopenharmony_ci /* 30662306a36Sopenharmony_ci * We have reentered the kprobe_handler(), since 30762306a36Sopenharmony_ci * another probe was hit while within the handler. 30862306a36Sopenharmony_ci * We here save the original kprobes variables and 30962306a36Sopenharmony_ci * just single step on the instruction of the new probe 31062306a36Sopenharmony_ci * without calling any user handlers. 31162306a36Sopenharmony_ci */ 31262306a36Sopenharmony_ci save_previous_kprobe(kcb); 31362306a36Sopenharmony_ci set_current_kprobe(p, regs, kcb); 31462306a36Sopenharmony_ci kprobes_inc_nmissed_count(p); 31562306a36Sopenharmony_ci prepare_singlestep(p, regs, kcb); 31662306a36Sopenharmony_ci kcb->kprobe_status = KPROBE_REENTER; 31762306a36Sopenharmony_ci if (kcb->flags & SKIP_DELAYSLOT) { 31862306a36Sopenharmony_ci resume_execution(p, regs, kcb); 31962306a36Sopenharmony_ci restore_previous_kprobe(kcb); 32062306a36Sopenharmony_ci preempt_enable_no_resched(); 32162306a36Sopenharmony_ci } 32262306a36Sopenharmony_ci return 1; 32362306a36Sopenharmony_ci } else if (addr->word != breakpoint_insn.word) { 32462306a36Sopenharmony_ci /* 32562306a36Sopenharmony_ci * The breakpoint instruction was removed by 32662306a36Sopenharmony_ci * another cpu right after we hit, no further 32762306a36Sopenharmony_ci * handling of this interrupt is appropriate 32862306a36Sopenharmony_ci */ 32962306a36Sopenharmony_ci ret = 1; 33062306a36Sopenharmony_ci } 33162306a36Sopenharmony_ci goto no_kprobe; 33262306a36Sopenharmony_ci } 33362306a36Sopenharmony_ci 33462306a36Sopenharmony_ci p = get_kprobe(addr); 33562306a36Sopenharmony_ci if (!p) { 33662306a36Sopenharmony_ci if (addr->word != breakpoint_insn.word) { 33762306a36Sopenharmony_ci /* 33862306a36Sopenharmony_ci * The breakpoint instruction was removed right 33962306a36Sopenharmony_ci * after we hit it. Another cpu has removed 34062306a36Sopenharmony_ci * either a probepoint or a debugger breakpoint 34162306a36Sopenharmony_ci * at this address. In either case, no further 34262306a36Sopenharmony_ci * handling of this interrupt is appropriate. 34362306a36Sopenharmony_ci */ 34462306a36Sopenharmony_ci ret = 1; 34562306a36Sopenharmony_ci } 34662306a36Sopenharmony_ci /* Not one of ours: let kernel handle it */ 34762306a36Sopenharmony_ci goto no_kprobe; 34862306a36Sopenharmony_ci } 34962306a36Sopenharmony_ci 35062306a36Sopenharmony_ci set_current_kprobe(p, regs, kcb); 35162306a36Sopenharmony_ci kcb->kprobe_status = KPROBE_HIT_ACTIVE; 35262306a36Sopenharmony_ci 35362306a36Sopenharmony_ci if (p->pre_handler && p->pre_handler(p, regs)) { 35462306a36Sopenharmony_ci /* handler has already set things up, so skip ss setup */ 35562306a36Sopenharmony_ci reset_current_kprobe(); 35662306a36Sopenharmony_ci preempt_enable_no_resched(); 35762306a36Sopenharmony_ci return 1; 35862306a36Sopenharmony_ci } 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci prepare_singlestep(p, regs, kcb); 36162306a36Sopenharmony_ci if (kcb->flags & SKIP_DELAYSLOT) { 36262306a36Sopenharmony_ci kcb->kprobe_status = KPROBE_HIT_SSDONE; 36362306a36Sopenharmony_ci if (p->post_handler) 36462306a36Sopenharmony_ci p->post_handler(p, regs, 0); 36562306a36Sopenharmony_ci resume_execution(p, regs, kcb); 36662306a36Sopenharmony_ci preempt_enable_no_resched(); 36762306a36Sopenharmony_ci } else 36862306a36Sopenharmony_ci kcb->kprobe_status = KPROBE_HIT_SS; 36962306a36Sopenharmony_ci 37062306a36Sopenharmony_ci return 1; 37162306a36Sopenharmony_ci 37262306a36Sopenharmony_cino_kprobe: 37362306a36Sopenharmony_ci preempt_enable_no_resched(); 37462306a36Sopenharmony_ci return ret; 37562306a36Sopenharmony_ci 37662306a36Sopenharmony_ci} 37762306a36Sopenharmony_ciNOKPROBE_SYMBOL(kprobe_handler); 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_cistatic inline int post_kprobe_handler(struct pt_regs *regs) 38062306a36Sopenharmony_ci{ 38162306a36Sopenharmony_ci struct kprobe *cur = kprobe_running(); 38262306a36Sopenharmony_ci struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); 38362306a36Sopenharmony_ci 38462306a36Sopenharmony_ci if (!cur) 38562306a36Sopenharmony_ci return 0; 38662306a36Sopenharmony_ci 38762306a36Sopenharmony_ci if ((kcb->kprobe_status != KPROBE_REENTER) && cur->post_handler) { 38862306a36Sopenharmony_ci kcb->kprobe_status = KPROBE_HIT_SSDONE; 38962306a36Sopenharmony_ci cur->post_handler(cur, regs, 0); 39062306a36Sopenharmony_ci } 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci resume_execution(cur, regs, kcb); 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci regs->cp0_status |= kcb->kprobe_saved_SR; 39562306a36Sopenharmony_ci 39662306a36Sopenharmony_ci /* Restore back the original saved kprobes variables and continue. */ 39762306a36Sopenharmony_ci if (kcb->kprobe_status == KPROBE_REENTER) { 39862306a36Sopenharmony_ci restore_previous_kprobe(kcb); 39962306a36Sopenharmony_ci goto out; 40062306a36Sopenharmony_ci } 40162306a36Sopenharmony_ci reset_current_kprobe(); 40262306a36Sopenharmony_ciout: 40362306a36Sopenharmony_ci preempt_enable_no_resched(); 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci return 1; 40662306a36Sopenharmony_ci} 40762306a36Sopenharmony_ci 40862306a36Sopenharmony_ciint kprobe_fault_handler(struct pt_regs *regs, int trapnr) 40962306a36Sopenharmony_ci{ 41062306a36Sopenharmony_ci struct kprobe *cur = kprobe_running(); 41162306a36Sopenharmony_ci struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci if (kcb->kprobe_status & KPROBE_HIT_SS) { 41462306a36Sopenharmony_ci resume_execution(cur, regs, kcb); 41562306a36Sopenharmony_ci regs->cp0_status |= kcb->kprobe_old_SR; 41662306a36Sopenharmony_ci 41762306a36Sopenharmony_ci reset_current_kprobe(); 41862306a36Sopenharmony_ci preempt_enable_no_resched(); 41962306a36Sopenharmony_ci } 42062306a36Sopenharmony_ci return 0; 42162306a36Sopenharmony_ci} 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci/* 42462306a36Sopenharmony_ci * Wrapper routine for handling exceptions. 42562306a36Sopenharmony_ci */ 42662306a36Sopenharmony_ciint kprobe_exceptions_notify(struct notifier_block *self, 42762306a36Sopenharmony_ci unsigned long val, void *data) 42862306a36Sopenharmony_ci{ 42962306a36Sopenharmony_ci 43062306a36Sopenharmony_ci struct die_args *args = (struct die_args *)data; 43162306a36Sopenharmony_ci int ret = NOTIFY_DONE; 43262306a36Sopenharmony_ci 43362306a36Sopenharmony_ci switch (val) { 43462306a36Sopenharmony_ci case DIE_BREAK: 43562306a36Sopenharmony_ci if (kprobe_handler(args->regs)) 43662306a36Sopenharmony_ci ret = NOTIFY_STOP; 43762306a36Sopenharmony_ci break; 43862306a36Sopenharmony_ci case DIE_SSTEPBP: 43962306a36Sopenharmony_ci if (post_kprobe_handler(args->regs)) 44062306a36Sopenharmony_ci ret = NOTIFY_STOP; 44162306a36Sopenharmony_ci break; 44262306a36Sopenharmony_ci 44362306a36Sopenharmony_ci case DIE_PAGE_FAULT: 44462306a36Sopenharmony_ci /* kprobe_running() needs smp_processor_id() */ 44562306a36Sopenharmony_ci preempt_disable(); 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_ci if (kprobe_running() 44862306a36Sopenharmony_ci && kprobe_fault_handler(args->regs, args->trapnr)) 44962306a36Sopenharmony_ci ret = NOTIFY_STOP; 45062306a36Sopenharmony_ci preempt_enable(); 45162306a36Sopenharmony_ci break; 45262306a36Sopenharmony_ci default: 45362306a36Sopenharmony_ci break; 45462306a36Sopenharmony_ci } 45562306a36Sopenharmony_ci return ret; 45662306a36Sopenharmony_ci} 45762306a36Sopenharmony_ciNOKPROBE_SYMBOL(kprobe_exceptions_notify); 45862306a36Sopenharmony_ci 45962306a36Sopenharmony_ci/* 46062306a36Sopenharmony_ci * Function return probe trampoline: 46162306a36Sopenharmony_ci * - init_kprobes() establishes a probepoint here 46262306a36Sopenharmony_ci * - When the probed function returns, this probe causes the 46362306a36Sopenharmony_ci * handlers to fire 46462306a36Sopenharmony_ci */ 46562306a36Sopenharmony_cistatic void __used kretprobe_trampoline_holder(void) 46662306a36Sopenharmony_ci{ 46762306a36Sopenharmony_ci asm volatile( 46862306a36Sopenharmony_ci ".set push\n\t" 46962306a36Sopenharmony_ci /* Keep the assembler from reordering and placing JR here. */ 47062306a36Sopenharmony_ci ".set noreorder\n\t" 47162306a36Sopenharmony_ci "nop\n\t" 47262306a36Sopenharmony_ci ".global __kretprobe_trampoline\n" 47362306a36Sopenharmony_ci "__kretprobe_trampoline:\n\t" 47462306a36Sopenharmony_ci "nop\n\t" 47562306a36Sopenharmony_ci ".set pop" 47662306a36Sopenharmony_ci : : : "memory"); 47762306a36Sopenharmony_ci} 47862306a36Sopenharmony_ci 47962306a36Sopenharmony_civoid __kretprobe_trampoline(void); 48062306a36Sopenharmony_ci 48162306a36Sopenharmony_civoid arch_prepare_kretprobe(struct kretprobe_instance *ri, 48262306a36Sopenharmony_ci struct pt_regs *regs) 48362306a36Sopenharmony_ci{ 48462306a36Sopenharmony_ci ri->ret_addr = (kprobe_opcode_t *) regs->regs[31]; 48562306a36Sopenharmony_ci ri->fp = NULL; 48662306a36Sopenharmony_ci 48762306a36Sopenharmony_ci /* Replace the return addr with trampoline addr */ 48862306a36Sopenharmony_ci regs->regs[31] = (unsigned long)__kretprobe_trampoline; 48962306a36Sopenharmony_ci} 49062306a36Sopenharmony_ciNOKPROBE_SYMBOL(arch_prepare_kretprobe); 49162306a36Sopenharmony_ci 49262306a36Sopenharmony_ci/* 49362306a36Sopenharmony_ci * Called when the probe at kretprobe trampoline is hit 49462306a36Sopenharmony_ci */ 49562306a36Sopenharmony_cistatic int trampoline_probe_handler(struct kprobe *p, 49662306a36Sopenharmony_ci struct pt_regs *regs) 49762306a36Sopenharmony_ci{ 49862306a36Sopenharmony_ci instruction_pointer(regs) = __kretprobe_trampoline_handler(regs, NULL); 49962306a36Sopenharmony_ci /* 50062306a36Sopenharmony_ci * By returning a non-zero value, we are telling 50162306a36Sopenharmony_ci * kprobe_handler() that we don't want the post_handler 50262306a36Sopenharmony_ci * to run (and have re-enabled preemption) 50362306a36Sopenharmony_ci */ 50462306a36Sopenharmony_ci return 1; 50562306a36Sopenharmony_ci} 50662306a36Sopenharmony_ciNOKPROBE_SYMBOL(trampoline_probe_handler); 50762306a36Sopenharmony_ci 50862306a36Sopenharmony_ciint arch_trampoline_kprobe(struct kprobe *p) 50962306a36Sopenharmony_ci{ 51062306a36Sopenharmony_ci if (p->addr == (kprobe_opcode_t *)__kretprobe_trampoline) 51162306a36Sopenharmony_ci return 1; 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_ci return 0; 51462306a36Sopenharmony_ci} 51562306a36Sopenharmony_ciNOKPROBE_SYMBOL(arch_trampoline_kprobe); 51662306a36Sopenharmony_ci 51762306a36Sopenharmony_cistatic struct kprobe trampoline_p = { 51862306a36Sopenharmony_ci .addr = (kprobe_opcode_t *)__kretprobe_trampoline, 51962306a36Sopenharmony_ci .pre_handler = trampoline_probe_handler 52062306a36Sopenharmony_ci}; 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ciint __init arch_init_kprobes(void) 52362306a36Sopenharmony_ci{ 52462306a36Sopenharmony_ci return register_kprobe(&trampoline_p); 52562306a36Sopenharmony_ci} 526