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