1 #include <linux/kernel.h>
2 #include <linux/spinlock.h>
3 #include <linux/kprobes.h>
5 #include <linux/stop_machine.h>
7 #include <asm/cacheflush.h>
8 #include <asm/fixmap.h>
9 #include <asm/smp_plat.h>
10 #include <asm/opcodes.h>
11 #include <asm/patch.h>
18 static DEFINE_SPINLOCK(patch_lock
);
20 static void __kprobes
*patch_map(void *addr
, int fixmap
, unsigned long *flags
)
21 __acquires(&patch_lock
)
23 unsigned int uintaddr
= (uintptr_t) addr
;
24 bool module
= !core_kernel_text(uintaddr
);
27 if (module
&& IS_ENABLED(CONFIG_STRICT_MODULE_RWX
))
28 page
= vmalloc_to_page(addr
);
29 else if (!module
&& IS_ENABLED(CONFIG_STRICT_KERNEL_RWX
))
30 page
= virt_to_page(addr
);
35 spin_lock_irqsave(&patch_lock
, *flags
);
37 __acquire(&patch_lock
);
39 set_fixmap(fixmap
, page_to_phys(page
));
41 return (void *) (__fix_to_virt(fixmap
) + (uintaddr
& ~PAGE_MASK
));
44 static void __kprobes
patch_unmap(int fixmap
, unsigned long *flags
)
45 __releases(&patch_lock
)
50 spin_unlock_irqrestore(&patch_lock
, *flags
);
52 __release(&patch_lock
);
55 void __kprobes
__patch_text_real(void *addr
, unsigned int insn
, bool remap
)
57 bool thumb2
= IS_ENABLED(CONFIG_THUMB2_KERNEL
);
58 unsigned int uintaddr
= (uintptr_t) addr
;
65 waddr
= patch_map(addr
, FIX_TEXT_POKE0
, &flags
);
67 __acquire(&patch_lock
);
69 if (thumb2
&& __opcode_is_thumb16(insn
)) {
70 *(u16
*)waddr
= __opcode_to_mem_thumb16(insn
);
72 } else if (thumb2
&& (uintaddr
& 2)) {
73 u16 first
= __opcode_thumb32_first(insn
);
74 u16 second
= __opcode_thumb32_second(insn
);
76 u16
*addrh1
= waddr
+ 2;
78 twopage
= (uintaddr
& ~PAGE_MASK
) == PAGE_SIZE
- 2;
80 addrh1
= patch_map(addr
+ 2, FIX_TEXT_POKE1
, NULL
);
82 *addrh0
= __opcode_to_mem_thumb16(first
);
83 *addrh1
= __opcode_to_mem_thumb16(second
);
85 if (twopage
&& addrh1
!= addr
+ 2) {
86 flush_kernel_vmap_range(addrh1
, 2);
87 patch_unmap(FIX_TEXT_POKE1
, NULL
);
93 insn
= __opcode_to_mem_thumb32(insn
);
95 insn
= __opcode_to_mem_arm(insn
);
102 flush_kernel_vmap_range(waddr
, twopage
? size
/ 2 : size
);
103 patch_unmap(FIX_TEXT_POKE0
, &flags
);
105 __release(&patch_lock
);
107 flush_icache_range((uintptr_t)(addr
),
108 (uintptr_t)(addr
) + size
);
111 static int __kprobes
patch_text_stop_machine(void *data
)
113 struct patch
*patch
= data
;
115 __patch_text(patch
->addr
, patch
->insn
);
120 void __kprobes
patch_text(void *addr
, unsigned int insn
)
122 struct patch patch
= {
127 stop_machine(patch_text_stop_machine
, &patch
, NULL
);