xref: /linux/arch/loongarch/kernel/uprobes.c (revision cdd5b5a9761fd66d17586e4f4ba6588c70e640ea)
1*19bc6cb6STiezhu Yang // SPDX-License-Identifier: GPL-2.0-only
2*19bc6cb6STiezhu Yang #include <linux/highmem.h>
3*19bc6cb6STiezhu Yang #include <linux/ptrace.h>
4*19bc6cb6STiezhu Yang #include <linux/sched.h>
5*19bc6cb6STiezhu Yang #include <linux/uprobes.h>
6*19bc6cb6STiezhu Yang #include <asm/cacheflush.h>
7*19bc6cb6STiezhu Yang 
8*19bc6cb6STiezhu Yang #define UPROBE_TRAP_NR	UINT_MAX
9*19bc6cb6STiezhu Yang 
arch_uprobe_analyze_insn(struct arch_uprobe * auprobe,struct mm_struct * mm,unsigned long addr)10*19bc6cb6STiezhu Yang int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe,
11*19bc6cb6STiezhu Yang 			     struct mm_struct *mm, unsigned long addr)
12*19bc6cb6STiezhu Yang {
13*19bc6cb6STiezhu Yang 	int idx;
14*19bc6cb6STiezhu Yang 	union loongarch_instruction insn;
15*19bc6cb6STiezhu Yang 
16*19bc6cb6STiezhu Yang 	if (addr & 0x3)
17*19bc6cb6STiezhu Yang 		return -EILSEQ;
18*19bc6cb6STiezhu Yang 
19*19bc6cb6STiezhu Yang 	for (idx = ARRAY_SIZE(auprobe->insn) - 1; idx >= 0; idx--) {
20*19bc6cb6STiezhu Yang 		insn.word = auprobe->insn[idx];
21*19bc6cb6STiezhu Yang 		if (insns_not_supported(insn))
22*19bc6cb6STiezhu Yang 			return -EINVAL;
23*19bc6cb6STiezhu Yang 	}
24*19bc6cb6STiezhu Yang 
25*19bc6cb6STiezhu Yang 	if (insns_need_simulation(insn)) {
26*19bc6cb6STiezhu Yang 		auprobe->ixol[0] = larch_insn_gen_nop();
27*19bc6cb6STiezhu Yang 		auprobe->simulate = true;
28*19bc6cb6STiezhu Yang 	} else {
29*19bc6cb6STiezhu Yang 		auprobe->ixol[0] = auprobe->insn[0];
30*19bc6cb6STiezhu Yang 		auprobe->simulate = false;
31*19bc6cb6STiezhu Yang 	}
32*19bc6cb6STiezhu Yang 
33*19bc6cb6STiezhu Yang 	auprobe->ixol[1] = UPROBE_XOLBP_INSN;
34*19bc6cb6STiezhu Yang 
35*19bc6cb6STiezhu Yang 	return 0;
36*19bc6cb6STiezhu Yang }
37*19bc6cb6STiezhu Yang 
arch_uprobe_pre_xol(struct arch_uprobe * auprobe,struct pt_regs * regs)38*19bc6cb6STiezhu Yang int arch_uprobe_pre_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
39*19bc6cb6STiezhu Yang {
40*19bc6cb6STiezhu Yang 	struct uprobe_task *utask = current->utask;
41*19bc6cb6STiezhu Yang 
42*19bc6cb6STiezhu Yang 	utask->autask.saved_trap_nr = current->thread.trap_nr;
43*19bc6cb6STiezhu Yang 	current->thread.trap_nr = UPROBE_TRAP_NR;
44*19bc6cb6STiezhu Yang 	instruction_pointer_set(regs, utask->xol_vaddr);
45*19bc6cb6STiezhu Yang 	user_enable_single_step(current);
46*19bc6cb6STiezhu Yang 
47*19bc6cb6STiezhu Yang 	return 0;
48*19bc6cb6STiezhu Yang }
49*19bc6cb6STiezhu Yang 
arch_uprobe_post_xol(struct arch_uprobe * auprobe,struct pt_regs * regs)50*19bc6cb6STiezhu Yang int arch_uprobe_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
51*19bc6cb6STiezhu Yang {
52*19bc6cb6STiezhu Yang 	struct uprobe_task *utask = current->utask;
53*19bc6cb6STiezhu Yang 
54*19bc6cb6STiezhu Yang 	WARN_ON_ONCE(current->thread.trap_nr != UPROBE_TRAP_NR);
55*19bc6cb6STiezhu Yang 	current->thread.trap_nr = utask->autask.saved_trap_nr;
56*19bc6cb6STiezhu Yang 
57*19bc6cb6STiezhu Yang 	if (auprobe->simulate)
58*19bc6cb6STiezhu Yang 		instruction_pointer_set(regs, auprobe->resume_era);
59*19bc6cb6STiezhu Yang 	else
60*19bc6cb6STiezhu Yang 		instruction_pointer_set(regs, utask->vaddr + LOONGARCH_INSN_SIZE);
61*19bc6cb6STiezhu Yang 
62*19bc6cb6STiezhu Yang 	user_disable_single_step(current);
63*19bc6cb6STiezhu Yang 
64*19bc6cb6STiezhu Yang 	return 0;
65*19bc6cb6STiezhu Yang }
66*19bc6cb6STiezhu Yang 
arch_uprobe_abort_xol(struct arch_uprobe * auprobe,struct pt_regs * regs)67*19bc6cb6STiezhu Yang void arch_uprobe_abort_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
68*19bc6cb6STiezhu Yang {
69*19bc6cb6STiezhu Yang 	struct uprobe_task *utask = current->utask;
70*19bc6cb6STiezhu Yang 
71*19bc6cb6STiezhu Yang 	current->thread.trap_nr = utask->autask.saved_trap_nr;
72*19bc6cb6STiezhu Yang 	instruction_pointer_set(regs, utask->vaddr);
73*19bc6cb6STiezhu Yang 	user_disable_single_step(current);
74*19bc6cb6STiezhu Yang }
75*19bc6cb6STiezhu Yang 
arch_uprobe_xol_was_trapped(struct task_struct * t)76*19bc6cb6STiezhu Yang bool arch_uprobe_xol_was_trapped(struct task_struct *t)
77*19bc6cb6STiezhu Yang {
78*19bc6cb6STiezhu Yang 	if (t->thread.trap_nr != UPROBE_TRAP_NR)
79*19bc6cb6STiezhu Yang 		return true;
80*19bc6cb6STiezhu Yang 
81*19bc6cb6STiezhu Yang 	return false;
82*19bc6cb6STiezhu Yang }
83*19bc6cb6STiezhu Yang 
arch_uprobe_skip_sstep(struct arch_uprobe * auprobe,struct pt_regs * regs)84*19bc6cb6STiezhu Yang bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs)
85*19bc6cb6STiezhu Yang {
86*19bc6cb6STiezhu Yang 	union loongarch_instruction insn;
87*19bc6cb6STiezhu Yang 
88*19bc6cb6STiezhu Yang 	if (!auprobe->simulate)
89*19bc6cb6STiezhu Yang 		return false;
90*19bc6cb6STiezhu Yang 
91*19bc6cb6STiezhu Yang 	insn.word = auprobe->insn[0];
92*19bc6cb6STiezhu Yang 	arch_simulate_insn(insn, regs);
93*19bc6cb6STiezhu Yang 	auprobe->resume_era = regs->csr_era;
94*19bc6cb6STiezhu Yang 
95*19bc6cb6STiezhu Yang 	return true;
96*19bc6cb6STiezhu Yang }
97*19bc6cb6STiezhu Yang 
arch_uretprobe_hijack_return_addr(unsigned long trampoline_vaddr,struct pt_regs * regs)98*19bc6cb6STiezhu Yang unsigned long arch_uretprobe_hijack_return_addr(unsigned long trampoline_vaddr,
99*19bc6cb6STiezhu Yang 						struct pt_regs *regs)
100*19bc6cb6STiezhu Yang {
101*19bc6cb6STiezhu Yang 	unsigned long ra = regs->regs[1];
102*19bc6cb6STiezhu Yang 
103*19bc6cb6STiezhu Yang 	regs->regs[1] = trampoline_vaddr;
104*19bc6cb6STiezhu Yang 
105*19bc6cb6STiezhu Yang 	return ra;
106*19bc6cb6STiezhu Yang }
107*19bc6cb6STiezhu Yang 
arch_uretprobe_is_alive(struct return_instance * ret,enum rp_check ctx,struct pt_regs * regs)108*19bc6cb6STiezhu Yang bool arch_uretprobe_is_alive(struct return_instance *ret,
109*19bc6cb6STiezhu Yang 			     enum rp_check ctx, struct pt_regs *regs)
110*19bc6cb6STiezhu Yang {
111*19bc6cb6STiezhu Yang 	if (ctx == RP_CHECK_CHAIN_CALL)
112*19bc6cb6STiezhu Yang 		return regs->regs[3] <= ret->stack;
113*19bc6cb6STiezhu Yang 	else
114*19bc6cb6STiezhu Yang 		return regs->regs[3] < ret->stack;
115*19bc6cb6STiezhu Yang }
116*19bc6cb6STiezhu Yang 
arch_uprobe_exception_notify(struct notifier_block * self,unsigned long val,void * data)117*19bc6cb6STiezhu Yang int arch_uprobe_exception_notify(struct notifier_block *self,
118*19bc6cb6STiezhu Yang 				 unsigned long val, void *data)
119*19bc6cb6STiezhu Yang {
120*19bc6cb6STiezhu Yang 	return NOTIFY_DONE;
121*19bc6cb6STiezhu Yang }
122*19bc6cb6STiezhu Yang 
uprobe_breakpoint_handler(struct pt_regs * regs)123*19bc6cb6STiezhu Yang bool uprobe_breakpoint_handler(struct pt_regs *regs)
124*19bc6cb6STiezhu Yang {
125*19bc6cb6STiezhu Yang 	if (uprobe_pre_sstep_notifier(regs))
126*19bc6cb6STiezhu Yang 		return true;
127*19bc6cb6STiezhu Yang 
128*19bc6cb6STiezhu Yang 	return false;
129*19bc6cb6STiezhu Yang }
130*19bc6cb6STiezhu Yang 
uprobe_singlestep_handler(struct pt_regs * regs)131*19bc6cb6STiezhu Yang bool uprobe_singlestep_handler(struct pt_regs *regs)
132*19bc6cb6STiezhu Yang {
133*19bc6cb6STiezhu Yang 	if (uprobe_post_sstep_notifier(regs))
134*19bc6cb6STiezhu Yang 		return true;
135*19bc6cb6STiezhu Yang 
136*19bc6cb6STiezhu Yang 	return false;
137*19bc6cb6STiezhu Yang }
138*19bc6cb6STiezhu Yang 
uprobe_get_swbp_addr(struct pt_regs * regs)139*19bc6cb6STiezhu Yang unsigned long uprobe_get_swbp_addr(struct pt_regs *regs)
140*19bc6cb6STiezhu Yang {
141*19bc6cb6STiezhu Yang 	return instruction_pointer(regs);
142*19bc6cb6STiezhu Yang }
143*19bc6cb6STiezhu Yang 
arch_uprobe_copy_ixol(struct page * page,unsigned long vaddr,void * src,unsigned long len)144*19bc6cb6STiezhu Yang void arch_uprobe_copy_ixol(struct page *page, unsigned long vaddr,
145*19bc6cb6STiezhu Yang 			   void *src, unsigned long len)
146*19bc6cb6STiezhu Yang {
147*19bc6cb6STiezhu Yang 	void *kaddr = kmap_local_page(page);
148*19bc6cb6STiezhu Yang 	void *dst = kaddr + (vaddr & ~PAGE_MASK);
149*19bc6cb6STiezhu Yang 
150*19bc6cb6STiezhu Yang 	memcpy(dst, src, len);
151*19bc6cb6STiezhu Yang 	flush_icache_range((unsigned long)dst, (unsigned long)dst + len);
152*19bc6cb6STiezhu Yang 	kunmap_local(kaddr);
153*19bc6cb6STiezhu Yang }
154