]>
Commit | Line | Data |
---|---|---|
2a0a5b22 JW |
1 | /* |
2 | * User-space Probes (UProbes) for s390 | |
3 | * | |
4 | * Copyright IBM Corp. 2014 | |
5 | * Author(s): Jan Willeke, | |
6 | */ | |
7 | ||
2a0a5b22 JW |
8 | #include <linux/uaccess.h> |
9 | #include <linux/uprobes.h> | |
10 | #include <linux/compat.h> | |
11 | #include <linux/kdebug.h> | |
12 | #include <asm/switch_to.h> | |
13 | #include <asm/facility.h> | |
d6fe5be3 | 14 | #include <asm/kprobes.h> |
2a0a5b22 JW |
15 | #include <asm/dis.h> |
16 | #include "entry.h" | |
17 | ||
18 | #define UPROBE_TRAP_NR UINT_MAX | |
19 | ||
20 | int arch_uprobe_analyze_insn(struct arch_uprobe *auprobe, struct mm_struct *mm, | |
21 | unsigned long addr) | |
22 | { | |
23 | return probe_is_prohibited_opcode(auprobe->insn); | |
24 | } | |
25 | ||
26 | int arch_uprobe_pre_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) | |
27 | { | |
28 | if (psw_bits(regs->psw).eaba == PSW_AMODE_24BIT) | |
29 | return -EINVAL; | |
30 | if (!is_compat_task() && psw_bits(regs->psw).eaba == PSW_AMODE_31BIT) | |
31 | return -EINVAL; | |
32 | clear_pt_regs_flag(regs, PIF_PER_TRAP); | |
33 | auprobe->saved_per = psw_bits(regs->psw).r; | |
34 | auprobe->saved_int_code = regs->int_code; | |
35 | regs->int_code = UPROBE_TRAP_NR; | |
36 | regs->psw.addr = current->utask->xol_vaddr; | |
37 | set_tsk_thread_flag(current, TIF_UPROBE_SINGLESTEP); | |
38 | update_cr_regs(current); | |
39 | return 0; | |
40 | } | |
41 | ||
42 | bool arch_uprobe_xol_was_trapped(struct task_struct *tsk) | |
43 | { | |
44 | struct pt_regs *regs = task_pt_regs(tsk); | |
45 | ||
46 | if (regs->int_code != UPROBE_TRAP_NR) | |
47 | return true; | |
48 | return false; | |
49 | } | |
50 | ||
51 | int arch_uprobe_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) | |
52 | { | |
53 | int fixup = probe_get_fixup_type(auprobe->insn); | |
54 | struct uprobe_task *utask = current->utask; | |
55 | ||
56 | clear_tsk_thread_flag(current, TIF_UPROBE_SINGLESTEP); | |
57 | update_cr_regs(current); | |
58 | psw_bits(regs->psw).r = auprobe->saved_per; | |
59 | regs->int_code = auprobe->saved_int_code; | |
60 | ||
61 | if (fixup & FIXUP_PSW_NORMAL) | |
62 | regs->psw.addr += utask->vaddr - utask->xol_vaddr; | |
63 | if (fixup & FIXUP_RETURN_REGISTER) { | |
64 | int reg = (auprobe->insn[0] & 0xf0) >> 4; | |
65 | ||
66 | regs->gprs[reg] += utask->vaddr - utask->xol_vaddr; | |
67 | } | |
68 | if (fixup & FIXUP_BRANCH_NOT_TAKEN) { | |
69 | int ilen = insn_length(auprobe->insn[0] >> 8); | |
70 | ||
71 | if (regs->psw.addr - utask->xol_vaddr == ilen) | |
72 | regs->psw.addr = utask->vaddr + ilen; | |
73 | } | |
74 | /* If per tracing was active generate trap */ | |
75 | if (regs->psw.mask & PSW_MASK_PER) | |
76 | do_per_trap(regs); | |
77 | return 0; | |
78 | } | |
79 | ||
80 | int arch_uprobe_exception_notify(struct notifier_block *self, unsigned long val, | |
81 | void *data) | |
82 | { | |
83 | struct die_args *args = data; | |
84 | struct pt_regs *regs = args->regs; | |
85 | ||
86 | if (!user_mode(regs)) | |
87 | return NOTIFY_DONE; | |
88 | if (regs->int_code & 0x200) /* Trap during transaction */ | |
89 | return NOTIFY_DONE; | |
90 | switch (val) { | |
91 | case DIE_BPT: | |
92 | if (uprobe_pre_sstep_notifier(regs)) | |
93 | return NOTIFY_STOP; | |
94 | break; | |
95 | case DIE_SSTEP: | |
96 | if (uprobe_post_sstep_notifier(regs)) | |
97 | return NOTIFY_STOP; | |
98 | default: | |
99 | break; | |
100 | } | |
101 | return NOTIFY_DONE; | |
102 | } | |
103 | ||
104 | void arch_uprobe_abort_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) | |
105 | { | |
106 | clear_thread_flag(TIF_UPROBE_SINGLESTEP); | |
107 | regs->int_code = auprobe->saved_int_code; | |
108 | regs->psw.addr = current->utask->vaddr; | |
109 | } | |
110 | ||
111 | unsigned long arch_uretprobe_hijack_return_addr(unsigned long trampoline, | |
112 | struct pt_regs *regs) | |
113 | { | |
114 | unsigned long orig; | |
115 | ||
116 | orig = regs->gprs[14]; | |
117 | regs->gprs[14] = trampoline; | |
118 | return orig; | |
119 | } | |
120 | ||
121 | /* Instruction Emulation */ | |
122 | ||
123 | static void adjust_psw_addr(psw_t *psw, unsigned long len) | |
124 | { | |
125 | psw->addr = __rewind_psw(*psw, -len); | |
126 | } | |
127 | ||
128 | #define EMU_ILLEGAL_OP 1 | |
129 | #define EMU_SPECIFICATION 2 | |
130 | #define EMU_ADDRESSING 3 | |
131 | ||
132 | #define emu_load_ril(ptr, output) \ | |
133 | ({ \ | |
134 | unsigned int mask = sizeof(*(ptr)) - 1; \ | |
135 | __typeof__(*(ptr)) input; \ | |
136 | int __rc = 0; \ | |
137 | \ | |
138 | if (!test_facility(34)) \ | |
139 | __rc = EMU_ILLEGAL_OP; \ | |
140 | else if ((u64 __force)ptr & mask) \ | |
141 | __rc = EMU_SPECIFICATION; \ | |
142 | else if (get_user(input, ptr)) \ | |
143 | __rc = EMU_ADDRESSING; \ | |
144 | else \ | |
145 | *(output) = input; \ | |
146 | __rc; \ | |
147 | }) | |
148 | ||
149 | #define emu_store_ril(ptr, input) \ | |
150 | ({ \ | |
151 | unsigned int mask = sizeof(*(ptr)) - 1; \ | |
152 | int __rc = 0; \ | |
153 | \ | |
154 | if (!test_facility(34)) \ | |
155 | __rc = EMU_ILLEGAL_OP; \ | |
156 | else if ((u64 __force)ptr & mask) \ | |
157 | __rc = EMU_SPECIFICATION; \ | |
158 | else if (put_user(*(input), ptr)) \ | |
159 | __rc = EMU_ADDRESSING; \ | |
160 | __rc; \ | |
161 | }) | |
162 | ||
163 | #define emu_cmp_ril(regs, ptr, cmp) \ | |
164 | ({ \ | |
165 | unsigned int mask = sizeof(*(ptr)) - 1; \ | |
166 | __typeof__(*(ptr)) input; \ | |
167 | int __rc = 0; \ | |
168 | \ | |
169 | if (!test_facility(34)) \ | |
170 | __rc = EMU_ILLEGAL_OP; \ | |
171 | else if ((u64 __force)ptr & mask) \ | |
172 | __rc = EMU_SPECIFICATION; \ | |
173 | else if (get_user(input, ptr)) \ | |
174 | __rc = EMU_ADDRESSING; \ | |
175 | else if (input > *(cmp)) \ | |
176 | psw_bits((regs)->psw).cc = 1; \ | |
177 | else if (input < *(cmp)) \ | |
178 | psw_bits((regs)->psw).cc = 2; \ | |
179 | else \ | |
180 | psw_bits((regs)->psw).cc = 0; \ | |
181 | __rc; \ | |
182 | }) | |
183 | ||
184 | struct insn_ril { | |
185 | u8 opc0; | |
186 | u8 reg : 4; | |
187 | u8 opc1 : 4; | |
188 | s32 disp; | |
189 | } __packed; | |
190 | ||
191 | union split_register { | |
192 | u64 u64; | |
193 | u32 u32[2]; | |
194 | u16 u16[4]; | |
195 | s64 s64; | |
196 | s32 s32[2]; | |
197 | s16 s16[4]; | |
198 | }; | |
199 | ||
200 | /* | |
201 | * pc relative instructions are emulated, since parameters may not be | |
202 | * accessible from the xol area due to range limitations. | |
203 | */ | |
204 | static void handle_insn_ril(struct arch_uprobe *auprobe, struct pt_regs *regs) | |
205 | { | |
206 | union split_register *rx; | |
207 | struct insn_ril *insn; | |
208 | unsigned int ilen; | |
209 | void *uptr; | |
210 | int rc = 0; | |
211 | ||
212 | insn = (struct insn_ril *) &auprobe->insn; | |
213 | rx = (union split_register *) ®s->gprs[insn->reg]; | |
214 | uptr = (void *)(regs->psw.addr + (insn->disp * 2)); | |
215 | ilen = insn_length(insn->opc0); | |
216 | ||
217 | switch (insn->opc0) { | |
218 | case 0xc0: | |
219 | switch (insn->opc1) { | |
220 | case 0x00: /* larl */ | |
221 | rx->u64 = (unsigned long)uptr; | |
222 | break; | |
223 | } | |
224 | break; | |
225 | case 0xc4: | |
226 | switch (insn->opc1) { | |
227 | case 0x02: /* llhrl */ | |
228 | rc = emu_load_ril((u16 __user *)uptr, &rx->u32[1]); | |
229 | break; | |
230 | case 0x04: /* lghrl */ | |
231 | rc = emu_load_ril((s16 __user *)uptr, &rx->u64); | |
232 | break; | |
233 | case 0x05: /* lhrl */ | |
234 | rc = emu_load_ril((s16 __user *)uptr, &rx->u32[1]); | |
235 | break; | |
236 | case 0x06: /* llghrl */ | |
237 | rc = emu_load_ril((u16 __user *)uptr, &rx->u64); | |
238 | break; | |
239 | case 0x08: /* lgrl */ | |
240 | rc = emu_load_ril((u64 __user *)uptr, &rx->u64); | |
241 | break; | |
242 | case 0x0c: /* lgfrl */ | |
243 | rc = emu_load_ril((s32 __user *)uptr, &rx->u64); | |
244 | break; | |
245 | case 0x0d: /* lrl */ | |
246 | rc = emu_load_ril((u32 __user *)uptr, &rx->u32[1]); | |
247 | break; | |
248 | case 0x0e: /* llgfrl */ | |
249 | rc = emu_load_ril((u32 __user *)uptr, &rx->u64); | |
250 | break; | |
251 | case 0x07: /* sthrl */ | |
252 | rc = emu_store_ril((u16 __user *)uptr, &rx->u16[3]); | |
253 | break; | |
254 | case 0x0b: /* stgrl */ | |
255 | rc = emu_store_ril((u64 __user *)uptr, &rx->u64); | |
256 | break; | |
257 | case 0x0f: /* strl */ | |
258 | rc = emu_store_ril((u32 __user *)uptr, &rx->u32[1]); | |
259 | break; | |
260 | } | |
261 | break; | |
262 | case 0xc6: | |
263 | switch (insn->opc1) { | |
264 | case 0x02: /* pfdrl */ | |
265 | if (!test_facility(34)) | |
266 | rc = EMU_ILLEGAL_OP; | |
267 | break; | |
268 | case 0x04: /* cghrl */ | |
269 | rc = emu_cmp_ril(regs, (s16 __user *)uptr, &rx->s64); | |
270 | break; | |
271 | case 0x05: /* chrl */ | |
272 | rc = emu_cmp_ril(regs, (s16 __user *)uptr, &rx->s32[1]); | |
273 | break; | |
274 | case 0x06: /* clghrl */ | |
275 | rc = emu_cmp_ril(regs, (u16 __user *)uptr, &rx->u64); | |
276 | break; | |
277 | case 0x07: /* clhrl */ | |
278 | rc = emu_cmp_ril(regs, (u16 __user *)uptr, &rx->u32[1]); | |
279 | break; | |
280 | case 0x08: /* cgrl */ | |
281 | rc = emu_cmp_ril(regs, (s64 __user *)uptr, &rx->s64); | |
282 | break; | |
283 | case 0x0a: /* clgrl */ | |
284 | rc = emu_cmp_ril(regs, (u64 __user *)uptr, &rx->u64); | |
285 | break; | |
286 | case 0x0c: /* cgfrl */ | |
287 | rc = emu_cmp_ril(regs, (s32 __user *)uptr, &rx->s64); | |
288 | break; | |
289 | case 0x0d: /* crl */ | |
290 | rc = emu_cmp_ril(regs, (s32 __user *)uptr, &rx->s32[1]); | |
291 | break; | |
292 | case 0x0e: /* clgfrl */ | |
293 | rc = emu_cmp_ril(regs, (u32 __user *)uptr, &rx->u64); | |
294 | break; | |
295 | case 0x0f: /* clrl */ | |
296 | rc = emu_cmp_ril(regs, (u32 __user *)uptr, &rx->u32[1]); | |
297 | break; | |
298 | } | |
299 | break; | |
300 | } | |
301 | adjust_psw_addr(®s->psw, ilen); | |
302 | switch (rc) { | |
303 | case EMU_ILLEGAL_OP: | |
304 | regs->int_code = ilen << 16 | 0x0001; | |
305 | do_report_trap(regs, SIGILL, ILL_ILLOPC, NULL); | |
306 | break; | |
307 | case EMU_SPECIFICATION: | |
308 | regs->int_code = ilen << 16 | 0x0006; | |
309 | do_report_trap(regs, SIGILL, ILL_ILLOPC , NULL); | |
310 | break; | |
311 | case EMU_ADDRESSING: | |
312 | regs->int_code = ilen << 16 | 0x0005; | |
313 | do_report_trap(regs, SIGSEGV, SEGV_MAPERR, NULL); | |
314 | break; | |
315 | } | |
316 | } | |
317 | ||
318 | bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs) | |
319 | { | |
320 | if ((psw_bits(regs->psw).eaba == PSW_AMODE_24BIT) || | |
321 | ((psw_bits(regs->psw).eaba == PSW_AMODE_31BIT) && | |
322 | !is_compat_task())) { | |
323 | regs->psw.addr = __rewind_psw(regs->psw, UPROBE_SWBP_INSN_SIZE); | |
324 | do_report_trap(regs, SIGILL, ILL_ILLADR, NULL); | |
325 | return true; | |
326 | } | |
327 | if (probe_is_insn_relative_long(auprobe->insn)) { | |
328 | handle_insn_ril(auprobe, regs); | |
329 | return true; | |
330 | } | |
331 | return false; | |
332 | } |