GNU Linux-libre 6.7.9-gnu
[releases.git] / arch / riscv / kernel / probes / uprobes.c
1 // SPDX-License-Identifier: GPL-2.0-only
2
3 #include <linux/highmem.h>
4 #include <linux/ptrace.h>
5 #include <linux/uprobes.h>
6 #include <asm/insn.h>
7
8 #include "decode-insn.h"
9
10 #define UPROBE_TRAP_NR  UINT_MAX
11
12 bool is_swbp_insn(uprobe_opcode_t *insn)
13 {
14 #ifdef CONFIG_RISCV_ISA_C
15         return (*insn & 0xffff) == UPROBE_SWBP_INSN;
16 #else
17         return *insn == UPROBE_SWBP_INSN;
18 #endif
19 }
20
21 bool is_trap_insn(uprobe_opcode_t *insn)
22 {
23         return riscv_insn_is_ebreak(*insn) || riscv_insn_is_c_ebreak(*insn);
24 }
25
26 unsigned long uprobe_get_swbp_addr(struct pt_regs *regs)
27 {
28         return instruction_pointer(regs);
29 }
30
31 int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm,
32                              unsigned long addr)
33 {
34         probe_opcode_t opcode;
35
36         opcode = *(probe_opcode_t *)(&auprobe->insn[0]);
37
38         auprobe->insn_size = GET_INSN_LENGTH(opcode);
39
40         switch (riscv_probe_decode_insn(&opcode, &auprobe->api)) {
41         case INSN_REJECTED:
42                 return -EINVAL;
43
44         case INSN_GOOD_NO_SLOT:
45                 auprobe->simulate = true;
46                 break;
47
48         case INSN_GOOD:
49                 auprobe->simulate = false;
50                 break;
51
52         default:
53                 return -EINVAL;
54         }
55
56         return 0;
57 }
58
59 int arch_uprobe_pre_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
60 {
61         struct uprobe_task *utask = current->utask;
62
63         utask->autask.saved_cause = current->thread.bad_cause;
64         current->thread.bad_cause = UPROBE_TRAP_NR;
65
66         instruction_pointer_set(regs, utask->xol_vaddr);
67
68         return 0;
69 }
70
71 int arch_uprobe_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
72 {
73         struct uprobe_task *utask = current->utask;
74
75         WARN_ON_ONCE(current->thread.bad_cause != UPROBE_TRAP_NR);
76         current->thread.bad_cause = utask->autask.saved_cause;
77
78         instruction_pointer_set(regs, utask->vaddr + auprobe->insn_size);
79
80         return 0;
81 }
82
83 bool arch_uprobe_xol_was_trapped(struct task_struct *t)
84 {
85         if (t->thread.bad_cause != UPROBE_TRAP_NR)
86                 return true;
87
88         return false;
89 }
90
91 bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs)
92 {
93         probe_opcode_t insn;
94         unsigned long addr;
95
96         if (!auprobe->simulate)
97                 return false;
98
99         insn = *(probe_opcode_t *)(&auprobe->insn[0]);
100         addr = instruction_pointer(regs);
101
102         if (auprobe->api.handler)
103                 auprobe->api.handler(insn, addr, regs);
104
105         return true;
106 }
107
108 void arch_uprobe_abort_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
109 {
110         struct uprobe_task *utask = current->utask;
111
112         current->thread.bad_cause = utask->autask.saved_cause;
113         /*
114          * Task has received a fatal signal, so reset back to probbed
115          * address.
116          */
117         instruction_pointer_set(regs, utask->vaddr);
118 }
119
120 bool arch_uretprobe_is_alive(struct return_instance *ret, enum rp_check ctx,
121                 struct pt_regs *regs)
122 {
123         if (ctx == RP_CHECK_CHAIN_CALL)
124                 return regs->sp <= ret->stack;
125         else
126                 return regs->sp < ret->stack;
127 }
128
129 unsigned long
130 arch_uretprobe_hijack_return_addr(unsigned long trampoline_vaddr,
131                                   struct pt_regs *regs)
132 {
133         unsigned long ra;
134
135         ra = regs->ra;
136
137         regs->ra = trampoline_vaddr;
138
139         return ra;
140 }
141
142 int arch_uprobe_exception_notify(struct notifier_block *self,
143                                  unsigned long val, void *data)
144 {
145         return NOTIFY_DONE;
146 }
147
148 bool uprobe_breakpoint_handler(struct pt_regs *regs)
149 {
150         if (uprobe_pre_sstep_notifier(regs))
151                 return true;
152
153         return false;
154 }
155
156 bool uprobe_single_step_handler(struct pt_regs *regs)
157 {
158         if (uprobe_post_sstep_notifier(regs))
159                 return true;
160
161         return false;
162 }
163
164 void arch_uprobe_copy_ixol(struct page *page, unsigned long vaddr,
165                            void *src, unsigned long len)
166 {
167         /* Initialize the slot */
168         void *kaddr = kmap_atomic(page);
169         void *dst = kaddr + (vaddr & ~PAGE_MASK);
170
171         memcpy(dst, src, len);
172
173         /* Add ebreak behind opcode to simulate singlestep */
174         if (vaddr) {
175                 dst += GET_INSN_LENGTH(*(probe_opcode_t *)src);
176                 *(uprobe_opcode_t *)dst = __BUG_INSN_32;
177         }
178
179         kunmap_atomic(kaddr);
180
181         /*
182          * We probably need flush_icache_user_page() but it needs vma.
183          * This should work on most of architectures by default. If
184          * architecture needs to do something different it can define
185          * its own version of the function.
186          */
187         flush_dcache_page(page);
188 }