18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  Kernel Probes Jump Optimization (Optprobes)
48c2ecf20Sopenharmony_ci *
58c2ecf20Sopenharmony_ci * Copyright (C) IBM Corporation, 2002, 2004
68c2ecf20Sopenharmony_ci * Copyright (C) Hitachi Ltd., 2012
78c2ecf20Sopenharmony_ci * Copyright (C) Huawei Inc., 2014
88c2ecf20Sopenharmony_ci */
98c2ecf20Sopenharmony_ci
108c2ecf20Sopenharmony_ci#include <linux/kprobes.h>
118c2ecf20Sopenharmony_ci#include <linux/jump_label.h>
128c2ecf20Sopenharmony_ci#include <asm/kprobes.h>
138c2ecf20Sopenharmony_ci#include <asm/cacheflush.h>
148c2ecf20Sopenharmony_ci/* for arm_gen_branch */
158c2ecf20Sopenharmony_ci#include <asm/insn.h>
168c2ecf20Sopenharmony_ci/* for patch_text */
178c2ecf20Sopenharmony_ci#include <asm/patch.h>
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci#include "core.h"
208c2ecf20Sopenharmony_ci
218c2ecf20Sopenharmony_ci/*
228c2ecf20Sopenharmony_ci * See register_usage_flags. If the probed instruction doesn't use PC,
238c2ecf20Sopenharmony_ci * we can copy it into template and have it executed directly without
248c2ecf20Sopenharmony_ci * simulation or emulation.
258c2ecf20Sopenharmony_ci */
268c2ecf20Sopenharmony_ci#define ARM_REG_PC	15
278c2ecf20Sopenharmony_ci#define can_kprobe_direct_exec(m)	(!test_bit(ARM_REG_PC, &(m)))
288c2ecf20Sopenharmony_ci
298c2ecf20Sopenharmony_ci/*
308c2ecf20Sopenharmony_ci * NOTE: the first sub and add instruction will be modified according
318c2ecf20Sopenharmony_ci * to the stack cost of the instruction.
328c2ecf20Sopenharmony_ci */
338c2ecf20Sopenharmony_ciasm (
348c2ecf20Sopenharmony_ci			".global optprobe_template_entry\n"
358c2ecf20Sopenharmony_ci			"optprobe_template_entry:\n"
368c2ecf20Sopenharmony_ci			".global optprobe_template_sub_sp\n"
378c2ecf20Sopenharmony_ci			"optprobe_template_sub_sp:"
388c2ecf20Sopenharmony_ci			"	sub	sp, sp, #0xff\n"
398c2ecf20Sopenharmony_ci			"	stmia	sp, {r0 - r14} \n"
408c2ecf20Sopenharmony_ci			".global optprobe_template_add_sp\n"
418c2ecf20Sopenharmony_ci			"optprobe_template_add_sp:"
428c2ecf20Sopenharmony_ci			"	add	r3, sp, #0xff\n"
438c2ecf20Sopenharmony_ci			"	str	r3, [sp, #52]\n"
448c2ecf20Sopenharmony_ci			"	mrs	r4, cpsr\n"
458c2ecf20Sopenharmony_ci			"	str	r4, [sp, #64]\n"
468c2ecf20Sopenharmony_ci			"	mov	r1, sp\n"
478c2ecf20Sopenharmony_ci			"	ldr	r0, 1f\n"
488c2ecf20Sopenharmony_ci			"	ldr	r2, 2f\n"
498c2ecf20Sopenharmony_ci			/*
508c2ecf20Sopenharmony_ci			 * AEABI requires an 8-bytes alignment stack. If
518c2ecf20Sopenharmony_ci			 * SP % 8 != 0 (SP % 4 == 0 should be ensured),
528c2ecf20Sopenharmony_ci			 * alloc more bytes here.
538c2ecf20Sopenharmony_ci			 */
548c2ecf20Sopenharmony_ci			"	and	r4, sp, #4\n"
558c2ecf20Sopenharmony_ci			"	sub	sp, sp, r4\n"
568c2ecf20Sopenharmony_ci#if __LINUX_ARM_ARCH__ >= 5
578c2ecf20Sopenharmony_ci			"	blx	r2\n"
588c2ecf20Sopenharmony_ci#else
598c2ecf20Sopenharmony_ci			"	mov     lr, pc\n"
608c2ecf20Sopenharmony_ci			"	mov	pc, r2\n"
618c2ecf20Sopenharmony_ci#endif
628c2ecf20Sopenharmony_ci			"	add	sp, sp, r4\n"
638c2ecf20Sopenharmony_ci			"	ldr	r1, [sp, #64]\n"
648c2ecf20Sopenharmony_ci			"	tst	r1, #"__stringify(PSR_T_BIT)"\n"
658c2ecf20Sopenharmony_ci			"	ldrne	r2, [sp, #60]\n"
668c2ecf20Sopenharmony_ci			"	orrne	r2, #1\n"
678c2ecf20Sopenharmony_ci			"	strne	r2, [sp, #60] @ set bit0 of PC for thumb\n"
688c2ecf20Sopenharmony_ci			"	msr	cpsr_cxsf, r1\n"
698c2ecf20Sopenharmony_ci			".global optprobe_template_restore_begin\n"
708c2ecf20Sopenharmony_ci			"optprobe_template_restore_begin:\n"
718c2ecf20Sopenharmony_ci			"	ldmia	sp, {r0 - r15}\n"
728c2ecf20Sopenharmony_ci			".global optprobe_template_restore_orig_insn\n"
738c2ecf20Sopenharmony_ci			"optprobe_template_restore_orig_insn:\n"
748c2ecf20Sopenharmony_ci			"	nop\n"
758c2ecf20Sopenharmony_ci			".global optprobe_template_restore_end\n"
768c2ecf20Sopenharmony_ci			"optprobe_template_restore_end:\n"
778c2ecf20Sopenharmony_ci			"	nop\n"
788c2ecf20Sopenharmony_ci			".global optprobe_template_val\n"
798c2ecf20Sopenharmony_ci			"optprobe_template_val:\n"
808c2ecf20Sopenharmony_ci			"1:	.long 0\n"
818c2ecf20Sopenharmony_ci			".global optprobe_template_call\n"
828c2ecf20Sopenharmony_ci			"optprobe_template_call:\n"
838c2ecf20Sopenharmony_ci			"2:	.long 0\n"
848c2ecf20Sopenharmony_ci			".global optprobe_template_end\n"
858c2ecf20Sopenharmony_ci			"optprobe_template_end:\n");
868c2ecf20Sopenharmony_ci
878c2ecf20Sopenharmony_ci#define TMPL_VAL_IDX \
888c2ecf20Sopenharmony_ci	((unsigned long *)optprobe_template_val - (unsigned long *)optprobe_template_entry)
898c2ecf20Sopenharmony_ci#define TMPL_CALL_IDX \
908c2ecf20Sopenharmony_ci	((unsigned long *)optprobe_template_call - (unsigned long *)optprobe_template_entry)
918c2ecf20Sopenharmony_ci#define TMPL_END_IDX \
928c2ecf20Sopenharmony_ci	((unsigned long *)optprobe_template_end - (unsigned long *)optprobe_template_entry)
938c2ecf20Sopenharmony_ci#define TMPL_ADD_SP \
948c2ecf20Sopenharmony_ci	((unsigned long *)optprobe_template_add_sp - (unsigned long *)optprobe_template_entry)
958c2ecf20Sopenharmony_ci#define TMPL_SUB_SP \
968c2ecf20Sopenharmony_ci	((unsigned long *)optprobe_template_sub_sp - (unsigned long *)optprobe_template_entry)
978c2ecf20Sopenharmony_ci#define TMPL_RESTORE_BEGIN \
988c2ecf20Sopenharmony_ci	((unsigned long *)optprobe_template_restore_begin - (unsigned long *)optprobe_template_entry)
998c2ecf20Sopenharmony_ci#define TMPL_RESTORE_ORIGN_INSN \
1008c2ecf20Sopenharmony_ci	((unsigned long *)optprobe_template_restore_orig_insn - (unsigned long *)optprobe_template_entry)
1018c2ecf20Sopenharmony_ci#define TMPL_RESTORE_END \
1028c2ecf20Sopenharmony_ci	((unsigned long *)optprobe_template_restore_end - (unsigned long *)optprobe_template_entry)
1038c2ecf20Sopenharmony_ci
1048c2ecf20Sopenharmony_ci/*
1058c2ecf20Sopenharmony_ci * ARM can always optimize an instruction when using ARM ISA, except
1068c2ecf20Sopenharmony_ci * instructions like 'str r0, [sp, r1]' which store to stack and unable
1078c2ecf20Sopenharmony_ci * to determine stack space consumption statically.
1088c2ecf20Sopenharmony_ci */
1098c2ecf20Sopenharmony_ciint arch_prepared_optinsn(struct arch_optimized_insn *optinsn)
1108c2ecf20Sopenharmony_ci{
1118c2ecf20Sopenharmony_ci	return optinsn->insn != NULL;
1128c2ecf20Sopenharmony_ci}
1138c2ecf20Sopenharmony_ci
1148c2ecf20Sopenharmony_ci/*
1158c2ecf20Sopenharmony_ci * In ARM ISA, kprobe opt always replace one instruction (4 bytes
1168c2ecf20Sopenharmony_ci * aligned and 4 bytes long). It is impossible to encounter another
1178c2ecf20Sopenharmony_ci * kprobe in the address range. So always return 0.
1188c2ecf20Sopenharmony_ci */
1198c2ecf20Sopenharmony_ciint arch_check_optimized_kprobe(struct optimized_kprobe *op)
1208c2ecf20Sopenharmony_ci{
1218c2ecf20Sopenharmony_ci	return 0;
1228c2ecf20Sopenharmony_ci}
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_ci/* Caller must ensure addr & 3 == 0 */
1258c2ecf20Sopenharmony_cistatic int can_optimize(struct kprobe *kp)
1268c2ecf20Sopenharmony_ci{
1278c2ecf20Sopenharmony_ci	if (kp->ainsn.stack_space < 0)
1288c2ecf20Sopenharmony_ci		return 0;
1298c2ecf20Sopenharmony_ci	/*
1308c2ecf20Sopenharmony_ci	 * 255 is the biggest imm can be used in 'sub r0, r0, #<imm>'.
1318c2ecf20Sopenharmony_ci	 * Number larger than 255 needs special encoding.
1328c2ecf20Sopenharmony_ci	 */
1338c2ecf20Sopenharmony_ci	if (kp->ainsn.stack_space > 255 - sizeof(struct pt_regs))
1348c2ecf20Sopenharmony_ci		return 0;
1358c2ecf20Sopenharmony_ci	return 1;
1368c2ecf20Sopenharmony_ci}
1378c2ecf20Sopenharmony_ci
1388c2ecf20Sopenharmony_ci/* Free optimized instruction slot */
1398c2ecf20Sopenharmony_cistatic void
1408c2ecf20Sopenharmony_ci__arch_remove_optimized_kprobe(struct optimized_kprobe *op, int dirty)
1418c2ecf20Sopenharmony_ci{
1428c2ecf20Sopenharmony_ci	if (op->optinsn.insn) {
1438c2ecf20Sopenharmony_ci		free_optinsn_slot(op->optinsn.insn, dirty);
1448c2ecf20Sopenharmony_ci		op->optinsn.insn = NULL;
1458c2ecf20Sopenharmony_ci	}
1468c2ecf20Sopenharmony_ci}
1478c2ecf20Sopenharmony_ci
1488c2ecf20Sopenharmony_cistatic void
1498c2ecf20Sopenharmony_cioptimized_callback(struct optimized_kprobe *op, struct pt_regs *regs)
1508c2ecf20Sopenharmony_ci{
1518c2ecf20Sopenharmony_ci	unsigned long flags;
1528c2ecf20Sopenharmony_ci	struct kprobe *p = &op->kp;
1538c2ecf20Sopenharmony_ci	struct kprobe_ctlblk *kcb;
1548c2ecf20Sopenharmony_ci
1558c2ecf20Sopenharmony_ci	/* Save skipped registers */
1568c2ecf20Sopenharmony_ci	regs->ARM_pc = (unsigned long)op->kp.addr;
1578c2ecf20Sopenharmony_ci	regs->ARM_ORIG_r0 = ~0UL;
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci	local_irq_save(flags);
1608c2ecf20Sopenharmony_ci	kcb = get_kprobe_ctlblk();
1618c2ecf20Sopenharmony_ci
1628c2ecf20Sopenharmony_ci	if (kprobe_running()) {
1638c2ecf20Sopenharmony_ci		kprobes_inc_nmissed_count(&op->kp);
1648c2ecf20Sopenharmony_ci	} else {
1658c2ecf20Sopenharmony_ci		__this_cpu_write(current_kprobe, &op->kp);
1668c2ecf20Sopenharmony_ci		kcb->kprobe_status = KPROBE_HIT_ACTIVE;
1678c2ecf20Sopenharmony_ci		opt_pre_handler(&op->kp, regs);
1688c2ecf20Sopenharmony_ci		__this_cpu_write(current_kprobe, NULL);
1698c2ecf20Sopenharmony_ci	}
1708c2ecf20Sopenharmony_ci
1718c2ecf20Sopenharmony_ci	/*
1728c2ecf20Sopenharmony_ci	 * We singlestep the replaced instruction only when it can't be
1738c2ecf20Sopenharmony_ci	 * executed directly during restore.
1748c2ecf20Sopenharmony_ci	 */
1758c2ecf20Sopenharmony_ci	if (!p->ainsn.kprobe_direct_exec)
1768c2ecf20Sopenharmony_ci		op->kp.ainsn.insn_singlestep(p->opcode, &p->ainsn, regs);
1778c2ecf20Sopenharmony_ci
1788c2ecf20Sopenharmony_ci	local_irq_restore(flags);
1798c2ecf20Sopenharmony_ci}
1808c2ecf20Sopenharmony_ciNOKPROBE_SYMBOL(optimized_callback)
1818c2ecf20Sopenharmony_ci
1828c2ecf20Sopenharmony_ciint arch_prepare_optimized_kprobe(struct optimized_kprobe *op, struct kprobe *orig)
1838c2ecf20Sopenharmony_ci{
1848c2ecf20Sopenharmony_ci	kprobe_opcode_t *code;
1858c2ecf20Sopenharmony_ci	unsigned long rel_chk;
1868c2ecf20Sopenharmony_ci	unsigned long val;
1878c2ecf20Sopenharmony_ci	unsigned long stack_protect = sizeof(struct pt_regs);
1888c2ecf20Sopenharmony_ci
1898c2ecf20Sopenharmony_ci	if (!can_optimize(orig))
1908c2ecf20Sopenharmony_ci		return -EILSEQ;
1918c2ecf20Sopenharmony_ci
1928c2ecf20Sopenharmony_ci	code = get_optinsn_slot();
1938c2ecf20Sopenharmony_ci	if (!code)
1948c2ecf20Sopenharmony_ci		return -ENOMEM;
1958c2ecf20Sopenharmony_ci
1968c2ecf20Sopenharmony_ci	/*
1978c2ecf20Sopenharmony_ci	 * Verify if the address gap is in 32MiB range, because this uses
1988c2ecf20Sopenharmony_ci	 * a relative jump.
1998c2ecf20Sopenharmony_ci	 *
2008c2ecf20Sopenharmony_ci	 * kprobe opt use a 'b' instruction to branch to optinsn.insn.
2018c2ecf20Sopenharmony_ci	 * According to ARM manual, branch instruction is:
2028c2ecf20Sopenharmony_ci	 *
2038c2ecf20Sopenharmony_ci	 *   31  28 27           24 23             0
2048c2ecf20Sopenharmony_ci	 *  +------+---+---+---+---+----------------+
2058c2ecf20Sopenharmony_ci	 *  | cond | 1 | 0 | 1 | 0 |      imm24     |
2068c2ecf20Sopenharmony_ci	 *  +------+---+---+---+---+----------------+
2078c2ecf20Sopenharmony_ci	 *
2088c2ecf20Sopenharmony_ci	 * imm24 is a signed 24 bits integer. The real branch offset is computed
2098c2ecf20Sopenharmony_ci	 * by: imm32 = SignExtend(imm24:'00', 32);
2108c2ecf20Sopenharmony_ci	 *
2118c2ecf20Sopenharmony_ci	 * So the maximum forward branch should be:
2128c2ecf20Sopenharmony_ci	 *   (0x007fffff << 2) = 0x01fffffc =  0x1fffffc
2138c2ecf20Sopenharmony_ci	 * The maximum backword branch should be:
2148c2ecf20Sopenharmony_ci	 *   (0xff800000 << 2) = 0xfe000000 = -0x2000000
2158c2ecf20Sopenharmony_ci	 *
2168c2ecf20Sopenharmony_ci	 * We can simply check (rel & 0xfe000003):
2178c2ecf20Sopenharmony_ci	 *  if rel is positive, (rel & 0xfe000000) shoule be 0
2188c2ecf20Sopenharmony_ci	 *  if rel is negitive, (rel & 0xfe000000) should be 0xfe000000
2198c2ecf20Sopenharmony_ci	 *  the last '3' is used for alignment checking.
2208c2ecf20Sopenharmony_ci	 */
2218c2ecf20Sopenharmony_ci	rel_chk = (unsigned long)((long)code -
2228c2ecf20Sopenharmony_ci			(long)orig->addr + 8) & 0xfe000003;
2238c2ecf20Sopenharmony_ci
2248c2ecf20Sopenharmony_ci	if ((rel_chk != 0) && (rel_chk != 0xfe000000)) {
2258c2ecf20Sopenharmony_ci		/*
2268c2ecf20Sopenharmony_ci		 * Different from x86, we free code buf directly instead of
2278c2ecf20Sopenharmony_ci		 * calling __arch_remove_optimized_kprobe() because
2288c2ecf20Sopenharmony_ci		 * we have not fill any field in op.
2298c2ecf20Sopenharmony_ci		 */
2308c2ecf20Sopenharmony_ci		free_optinsn_slot(code, 0);
2318c2ecf20Sopenharmony_ci		return -ERANGE;
2328c2ecf20Sopenharmony_ci	}
2338c2ecf20Sopenharmony_ci
2348c2ecf20Sopenharmony_ci	/* Copy arch-dep-instance from template. */
2358c2ecf20Sopenharmony_ci	memcpy(code, (unsigned long *)optprobe_template_entry,
2368c2ecf20Sopenharmony_ci			TMPL_END_IDX * sizeof(kprobe_opcode_t));
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	/* Adjust buffer according to instruction. */
2398c2ecf20Sopenharmony_ci	BUG_ON(orig->ainsn.stack_space < 0);
2408c2ecf20Sopenharmony_ci
2418c2ecf20Sopenharmony_ci	stack_protect += orig->ainsn.stack_space;
2428c2ecf20Sopenharmony_ci
2438c2ecf20Sopenharmony_ci	/* Should have been filtered by can_optimize(). */
2448c2ecf20Sopenharmony_ci	BUG_ON(stack_protect > 255);
2458c2ecf20Sopenharmony_ci
2468c2ecf20Sopenharmony_ci	/* Create a 'sub sp, sp, #<stack_protect>' */
2478c2ecf20Sopenharmony_ci	code[TMPL_SUB_SP] = __opcode_to_mem_arm(0xe24dd000 | stack_protect);
2488c2ecf20Sopenharmony_ci	/* Create a 'add r3, sp, #<stack_protect>' */
2498c2ecf20Sopenharmony_ci	code[TMPL_ADD_SP] = __opcode_to_mem_arm(0xe28d3000 | stack_protect);
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ci	/* Set probe information */
2528c2ecf20Sopenharmony_ci	val = (unsigned long)op;
2538c2ecf20Sopenharmony_ci	code[TMPL_VAL_IDX] = val;
2548c2ecf20Sopenharmony_ci
2558c2ecf20Sopenharmony_ci	/* Set probe function call */
2568c2ecf20Sopenharmony_ci	val = (unsigned long)optimized_callback;
2578c2ecf20Sopenharmony_ci	code[TMPL_CALL_IDX] = val;
2588c2ecf20Sopenharmony_ci
2598c2ecf20Sopenharmony_ci	/* If possible, copy insn and have it executed during restore */
2608c2ecf20Sopenharmony_ci	orig->ainsn.kprobe_direct_exec = false;
2618c2ecf20Sopenharmony_ci	if (can_kprobe_direct_exec(orig->ainsn.register_usage_flags)) {
2628c2ecf20Sopenharmony_ci		kprobe_opcode_t final_branch = arm_gen_branch(
2638c2ecf20Sopenharmony_ci				(unsigned long)(&code[TMPL_RESTORE_END]),
2648c2ecf20Sopenharmony_ci				(unsigned long)(op->kp.addr) + 4);
2658c2ecf20Sopenharmony_ci		if (final_branch != 0) {
2668c2ecf20Sopenharmony_ci			/*
2678c2ecf20Sopenharmony_ci			 * Replace original 'ldmia sp, {r0 - r15}' with
2688c2ecf20Sopenharmony_ci			 * 'ldmia {r0 - r14}', restore all registers except pc.
2698c2ecf20Sopenharmony_ci			 */
2708c2ecf20Sopenharmony_ci			code[TMPL_RESTORE_BEGIN] = __opcode_to_mem_arm(0xe89d7fff);
2718c2ecf20Sopenharmony_ci
2728c2ecf20Sopenharmony_ci			/* The original probed instruction */
2738c2ecf20Sopenharmony_ci			code[TMPL_RESTORE_ORIGN_INSN] = __opcode_to_mem_arm(orig->opcode);
2748c2ecf20Sopenharmony_ci
2758c2ecf20Sopenharmony_ci			/* Jump back to next instruction */
2768c2ecf20Sopenharmony_ci			code[TMPL_RESTORE_END] = __opcode_to_mem_arm(final_branch);
2778c2ecf20Sopenharmony_ci			orig->ainsn.kprobe_direct_exec = true;
2788c2ecf20Sopenharmony_ci		}
2798c2ecf20Sopenharmony_ci	}
2808c2ecf20Sopenharmony_ci
2818c2ecf20Sopenharmony_ci	flush_icache_range((unsigned long)code,
2828c2ecf20Sopenharmony_ci			   (unsigned long)(&code[TMPL_END_IDX]));
2838c2ecf20Sopenharmony_ci
2848c2ecf20Sopenharmony_ci	/* Set op->optinsn.insn means prepared. */
2858c2ecf20Sopenharmony_ci	op->optinsn.insn = code;
2868c2ecf20Sopenharmony_ci	return 0;
2878c2ecf20Sopenharmony_ci}
2888c2ecf20Sopenharmony_ci
2898c2ecf20Sopenharmony_civoid __kprobes arch_optimize_kprobes(struct list_head *oplist)
2908c2ecf20Sopenharmony_ci{
2918c2ecf20Sopenharmony_ci	struct optimized_kprobe *op, *tmp;
2928c2ecf20Sopenharmony_ci
2938c2ecf20Sopenharmony_ci	list_for_each_entry_safe(op, tmp, oplist, list) {
2948c2ecf20Sopenharmony_ci		unsigned long insn;
2958c2ecf20Sopenharmony_ci		WARN_ON(kprobe_disabled(&op->kp));
2968c2ecf20Sopenharmony_ci
2978c2ecf20Sopenharmony_ci		/*
2988c2ecf20Sopenharmony_ci		 * Backup instructions which will be replaced
2998c2ecf20Sopenharmony_ci		 * by jump address
3008c2ecf20Sopenharmony_ci		 */
3018c2ecf20Sopenharmony_ci		memcpy(op->optinsn.copied_insn, op->kp.addr,
3028c2ecf20Sopenharmony_ci				RELATIVEJUMP_SIZE);
3038c2ecf20Sopenharmony_ci
3048c2ecf20Sopenharmony_ci		insn = arm_gen_branch((unsigned long)op->kp.addr,
3058c2ecf20Sopenharmony_ci				(unsigned long)op->optinsn.insn);
3068c2ecf20Sopenharmony_ci		BUG_ON(insn == 0);
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci		/*
3098c2ecf20Sopenharmony_ci		 * Make it a conditional branch if replaced insn
3108c2ecf20Sopenharmony_ci		 * is consitional
3118c2ecf20Sopenharmony_ci		 */
3128c2ecf20Sopenharmony_ci		insn = (__mem_to_opcode_arm(
3138c2ecf20Sopenharmony_ci			  op->optinsn.copied_insn[0]) & 0xf0000000) |
3148c2ecf20Sopenharmony_ci			(insn & 0x0fffffff);
3158c2ecf20Sopenharmony_ci
3168c2ecf20Sopenharmony_ci		/*
3178c2ecf20Sopenharmony_ci		 * Similar to __arch_disarm_kprobe, operations which
3188c2ecf20Sopenharmony_ci		 * removing breakpoints must be wrapped by stop_machine
3198c2ecf20Sopenharmony_ci		 * to avoid racing.
3208c2ecf20Sopenharmony_ci		 */
3218c2ecf20Sopenharmony_ci		kprobes_remove_breakpoint(op->kp.addr, insn);
3228c2ecf20Sopenharmony_ci
3238c2ecf20Sopenharmony_ci		list_del_init(&op->list);
3248c2ecf20Sopenharmony_ci	}
3258c2ecf20Sopenharmony_ci}
3268c2ecf20Sopenharmony_ci
3278c2ecf20Sopenharmony_civoid arch_unoptimize_kprobe(struct optimized_kprobe *op)
3288c2ecf20Sopenharmony_ci{
3298c2ecf20Sopenharmony_ci	arch_arm_kprobe(&op->kp);
3308c2ecf20Sopenharmony_ci}
3318c2ecf20Sopenharmony_ci
3328c2ecf20Sopenharmony_ci/*
3338c2ecf20Sopenharmony_ci * Recover original instructions and breakpoints from relative jumps.
3348c2ecf20Sopenharmony_ci * Caller must call with locking kprobe_mutex.
3358c2ecf20Sopenharmony_ci */
3368c2ecf20Sopenharmony_civoid arch_unoptimize_kprobes(struct list_head *oplist,
3378c2ecf20Sopenharmony_ci			    struct list_head *done_list)
3388c2ecf20Sopenharmony_ci{
3398c2ecf20Sopenharmony_ci	struct optimized_kprobe *op, *tmp;
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci	list_for_each_entry_safe(op, tmp, oplist, list) {
3428c2ecf20Sopenharmony_ci		arch_unoptimize_kprobe(op);
3438c2ecf20Sopenharmony_ci		list_move(&op->list, done_list);
3448c2ecf20Sopenharmony_ci	}
3458c2ecf20Sopenharmony_ci}
3468c2ecf20Sopenharmony_ci
3478c2ecf20Sopenharmony_ciint arch_within_optimized_kprobe(struct optimized_kprobe *op,
3488c2ecf20Sopenharmony_ci				unsigned long addr)
3498c2ecf20Sopenharmony_ci{
3508c2ecf20Sopenharmony_ci	return ((unsigned long)op->kp.addr <= addr &&
3518c2ecf20Sopenharmony_ci		(unsigned long)op->kp.addr + RELATIVEJUMP_SIZE > addr);
3528c2ecf20Sopenharmony_ci}
3538c2ecf20Sopenharmony_ci
3548c2ecf20Sopenharmony_civoid arch_remove_optimized_kprobe(struct optimized_kprobe *op)
3558c2ecf20Sopenharmony_ci{
3568c2ecf20Sopenharmony_ci	__arch_remove_optimized_kprobe(op, 1);
3578c2ecf20Sopenharmony_ci}
358