1 #include <linux/kernel.h>
2 #include <linux/kprobes.h>
3 #include <linux/stop_machine.h>
5 #include <asm/cacheflush.h>
6 #include <asm/smp_plat.h>
7 #include <asm/opcodes.h>
16 void __kprobes
__patch_text(void *addr
, unsigned int insn
)
18 bool thumb2
= IS_ENABLED(CONFIG_THUMB2_KERNEL
);
21 if (thumb2
&& __opcode_is_thumb16(insn
)) {
22 *(u16
*)addr
= __opcode_to_mem_thumb16(insn
);
24 } else if (thumb2
&& ((uintptr_t)addr
& 2)) {
25 u16 first
= __opcode_thumb32_first(insn
);
26 u16 second
= __opcode_thumb32_second(insn
);
29 addrh
[0] = __opcode_to_mem_thumb16(first
);
30 addrh
[1] = __opcode_to_mem_thumb16(second
);
35 insn
= __opcode_to_mem_thumb32(insn
);
37 insn
= __opcode_to_mem_arm(insn
);
43 flush_icache_range((uintptr_t)(addr
),
44 (uintptr_t)(addr
) + size
);
47 static int __kprobes
patch_text_stop_machine(void *data
)
49 struct patch
*patch
= data
;
51 __patch_text(patch
->addr
, patch
->insn
);
56 void __kprobes
patch_text(void *addr
, unsigned int insn
)
58 struct patch patch
= {
63 if (cache_ops_need_broadcast()) {
64 stop_machine(patch_text_stop_machine
, &patch
, cpu_online_mask
);
66 bool straddles_word
= IS_ENABLED(CONFIG_THUMB2_KERNEL
)
67 && __opcode_is_thumb32(insn
)
68 && ((uintptr_t)addr
& 2);
71 stop_machine(patch_text_stop_machine
, &patch
, NULL
);
73 __patch_text(addr
, insn
);