1
2
3
4
5
6
7
8
9
10
11
12
13
14
15#include <linux/kprobes.h>
16#include <linux/kdebug.h>
17#include <linux/module.h>
18#include <linux/ptrace.h>
19#include <linux/sched.h>
20#include <linux/mm.h>
21#include <linux/slab.h>
22#include <asm/switch_to.h>
23#include "entry.h"
24
25int show_unhandled_signals = 1;
26
27static inline void __user *get_trap_ip(struct pt_regs *regs)
28{
29#ifdef CONFIG_64BIT
30 unsigned long address;
31
32 if (regs->int_code & 0x200)
33 address = *(unsigned long *)(current->thread.trap_tdb + 24);
34 else
35 address = regs->psw.addr;
36 return (void __user *)
37 ((address - (regs->int_code >> 16)) & PSW_ADDR_INSN);
38#else
39 return (void __user *)
40 ((regs->psw.addr - (regs->int_code >> 16)) & PSW_ADDR_INSN);
41#endif
42}
43
44static inline void report_user_fault(struct pt_regs *regs, int signr)
45{
46 if ((task_pid_nr(current) > 1) && !show_unhandled_signals)
47 return;
48 if (!unhandled_signal(current, signr))
49 return;
50 if (!printk_ratelimit())
51 return;
52 printk("User process fault: interruption code %04x ilc:%d ",
53 regs->int_code & 0xffff, regs->int_code >> 17);
54 print_vma_addr("in ", regs->psw.addr & PSW_ADDR_INSN);
55 printk("\n");
56 show_regs(regs);
57}
58
59int is_valid_bugaddr(unsigned long addr)
60{
61 return 1;
62}
63
64void do_report_trap(struct pt_regs *regs, int si_signo, int si_code, char *str)
65{
66 siginfo_t info;
67
68 if (user_mode(regs)) {
69 info.si_signo = si_signo;
70 info.si_errno = 0;
71 info.si_code = si_code;
72 info.si_addr = get_trap_ip(regs);
73 force_sig_info(si_signo, &info, current);
74 report_user_fault(regs, si_signo);
75 } else {
76 const struct exception_table_entry *fixup;
77 fixup = search_exception_tables(regs->psw.addr & PSW_ADDR_INSN);
78 if (fixup)
79 regs->psw.addr = extable_fixup(fixup) | PSW_ADDR_AMODE;
80 else {
81 enum bug_trap_type btt;
82
83 btt = report_bug(regs->psw.addr & PSW_ADDR_INSN, regs);
84 if (btt == BUG_TRAP_TYPE_WARN)
85 return;
86 die(regs, str);
87 }
88 }
89}
90
91static void do_trap(struct pt_regs *regs, int si_signo, int si_code, char *str)
92{
93 if (notify_die(DIE_TRAP, str, regs, 0,
94 regs->int_code, si_signo) == NOTIFY_STOP)
95 return;
96 do_report_trap(regs, si_signo, si_code, str);
97}
98NOKPROBE_SYMBOL(do_trap);
99
100void do_per_trap(struct pt_regs *regs)
101{
102 siginfo_t info;
103
104 if (notify_die(DIE_SSTEP, "sstep", regs, 0, 0, SIGTRAP) == NOTIFY_STOP)
105 return;
106 if (!current->ptrace)
107 return;
108 info.si_signo = SIGTRAP;
109 info.si_errno = 0;
110 info.si_code = TRAP_HWBKPT;
111 info.si_addr =
112 (void __force __user *) current->thread.per_event.address;
113 force_sig_info(SIGTRAP, &info, current);
114}
115NOKPROBE_SYMBOL(do_per_trap);
116
117void default_trap_handler(struct pt_regs *regs)
118{
119 if (user_mode(regs)) {
120 report_user_fault(regs, SIGSEGV);
121 do_exit(SIGSEGV);
122 } else
123 die(regs, "Unknown program exception");
124}
125
126#define DO_ERROR_INFO(name, signr, sicode, str) \
127void name(struct pt_regs *regs) \
128{ \
129 do_trap(regs, signr, sicode, str); \
130}
131
132DO_ERROR_INFO(addressing_exception, SIGILL, ILL_ILLADR,
133 "addressing exception")
134DO_ERROR_INFO(execute_exception, SIGILL, ILL_ILLOPN,
135 "execute exception")
136DO_ERROR_INFO(divide_exception, SIGFPE, FPE_INTDIV,
137 "fixpoint divide exception")
138DO_ERROR_INFO(overflow_exception, SIGFPE, FPE_INTOVF,
139 "fixpoint overflow exception")
140DO_ERROR_INFO(hfp_overflow_exception, SIGFPE, FPE_FLTOVF,
141 "HFP overflow exception")
142DO_ERROR_INFO(hfp_underflow_exception, SIGFPE, FPE_FLTUND,
143 "HFP underflow exception")
144DO_ERROR_INFO(hfp_significance_exception, SIGFPE, FPE_FLTRES,
145 "HFP significance exception")
146DO_ERROR_INFO(hfp_divide_exception, SIGFPE, FPE_FLTDIV,
147 "HFP divide exception")
148DO_ERROR_INFO(hfp_sqrt_exception, SIGFPE, FPE_FLTINV,
149 "HFP square root exception")
150DO_ERROR_INFO(operand_exception, SIGILL, ILL_ILLOPN,
151 "operand exception")
152DO_ERROR_INFO(privileged_op, SIGILL, ILL_PRVOPC,
153 "privileged operation")
154DO_ERROR_INFO(special_op_exception, SIGILL, ILL_ILLOPN,
155 "special operation exception")
156
157#ifdef CONFIG_64BIT
158DO_ERROR_INFO(transaction_exception, SIGILL, ILL_ILLOPN,
159 "transaction constraint exception")
160#endif
161
162static inline void do_fp_trap(struct pt_regs *regs, int fpc)
163{
164 int si_code = 0;
165
166 if ((fpc & 0x00000300) == 0) {
167
168 if (fpc & 0x8000)
169 si_code = FPE_FLTINV;
170 else if (fpc & 0x4000)
171 si_code = FPE_FLTDIV;
172 else if (fpc & 0x2000)
173 si_code = FPE_FLTOVF;
174 else if (fpc & 0x1000)
175 si_code = FPE_FLTUND;
176 else if (fpc & 0x0800)
177 si_code = FPE_FLTRES;
178 }
179 do_trap(regs, SIGFPE, si_code, "floating point exception");
180}
181
182void translation_exception(struct pt_regs *regs)
183{
184
185 die(regs, "Translation exception");
186}
187
188void illegal_op(struct pt_regs *regs)
189{
190 siginfo_t info;
191 __u8 opcode[6];
192 __u16 __user *location;
193 int is_uprobe_insn = 0;
194 int signal = 0;
195
196 location = get_trap_ip(regs);
197
198 if (user_mode(regs)) {
199 if (get_user(*((__u16 *) opcode), (__u16 __user *) location))
200 return;
201 if (*((__u16 *) opcode) == S390_BREAKPOINT_U16) {
202 if (current->ptrace) {
203 info.si_signo = SIGTRAP;
204 info.si_errno = 0;
205 info.si_code = TRAP_BRKPT;
206 info.si_addr = location;
207 force_sig_info(SIGTRAP, &info, current);
208 } else
209 signal = SIGILL;
210#ifdef CONFIG_UPROBES
211 } else if (*((__u16 *) opcode) == UPROBE_SWBP_INSN) {
212 is_uprobe_insn = 1;
213#endif
214#ifdef CONFIG_MATHEMU
215 } else if (opcode[0] == 0xb3) {
216 if (get_user(*((__u16 *) (opcode+2)), location+1))
217 return;
218 signal = math_emu_b3(opcode, regs);
219 } else if (opcode[0] == 0xed) {
220 if (get_user(*((__u32 *) (opcode+2)),
221 (__u32 __user *)(location+1)))
222 return;
223 signal = math_emu_ed(opcode, regs);
224 } else if (*((__u16 *) opcode) == 0xb299) {
225 if (get_user(*((__u16 *) (opcode+2)), location+1))
226 return;
227 signal = math_emu_srnm(opcode, regs);
228 } else if (*((__u16 *) opcode) == 0xb29c) {
229 if (get_user(*((__u16 *) (opcode+2)), location+1))
230 return;
231 signal = math_emu_stfpc(opcode, regs);
232 } else if (*((__u16 *) opcode) == 0xb29d) {
233 if (get_user(*((__u16 *) (opcode+2)), location+1))
234 return;
235 signal = math_emu_lfpc(opcode, regs);
236#endif
237 } else
238 signal = SIGILL;
239 }
240
241
242
243
244
245 if (is_uprobe_insn || !user_mode(regs)) {
246 if (notify_die(DIE_BPT, "bpt", regs, 0,
247 3, SIGTRAP) != NOTIFY_STOP)
248 signal = SIGILL;
249 }
250
251#ifdef CONFIG_MATHEMU
252 if (signal == SIGFPE)
253 do_fp_trap(regs, current->thread.fp_regs.fpc);
254 else if (signal == SIGSEGV)
255 do_trap(regs, signal, SEGV_MAPERR, "user address fault");
256 else
257#endif
258 if (signal)
259 do_trap(regs, signal, ILL_ILLOPC, "illegal operation");
260}
261NOKPROBE_SYMBOL(illegal_op);
262
263#ifdef CONFIG_MATHEMU
264void specification_exception(struct pt_regs *regs)
265{
266 __u8 opcode[6];
267 __u16 __user *location = NULL;
268 int signal = 0;
269
270 location = (__u16 __user *) get_trap_ip(regs);
271
272 if (user_mode(regs)) {
273 get_user(*((__u16 *) opcode), location);
274 switch (opcode[0]) {
275 case 0x28:
276 signal = math_emu_ldr(opcode);
277 break;
278 case 0x38:
279 signal = math_emu_ler(opcode);
280 break;
281 case 0x60:
282 get_user(*((__u16 *) (opcode+2)), location+1);
283 signal = math_emu_std(opcode, regs);
284 break;
285 case 0x68:
286 get_user(*((__u16 *) (opcode+2)), location+1);
287 signal = math_emu_ld(opcode, regs);
288 break;
289 case 0x70:
290 get_user(*((__u16 *) (opcode+2)), location+1);
291 signal = math_emu_ste(opcode, regs);
292 break;
293 case 0x78:
294 get_user(*((__u16 *) (opcode+2)), location+1);
295 signal = math_emu_le(opcode, regs);
296 break;
297 default:
298 signal = SIGILL;
299 break;
300 }
301 } else
302 signal = SIGILL;
303
304 if (signal == SIGFPE)
305 do_fp_trap(regs, current->thread.fp_regs.fpc);
306 else if (signal)
307 do_trap(regs, signal, ILL_ILLOPN, "specification exception");
308}
309#else
310DO_ERROR_INFO(specification_exception, SIGILL, ILL_ILLOPN,
311 "specification exception");
312#endif
313
314#ifdef CONFIG_64BIT
315int alloc_vector_registers(struct task_struct *tsk)
316{
317 __vector128 *vxrs;
318 int i;
319
320
321 vxrs = kzalloc(sizeof(__vector128) * __NUM_VXRS,
322 GFP_KERNEL|__GFP_REPEAT);
323 if (!vxrs)
324 return -ENOMEM;
325 preempt_disable();
326 if (tsk == current)
327 save_fp_regs(tsk->thread.fp_regs.fprs);
328
329 for (i = 0; i < 16; i++)
330 *(freg_t *) &vxrs[i] = tsk->thread.fp_regs.fprs[i];
331 tsk->thread.vxrs = vxrs;
332 if (tsk == current) {
333 __ctl_set_bit(0, 17);
334 restore_vx_regs(vxrs);
335 }
336 preempt_enable();
337 return 0;
338}
339
340void vector_exception(struct pt_regs *regs)
341{
342 int si_code, vic;
343
344 if (!MACHINE_HAS_VX) {
345 do_trap(regs, SIGILL, ILL_ILLOPN, "illegal operation");
346 return;
347 }
348
349
350 asm volatile("stfpc %0" : "=m" (current->thread.fp_regs.fpc));
351 vic = (current->thread.fp_regs.fpc & 0xf00) >> 8;
352 switch (vic) {
353 case 1:
354 si_code = FPE_FLTINV;
355 break;
356 case 2:
357 si_code = FPE_FLTDIV;
358 break;
359 case 3:
360 si_code = FPE_FLTOVF;
361 break;
362 case 4:
363 si_code = FPE_FLTUND;
364 break;
365 case 5:
366 si_code = FPE_FLTRES;
367 break;
368 default:
369 si_code = 0;
370 }
371 do_trap(regs, SIGFPE, si_code, "vector exception");
372}
373
374static int __init disable_vector_extension(char *str)
375{
376 S390_lowcore.machine_flags &= ~MACHINE_FLAG_VX;
377 return 1;
378}
379__setup("novx", disable_vector_extension);
380#endif
381
382void data_exception(struct pt_regs *regs)
383{
384 __u16 __user *location;
385 int signal = 0;
386
387 location = get_trap_ip(regs);
388
389 if (MACHINE_HAS_IEEE)
390 asm volatile("stfpc %0" : "=m" (current->thread.fp_regs.fpc));
391
392#ifdef CONFIG_MATHEMU
393 else if (user_mode(regs)) {
394 __u8 opcode[6];
395 get_user(*((__u16 *) opcode), location);
396 switch (opcode[0]) {
397 case 0x28:
398 signal = math_emu_ldr(opcode);
399 break;
400 case 0x38:
401 signal = math_emu_ler(opcode);
402 break;
403 case 0x60:
404 get_user(*((__u16 *) (opcode+2)), location+1);
405 signal = math_emu_std(opcode, regs);
406 break;
407 case 0x68:
408 get_user(*((__u16 *) (opcode+2)), location+1);
409 signal = math_emu_ld(opcode, regs);
410 break;
411 case 0x70:
412 get_user(*((__u16 *) (opcode+2)), location+1);
413 signal = math_emu_ste(opcode, regs);
414 break;
415 case 0x78:
416 get_user(*((__u16 *) (opcode+2)), location+1);
417 signal = math_emu_le(opcode, regs);
418 break;
419 case 0xb3:
420 get_user(*((__u16 *) (opcode+2)), location+1);
421 signal = math_emu_b3(opcode, regs);
422 break;
423 case 0xed:
424 get_user(*((__u32 *) (opcode+2)),
425 (__u32 __user *)(location+1));
426 signal = math_emu_ed(opcode, regs);
427 break;
428 case 0xb2:
429 if (opcode[1] == 0x99) {
430 get_user(*((__u16 *) (opcode+2)), location+1);
431 signal = math_emu_srnm(opcode, regs);
432 } else if (opcode[1] == 0x9c) {
433 get_user(*((__u16 *) (opcode+2)), location+1);
434 signal = math_emu_stfpc(opcode, regs);
435 } else if (opcode[1] == 0x9d) {
436 get_user(*((__u16 *) (opcode+2)), location+1);
437 signal = math_emu_lfpc(opcode, regs);
438 } else
439 signal = SIGILL;
440 break;
441 default:
442 signal = SIGILL;
443 break;
444 }
445 }
446#endif
447#ifdef CONFIG_64BIT
448
449 if (MACHINE_HAS_VX && !current->thread.vxrs &&
450 (current->thread.fp_regs.fpc & FPC_DXC_MASK) == 0xfe00) {
451 alloc_vector_registers(current);
452
453 regs->psw.addr = __rewind_psw(regs->psw, regs->int_code >> 16);
454 clear_pt_regs_flag(regs, PIF_PER_TRAP);
455 return;
456 }
457#endif
458
459 if (current->thread.fp_regs.fpc & FPC_DXC_MASK)
460 signal = SIGFPE;
461 else
462 signal = SIGILL;
463 if (signal == SIGFPE)
464 do_fp_trap(regs, current->thread.fp_regs.fpc);
465 else if (signal)
466 do_trap(regs, signal, ILL_ILLOPN, "data exception");
467}
468
469void space_switch_exception(struct pt_regs *regs)
470{
471
472 if (user_mode(regs))
473 regs->psw.mask |= PSW_ASC_HOME;
474
475 do_trap(regs, SIGILL, ILL_PRVOPC, "space switch event");
476}
477
478void kernel_stack_overflow(struct pt_regs *regs)
479{
480 bust_spinlocks(1);
481 printk("Kernel stack overflow.\n");
482 show_regs(regs);
483 bust_spinlocks(0);
484 panic("Corrupt kernel stack, can't continue.");
485}
486NOKPROBE_SYMBOL(kernel_stack_overflow);
487
488void __init trap_init(void)
489{
490 local_mcck_enable();
491}
492