1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17#include <linux/config.h>
18#include <linux/sched.h>
19#include <linux/kernel.h>
20#include <linux/string.h>
21#include <linux/errno.h>
22#include <linux/ptrace.h>
23#include <linux/timer.h>
24#include <linux/mm.h>
25#include <linux/smp.h>
26#include <linux/smp_lock.h>
27#include <linux/init.h>
28#include <linux/delay.h>
29#include <linux/module.h>
30
31#include <asm/system.h>
32#include <asm/uaccess.h>
33#include <asm/io.h>
34#include <asm/atomic.h>
35#include <asm/mathemu.h>
36#include <asm/cpcmd.h>
37#include <asm/s390_ext.h>
38
39
40extern void handle_per_exception(struct pt_regs *regs);
41
42typedef void pgm_check_handler_t(struct pt_regs *, long);
43pgm_check_handler_t *pgm_check_table[128];
44
45#ifdef CONFIG_SYSCTL
46#ifdef CONFIG_PROCESS_DEBUG
47int sysctl_userprocess_debug = 1;
48#else
49int sysctl_userprocess_debug = 0;
50#endif
51#endif
52
53extern pgm_check_handler_t do_protection_exception;
54extern pgm_check_handler_t do_segment_exception;
55extern pgm_check_handler_t do_page_exception;
56extern pgm_check_handler_t do_pseudo_page_fault;
57#ifdef CONFIG_PFAULT
58extern int pfault_init(void);
59extern void pfault_fini(void);
60extern void pfault_interrupt(struct pt_regs *regs, __u16 error_code);
61static ext_int_info_t ext_int_pfault;
62#endif
63
64int kstack_depth_to_print = 12;
65
66
67
68
69
70
71extern char _stext, _etext;
72
73#ifdef CONFIG_MODULES
74
75extern struct module *module_list;
76extern struct module kernel_module;
77
78static inline int kernel_text_address(unsigned long addr)
79{
80 int retval = 0;
81 struct module *mod;
82
83 if (addr >= (unsigned long) &_stext &&
84 addr <= (unsigned long) &_etext)
85 return 1;
86
87 for (mod = module_list; mod != &kernel_module; mod = mod->next) {
88
89
90
91 if (mod_bound(addr, 0, mod)) {
92 retval = 1;
93 break;
94 }
95 }
96
97 return retval;
98}
99
100#else
101
102static inline int kernel_text_address(unsigned long addr)
103{
104 return (addr >= (unsigned long) &_stext &&
105 addr <= (unsigned long) &_etext);
106}
107
108#endif
109
110void show_trace(unsigned long * stack)
111{
112 unsigned long backchain, low_addr, high_addr, ret_addr;
113 int i;
114
115 if (!stack)
116 stack = (unsigned long*)&stack;
117
118 printk("Call Trace: ");
119 low_addr = ((unsigned long) stack) & PSW_ADDR_MASK;
120 high_addr = (low_addr & (-THREAD_SIZE)) + THREAD_SIZE;
121
122 backchain = *((unsigned long *) low_addr) & PSW_ADDR_MASK;
123
124 for (i = 0; i < 8; i++) {
125 if (backchain < low_addr || backchain >= high_addr)
126 break;
127 ret_addr = *((unsigned long *) (backchain+56)) & PSW_ADDR_MASK;
128 if (!kernel_text_address(ret_addr))
129 break;
130 if (i && ((i % 6) == 0))
131 printk("\n ");
132 printk("[<%08lx>] ", ret_addr);
133 low_addr = backchain;
134 backchain = *((unsigned long *) backchain) & PSW_ADDR_MASK;
135 }
136 printk("\n");
137}
138
139void show_trace_task(struct task_struct *tsk)
140{
141
142
143
144
145 if (task_has_cpu(tsk))
146 return;
147 show_trace((unsigned long *) tsk->thread.ksp);
148}
149
150void show_stack(unsigned long *sp)
151{
152 unsigned long *stack;
153 int i;
154
155
156
157
158 if(sp == NULL)
159 sp = (unsigned long*) &sp;
160
161 stack = sp;
162 for (i = 0; i < kstack_depth_to_print; i++) {
163 if (((addr_t) stack & (THREAD_SIZE-1)) == 0)
164 break;
165 if (i && ((i % 8) == 0))
166 printk("\n ");
167 printk("%08lx ", *stack++);
168 }
169 printk("\n");
170 show_trace(sp);
171}
172
173void show_registers(struct pt_regs *regs)
174{
175 mm_segment_t old_fs;
176 char *mode;
177 int i;
178
179 mode = (regs->psw.mask & PSW_PROBLEM_STATE) ? "User" : "Krnl";
180 printk("%s PSW : %08lx %08lx\n",
181 mode, (unsigned long) regs->psw.mask,
182 (unsigned long) regs->psw.addr);
183 printk("%s GPRS: %08x %08x %08x %08x\n", mode,
184 regs->gprs[0], regs->gprs[1], regs->gprs[2], regs->gprs[3]);
185 printk(" %08x %08x %08x %08x\n",
186 regs->gprs[4], regs->gprs[5], regs->gprs[6], regs->gprs[7]);
187 printk(" %08x %08x %08x %08x\n",
188 regs->gprs[8], regs->gprs[9], regs->gprs[10], regs->gprs[11]);
189 printk(" %08x %08x %08x %08x\n",
190 regs->gprs[12], regs->gprs[13], regs->gprs[14], regs->gprs[15]);
191 printk("%s ACRS: %08x %08x %08x %08x\n", mode,
192 regs->acrs[0], regs->acrs[1], regs->acrs[2], regs->acrs[3]);
193 printk(" %08x %08x %08x %08x\n",
194 regs->acrs[4], regs->acrs[5], regs->acrs[6], regs->acrs[7]);
195 printk(" %08x %08x %08x %08x\n",
196 regs->acrs[8], regs->acrs[9], regs->acrs[10], regs->acrs[11]);
197 printk(" %08x %08x %08x %08x\n",
198 regs->acrs[12], regs->acrs[13], regs->acrs[14], regs->acrs[15]);
199
200
201
202
203
204 old_fs = get_fs();
205 if (regs->psw.mask & PSW_PROBLEM_STATE)
206 set_fs(USER_DS);
207 else
208 set_fs(KERNEL_DS);
209 printk("%s Code: ", mode);
210 for (i = 0; i < 20; i++) {
211 unsigned char c;
212 if (__get_user(c, (char *)(regs->psw.addr + i))) {
213 printk(" Bad PSW.");
214 break;
215 }
216 printk("%02x ", c);
217 }
218 set_fs(old_fs);
219
220 printk("\n");
221}
222
223
224char *task_show_regs(struct task_struct *task, char *buffer)
225{
226 struct pt_regs *regs;
227
228 regs = __KSTK_PTREGS(task);
229 buffer += sprintf(buffer, "task: %08lx, ksp: %08x\n",
230 (unsigned long) task, task->thread.ksp);
231 buffer += sprintf(buffer, "User PSW : %08lx %08lx\n",
232 (unsigned long) regs->psw.mask,
233 (unsigned long) regs->psw.addr);
234 buffer += sprintf(buffer, "User GPRS: %08x %08x %08x %08x\n",
235 regs->gprs[0], regs->gprs[1],
236 regs->gprs[2], regs->gprs[3]);
237 buffer += sprintf(buffer, " %08x %08x %08x %08x\n",
238 regs->gprs[4], regs->gprs[5],
239 regs->gprs[6], regs->gprs[7]);
240 buffer += sprintf(buffer, " %08x %08x %08x %08x\n",
241 regs->gprs[8], regs->gprs[9],
242 regs->gprs[10], regs->gprs[11]);
243 buffer += sprintf(buffer, " %08x %08x %08x %08x\n",
244 regs->gprs[12], regs->gprs[13],
245 regs->gprs[14], regs->gprs[15]);
246 buffer += sprintf(buffer, "User ACRS: %08x %08x %08x %08x\n",
247 regs->acrs[0], regs->acrs[1],
248 regs->acrs[2], regs->acrs[3]);
249 buffer += sprintf(buffer, " %08x %08x %08x %08x\n",
250 regs->acrs[4], regs->acrs[5],
251 regs->acrs[6], regs->acrs[7]);
252 buffer += sprintf(buffer, " %08x %08x %08x %08x\n",
253 regs->acrs[8], regs->acrs[9],
254 regs->acrs[10], regs->acrs[11]);
255 buffer += sprintf(buffer, " %08x %08x %08x %08x\n",
256 regs->acrs[12], regs->acrs[13],
257 regs->acrs[14], regs->acrs[15]);
258 return buffer;
259}
260
261spinlock_t die_lock = SPIN_LOCK_UNLOCKED;
262
263void die(const char * str, struct pt_regs * regs, long err)
264{
265 console_verbose();
266 spin_lock_irq(&die_lock);
267 bust_spinlocks(1);
268 printk("%s: %04lx\n", str, err & 0xffff);
269 show_regs(regs);
270 bust_spinlocks(0);
271 spin_unlock_irq(&die_lock);
272 do_exit(SIGSEGV);
273}
274
275static void inline do_trap(long interruption_code, int signr, char *str,
276 struct pt_regs *regs, siginfo_t *info)
277{
278
279
280
281
282 if (regs->psw.mask & PSW_PROBLEM_STATE)
283 __sti();
284
285 if (regs->psw.mask & PSW_PROBLEM_STATE) {
286 struct task_struct *tsk = current;
287
288 tsk->thread.trap_no = interruption_code & 0xffff;
289 if (info)
290 force_sig_info(signr, info, tsk);
291 else
292 force_sig(signr, tsk);
293#ifndef CONFIG_SYSCTL
294#ifdef CONFIG_PROCESS_DEBUG
295 printk("User process fault: interruption code 0x%lX\n",
296 interruption_code);
297 show_regs(regs);
298#endif
299#else
300 if (sysctl_userprocess_debug) {
301 printk("User process fault: interruption code 0x%lX\n",
302 interruption_code);
303 show_regs(regs);
304 }
305#endif
306 } else {
307 unsigned long fixup = search_exception_table(regs->psw.addr);
308 if (fixup)
309 regs->psw.addr = fixup;
310 else
311 die(str, regs, interruption_code);
312 }
313}
314
315static inline void *get_check_address(struct pt_regs *regs)
316{
317 return (void *) ADDR_BITS_REMOVE(regs->psw.addr-S390_lowcore.pgm_ilc);
318}
319
320int do_debugger_trap(struct pt_regs *regs,int signal)
321{
322 if(regs->psw.mask&PSW_PROBLEM_STATE)
323 {
324 if(current->ptrace & PT_PTRACED)
325 force_sig(signal,current);
326 else
327 return 1;
328 }
329 else
330 {
331#if CONFIG_REMOTE_DEBUG
332 if(gdb_stub_initialised)
333 {
334 gdb_stub_handle_exception(regs, signal);
335 return 0;
336 }
337#endif
338 return 1;
339 }
340 return 0;
341}
342
343#define DO_ERROR(signr, str, name) \
344asmlinkage void name(struct pt_regs * regs, long interruption_code) \
345{ \
346 do_trap(interruption_code, signr, str, regs, NULL); \
347}
348
349#define DO_ERROR_INFO(signr, str, name, sicode, siaddr) \
350asmlinkage void name(struct pt_regs * regs, long interruption_code) \
351{ \
352 siginfo_t info; \
353 info.si_signo = signr; \
354 info.si_errno = 0; \
355 info.si_code = sicode; \
356 info.si_addr = (void *)siaddr; \
357 do_trap(interruption_code, signr, str, regs, &info); \
358}
359
360DO_ERROR(SIGSEGV, "Unknown program exception", default_trap_handler)
361
362DO_ERROR_INFO(SIGBUS, "addressing exception", addressing_exception,
363 BUS_ADRERR, get_check_address(regs))
364DO_ERROR_INFO(SIGILL, "execute exception", execute_exception,
365 ILL_ILLOPN, get_check_address(regs))
366DO_ERROR_INFO(SIGFPE, "fixpoint divide exception", divide_exception,
367 FPE_INTDIV, get_check_address(regs))
368DO_ERROR_INFO(SIGILL, "operand exception", operand_exception,
369 ILL_ILLOPN, get_check_address(regs))
370DO_ERROR_INFO(SIGILL, "privileged operation", privileged_op,
371 ILL_PRVOPC, get_check_address(regs))
372DO_ERROR_INFO(SIGILL, "special operation exception", special_op_exception,
373 ILL_ILLOPN, get_check_address(regs))
374DO_ERROR_INFO(SIGILL, "translation exception", translation_exception,
375 ILL_ILLOPN, get_check_address(regs))
376
377static inline void
378do_fp_trap(struct pt_regs *regs, void *location,
379 int fpc, long interruption_code)
380{
381 siginfo_t si;
382
383 si.si_signo = SIGFPE;
384 si.si_errno = 0;
385 si.si_addr = location;
386 si.si_code = 0;
387
388 if ((fpc & 0x00000300) == 0) {
389
390 if (fpc & 0x8000)
391 si.si_code = FPE_FLTINV;
392 else if (fpc & 0x4000)
393 si.si_code = FPE_FLTDIV;
394 else if (fpc & 0x2000)
395 si.si_code = FPE_FLTOVF;
396 else if (fpc & 0x1000)
397 si.si_code = FPE_FLTUND;
398 else if (fpc & 0x0800)
399 si.si_code = FPE_FLTRES;
400 }
401 current->thread.ieee_instruction_pointer = (addr_t) location;
402 do_trap(interruption_code, SIGFPE,
403 "floating point exception", regs, &si);
404}
405
406asmlinkage void illegal_op(struct pt_regs * regs, long interruption_code)
407{
408 __u8 opcode[6];
409 __u16 *location;
410 int signal = 0;
411
412 location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc);
413
414
415
416
417
418 if (regs->psw.mask & PSW_PROBLEM_STATE)
419 __sti();
420
421 if (regs->psw.mask & PSW_PROBLEM_STATE)
422 get_user(*((__u16 *) opcode), location);
423 else
424 *((__u16 *)opcode)=*((__u16 *)location);
425 if (*((__u16 *)opcode)==S390_BREAKPOINT_U16)
426 {
427 if(do_debugger_trap(regs,SIGTRAP))
428 signal = SIGILL;
429 }
430#ifdef CONFIG_MATHEMU
431 else if (regs->psw.mask & PSW_PROBLEM_STATE)
432 {
433 if (opcode[0] == 0xb3) {
434 get_user(*((__u16 *) (opcode+2)), location+1);
435 signal = math_emu_b3(opcode, regs);
436 } else if (opcode[0] == 0xed) {
437 get_user(*((__u32 *) (opcode+2)),
438 (__u32 *)(location+1));
439 signal = math_emu_ed(opcode, regs);
440 } else if (*((__u16 *) opcode) == 0xb299) {
441 get_user(*((__u16 *) (opcode+2)), location+1);
442 signal = math_emu_srnm(opcode, regs);
443 } else if (*((__u16 *) opcode) == 0xb29c) {
444 get_user(*((__u16 *) (opcode+2)), location+1);
445 signal = math_emu_stfpc(opcode, regs);
446 } else if (*((__u16 *) opcode) == 0xb29d) {
447 get_user(*((__u16 *) (opcode+2)), location+1);
448 signal = math_emu_lfpc(opcode, regs);
449 } else
450 signal = SIGILL;
451 }
452#endif
453 else
454 signal = SIGILL;
455 if (signal == SIGFPE)
456 do_fp_trap(regs, location,
457 current->thread.fp_regs.fpc, interruption_code);
458 else if (signal)
459 do_trap(interruption_code, signal,
460 "illegal operation", regs, NULL);
461}
462
463
464
465#ifdef CONFIG_MATHEMU
466asmlinkage void
467specification_exception(struct pt_regs * regs, long interruption_code)
468{
469 __u8 opcode[6];
470 __u16 *location = NULL;
471 int signal = 0;
472
473 location = (__u16 *) get_check_address(regs);
474
475
476
477
478
479 if (regs->psw.mask & PSW_PROBLEM_STATE)
480 __sti();
481
482 if (regs->psw.mask & PSW_PROBLEM_STATE) {
483 get_user(*((__u16 *) opcode), location);
484 switch (opcode[0]) {
485 case 0x28:
486 signal = math_emu_ldr(opcode);
487 break;
488 case 0x38:
489 signal = math_emu_ler(opcode);
490 break;
491 case 0x60:
492 get_user(*((__u16 *) (opcode+2)), location+1);
493 signal = math_emu_std(opcode, regs);
494 break;
495 case 0x68:
496 get_user(*((__u16 *) (opcode+2)), location+1);
497 signal = math_emu_ld(opcode, regs);
498 break;
499 case 0x70:
500 get_user(*((__u16 *) (opcode+2)), location+1);
501 signal = math_emu_ste(opcode, regs);
502 break;
503 case 0x78:
504 get_user(*((__u16 *) (opcode+2)), location+1);
505 signal = math_emu_le(opcode, regs);
506 break;
507 default:
508 signal = SIGILL;
509 break;
510 }
511 } else
512 signal = SIGILL;
513 if (signal == SIGFPE)
514 do_fp_trap(regs, location,
515 current->thread.fp_regs.fpc, interruption_code);
516 else if (signal) {
517 siginfo_t info;
518 info.si_signo = signal;
519 info.si_errno = 0;
520 info.si_code = ILL_ILLOPN;
521 info.si_addr = location;
522 do_trap(interruption_code, signal,
523 "specification exception", regs, &info);
524 }
525}
526#else
527DO_ERROR_INFO(SIGILL, "specification exception", specification_exception,
528 ILL_ILLOPN, get_check_address(regs));
529#endif
530
531asmlinkage void data_exception(struct pt_regs * regs, long interruption_code)
532{
533 __u8 opcode[6];
534 __u16 *location;
535 int signal = 0;
536
537 location = (__u16 *) get_check_address(regs);
538
539
540
541
542
543 if (regs->psw.mask & PSW_PROBLEM_STATE)
544 __sti();
545
546 if (MACHINE_HAS_IEEE)
547 __asm__ volatile ("stfpc %0\n\t"
548 : "=m" (current->thread.fp_regs.fpc));
549
550#ifdef CONFIG_MATHEMU
551 else if (regs->psw.mask & PSW_PROBLEM_STATE) {
552 get_user(*((__u16 *) opcode), location);
553 switch (opcode[0]) {
554 case 0x28:
555 signal = math_emu_ldr(opcode);
556 break;
557 case 0x38:
558 signal = math_emu_ler(opcode);
559 break;
560 case 0x60:
561 get_user(*((__u16 *) (opcode+2)), location+1);
562 signal = math_emu_std(opcode, regs);
563 break;
564 case 0x68:
565 get_user(*((__u16 *) (opcode+2)), location+1);
566 signal = math_emu_ld(opcode, regs);
567 break;
568 case 0x70:
569 get_user(*((__u16 *) (opcode+2)), location+1);
570 signal = math_emu_ste(opcode, regs);
571 break;
572 case 0x78:
573 get_user(*((__u16 *) (opcode+2)), location+1);
574 signal = math_emu_le(opcode, regs);
575 break;
576 case 0xb3:
577 get_user(*((__u16 *) (opcode+2)), location+1);
578 signal = math_emu_b3(opcode, regs);
579 break;
580 case 0xed:
581 get_user(*((__u32 *) (opcode+2)),
582 (__u32 *)(location+1));
583 signal = math_emu_ed(opcode, regs);
584 break;
585 case 0xb2:
586 if (opcode[1] == 0x99) {
587 get_user(*((__u16 *) (opcode+2)), location+1);
588 signal = math_emu_srnm(opcode, regs);
589 } else if (opcode[1] == 0x9c) {
590 get_user(*((__u16 *) (opcode+2)), location+1);
591 signal = math_emu_stfpc(opcode, regs);
592 } else if (opcode[1] == 0x9d) {
593 get_user(*((__u16 *) (opcode+2)), location+1);
594 signal = math_emu_lfpc(opcode, regs);
595 } else
596 signal = SIGILL;
597 break;
598 default:
599 signal = SIGILL;
600 break;
601 }
602 }
603#endif
604 if (current->thread.fp_regs.fpc & FPC_DXC_MASK)
605 signal = SIGFPE;
606 else
607 signal = SIGILL;
608 if (signal == SIGFPE)
609 do_fp_trap(regs, location,
610 current->thread.fp_regs.fpc, interruption_code);
611 else if (signal) {
612 siginfo_t info;
613 info.si_signo = signal;
614 info.si_errno = 0;
615 info.si_code = ILL_ILLOPN;
616 info.si_addr = location;
617 do_trap(interruption_code, signal,
618 "data exception", regs, &info);
619 }
620}
621
622
623
624
625
626void __init trap_init(void)
627{
628 int i;
629
630 for (i = 0; i < 128; i++)
631 pgm_check_table[i] = &default_trap_handler;
632 pgm_check_table[1] = &illegal_op;
633 pgm_check_table[2] = &privileged_op;
634 pgm_check_table[3] = &execute_exception;
635 pgm_check_table[4] = &do_protection_exception;
636 pgm_check_table[5] = &addressing_exception;
637 pgm_check_table[6] = &specification_exception;
638 pgm_check_table[7] = &data_exception;
639 pgm_check_table[9] = ÷_exception;
640 pgm_check_table[0x10] = &do_segment_exception;
641 pgm_check_table[0x11] = &do_page_exception;
642 pgm_check_table[0x12] = &translation_exception;
643 pgm_check_table[0x13] = &special_op_exception;
644 pgm_check_table[0x14] = &do_pseudo_page_fault;
645 pgm_check_table[0x15] = &operand_exception;
646 pgm_check_table[0x1C] = &privileged_op;
647#ifdef CONFIG_PFAULT
648 if (MACHINE_IS_VM) {
649
650 if (register_early_external_interrupt(0x2603, pfault_interrupt,
651 &ext_int_pfault) != 0)
652 panic("Couldn't request external interrupt 0x2603");
653
654
655
656
657 if (pfault_init() != 0) {
658
659 unregister_early_external_interrupt(0x2603,
660 pfault_interrupt,
661 &ext_int_pfault);
662 cpcmd("SET PAGEX ON", NULL, 0);
663 }
664 }
665#else
666 if (MACHINE_IS_VM)
667 cpcmd("SET PAGEX ON", NULL, 0);
668#endif
669}
670
671
672void handle_per_exception(struct pt_regs *regs)
673{
674 if(regs->psw.mask&PSW_PROBLEM_STATE)
675 {
676 per_struct *per_info=¤t->thread.per_info;
677 per_info->lowcore.words.perc_atmid=S390_lowcore.per_perc_atmid;
678 per_info->lowcore.words.address=S390_lowcore.per_address;
679 per_info->lowcore.words.access_id=S390_lowcore.per_access_id;
680 }
681 if(do_debugger_trap(regs,SIGTRAP))
682 {
683
684 printk("Spurious per exception detected\n");
685 printk("switching off per tracing for this task.\n");
686 show_regs(regs);
687
688 regs->psw.mask &= ~PSW_PER_MASK;
689 }
690}
691
692