traps.c
上传用户:jlfgdled
上传日期:2013-04-10
资源大小:33168k
文件大小:19k
源码类别:

Linux/Unix编程

开发平台:

Unix_Linux

  1. /*
  2.  *  arch/s390/kernel/traps.c
  3.  *
  4.  *  S390 version
  5.  *    Copyright (C) 1999,2000 IBM Deutschland Entwicklung GmbH, IBM Corporation
  6.  *    Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
  7.  *               Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
  8.  *
  9.  *  Derived from "arch/i386/kernel/traps.c"
  10.  *    Copyright (C) 1991, 1992 Linus Torvalds
  11.  */
  12. /*
  13.  * 'Traps.c' handles hardware traps and faults after we have saved some
  14.  * state in 'asm.s'.
  15.  */
  16. #include <linux/config.h>
  17. #include <linux/sched.h>
  18. #include <linux/kernel.h>
  19. #include <linux/string.h>
  20. #include <linux/errno.h>
  21. #include <linux/ptrace.h>
  22. #include <linux/timer.h>
  23. #include <linux/mm.h>
  24. #include <linux/smp.h>
  25. #include <linux/smp_lock.h>
  26. #include <linux/init.h>
  27. #include <linux/delay.h>
  28. #include <linux/module.h>
  29. #include <asm/system.h>
  30. #include <asm/uaccess.h>
  31. #include <asm/io.h>
  32. #include <asm/atomic.h>
  33. #include <asm/mathemu.h>
  34. #include <asm/cpcmd.h>
  35. #include <asm/s390_ext.h>
  36. /* Called from entry.S only */
  37. extern void handle_per_exception(struct pt_regs *regs);
  38. typedef void pgm_check_handler_t(struct pt_regs *, long);
  39. pgm_check_handler_t *pgm_check_table[128];
  40. #ifdef CONFIG_SYSCTL
  41. #ifdef CONFIG_PROCESS_DEBUG
  42. int sysctl_userprocess_debug = 1;
  43. #else
  44. int sysctl_userprocess_debug = 0;
  45. #endif
  46. #endif
  47. extern pgm_check_handler_t do_protection_exception;
  48. extern pgm_check_handler_t do_segment_exception;
  49. extern pgm_check_handler_t do_page_exception;
  50. extern pgm_check_handler_t do_pseudo_page_fault;
  51. #ifdef CONFIG_PFAULT
  52. extern int pfault_init(void);
  53. extern void pfault_fini(void);
  54. extern void pfault_interrupt(struct pt_regs *regs, __u16 error_code);
  55. static ext_int_info_t ext_int_pfault;
  56. #endif
  57. int kstack_depth_to_print = 12;
  58. /*
  59.  * If the address is either in the .text section of the
  60.  * kernel, or in the vmalloc'ed module regions, it *may* 
  61.  * be the address of a calling routine
  62.  */
  63. extern char _stext, _etext;
  64. #ifdef CONFIG_MODULES
  65. extern struct module *module_list;
  66. extern struct module kernel_module;
  67. static inline int kernel_text_address(unsigned long addr)
  68. {
  69. int retval = 0;
  70. struct module *mod;
  71. if (addr >= (unsigned long) &_stext &&
  72.     addr <= (unsigned long) &_etext)
  73. return 1;
  74. for (mod = module_list; mod != &kernel_module; mod = mod->next) {
  75. /* mod_bound tests for addr being inside the vmalloc'ed
  76.  * module area. Of course it'd be better to test only
  77.  * for the .text subset... */
  78. if (mod_bound(addr, 0, mod)) {
  79. retval = 1;
  80. break;
  81. }
  82. }
  83. return retval;
  84. }
  85. #else
  86. static inline int kernel_text_address(unsigned long addr)
  87. {
  88. return (addr >= (unsigned long) &_stext &&
  89. addr <= (unsigned long) &_etext);
  90. }
  91. #endif
  92. void show_trace(unsigned long * stack)
  93. {
  94. unsigned long backchain, low_addr, high_addr, ret_addr;
  95. int i;
  96. if (!stack)
  97. stack = (unsigned long*)&stack;
  98. printk("Call Trace: ");
  99. low_addr = ((unsigned long) stack) & PSW_ADDR_MASK;
  100. high_addr = (low_addr & (-THREAD_SIZE)) + THREAD_SIZE;
  101. /* Skip the first frame (biased stack) */
  102. backchain = *((unsigned long *) low_addr) & PSW_ADDR_MASK;
  103. /* Print up to 8 lines */
  104. for (i = 0; i < 8; i++) {
  105. if (backchain < low_addr || backchain >= high_addr)
  106. break;
  107. ret_addr = *((unsigned long *) (backchain+56)) & PSW_ADDR_MASK;
  108. if (!kernel_text_address(ret_addr))
  109. break;
  110. if (i && ((i % 6) == 0))
  111. printk("n   ");
  112. printk("[<%08lx>] ", ret_addr);
  113. low_addr = backchain;
  114. backchain = *((unsigned long *) backchain) & PSW_ADDR_MASK;
  115. }
  116. printk("n");
  117. }
  118. void show_trace_task(struct task_struct *tsk)
  119. {
  120. /*
  121.  * We can't print the backtrace of a running process. It is
  122.  * unreliable at best and can cause kernel oopses.
  123.  */
  124. if (task_has_cpu(tsk))
  125. return;
  126. show_trace((unsigned long *) tsk->thread.ksp);
  127. }
  128. void show_stack(unsigned long *sp)
  129. {
  130. unsigned long *stack;
  131. int i;
  132. // debugging aid: "show_stack(NULL);" prints the
  133. // back trace for this cpu.
  134. if(sp == NULL)
  135. sp = (unsigned long*) &sp;
  136. stack = sp;
  137. for (i = 0; i < kstack_depth_to_print; i++) {
  138. if (((addr_t) stack & (THREAD_SIZE-1)) == 0)
  139. break;
  140. if (i && ((i % 8) == 0))
  141. printk("n       ");
  142. printk("%08lx ", *stack++);
  143. }
  144. printk("n");
  145. show_trace(sp);
  146. }
  147. void show_registers(struct pt_regs *regs)
  148. {
  149. mm_segment_t old_fs;
  150. char *mode;
  151. int i;
  152. mode = (regs->psw.mask & PSW_PROBLEM_STATE) ? "User" : "Krnl";
  153. printk("%s PSW : %08lx %08lxn",
  154.        mode, (unsigned long) regs->psw.mask,
  155.        (unsigned long) regs->psw.addr);
  156. printk("%s GPRS: %08x %08x %08x %08xn", mode,
  157.        regs->gprs[0], regs->gprs[1], regs->gprs[2], regs->gprs[3]);
  158. printk("           %08x %08x %08x %08xn",
  159.        regs->gprs[4], regs->gprs[5], regs->gprs[6], regs->gprs[7]);
  160. printk("           %08x %08x %08x %08xn",
  161.        regs->gprs[8], regs->gprs[9], regs->gprs[10], regs->gprs[11]);
  162. printk("           %08x %08x %08x %08xn",
  163.        regs->gprs[12], regs->gprs[13], regs->gprs[14], regs->gprs[15]);
  164. printk("%s ACRS: %08x %08x %08x %08xn", mode,
  165.        regs->acrs[0], regs->acrs[1], regs->acrs[2], regs->acrs[3]);
  166. printk("           %08x %08x %08x %08xn",
  167.        regs->acrs[4], regs->acrs[5], regs->acrs[6], regs->acrs[7]);
  168. printk("           %08x %08x %08x %08xn",
  169.        regs->acrs[8], regs->acrs[9], regs->acrs[10], regs->acrs[11]);
  170. printk("           %08x %08x %08x %08xn",
  171.        regs->acrs[12], regs->acrs[13], regs->acrs[14], regs->acrs[15]);
  172. /*
  173.  * Print the first 20 byte of the instruction stream at the
  174.  * time of the fault.
  175.  */
  176. old_fs = get_fs();
  177. if (regs->psw.mask & PSW_PROBLEM_STATE)
  178. set_fs(USER_DS);
  179. else
  180. set_fs(KERNEL_DS);
  181. printk("%s Code: ", mode);
  182. for (i = 0; i < 20; i++) {
  183. unsigned char c;
  184. if (__get_user(c, (char *)(regs->psw.addr + i))) {
  185. printk(" Bad PSW.");
  186. break;
  187. }
  188. printk("%02x ", c);
  189. }
  190. set_fs(old_fs);
  191. printk("n");
  192. }
  193. /* This is called from fs/proc/array.c */
  194. char *task_show_regs(struct task_struct *task, char *buffer)
  195. {
  196. struct pt_regs *regs;
  197. regs = __KSTK_PTREGS(task);
  198. buffer += sprintf(buffer, "task: %08lx, ksp: %08xn",
  199.   (unsigned long) task, task->thread.ksp);
  200. buffer += sprintf(buffer, "User PSW : %08lx %08lxn",
  201.   (unsigned long) regs->psw.mask, 
  202.   (unsigned long) regs->psw.addr);
  203. buffer += sprintf(buffer, "User GPRS: %08x %08x %08x %08xn",
  204.   regs->gprs[0], regs->gprs[1],
  205.   regs->gprs[2], regs->gprs[3]);
  206. buffer += sprintf(buffer, "           %08x %08x %08x %08xn",
  207.   regs->gprs[4], regs->gprs[5],
  208.   regs->gprs[6], regs->gprs[7]);
  209. buffer += sprintf(buffer, "           %08x %08x %08x %08xn",
  210.   regs->gprs[8], regs->gprs[9],
  211.   regs->gprs[10], regs->gprs[11]);
  212. buffer += sprintf(buffer, "           %08x %08x %08x %08xn",
  213.   regs->gprs[12], regs->gprs[13],
  214.   regs->gprs[14], regs->gprs[15]);
  215. buffer += sprintf(buffer, "User ACRS: %08x %08x %08x %08xn",
  216.   regs->acrs[0], regs->acrs[1],
  217.   regs->acrs[2], regs->acrs[3]);
  218. buffer += sprintf(buffer, "           %08x %08x %08x %08xn",
  219.   regs->acrs[4], regs->acrs[5],
  220.   regs->acrs[6], regs->acrs[7]);
  221. buffer += sprintf(buffer, "           %08x %08x %08x %08xn",
  222.   regs->acrs[8], regs->acrs[9],
  223.   regs->acrs[10], regs->acrs[11]);
  224. buffer += sprintf(buffer, "           %08x %08x %08x %08xn",
  225.   regs->acrs[12], regs->acrs[13],
  226.   regs->acrs[14], regs->acrs[15]);
  227. return buffer;
  228. }
  229. spinlock_t die_lock = SPIN_LOCK_UNLOCKED;
  230. void die(const char * str, struct pt_regs * regs, long err)
  231. {
  232.         console_verbose();
  233.         spin_lock_irq(&die_lock);
  234. bust_spinlocks(1);
  235.         printk("%s: %04lxn", str, err & 0xffff);
  236.         show_regs(regs);
  237. bust_spinlocks(0);
  238.         spin_unlock_irq(&die_lock);
  239.         do_exit(SIGSEGV);
  240. }
  241. static void inline do_trap(long interruption_code, int signr, char *str,
  242.                            struct pt_regs *regs, siginfo_t *info)
  243. {
  244. /*
  245.  * We got all needed information from the lowcore and can
  246.  * now safely switch on interrupts.
  247.  */
  248.         if (regs->psw.mask & PSW_PROBLEM_STATE)
  249. __sti();
  250.         if (regs->psw.mask & PSW_PROBLEM_STATE) {
  251.                 struct task_struct *tsk = current;
  252.                 tsk->thread.trap_no = interruption_code & 0xffff;
  253. if (info)
  254. force_sig_info(signr, info, tsk);
  255. else
  256.                  force_sig(signr, tsk);
  257. #ifndef CONFIG_SYSCTL
  258. #ifdef CONFIG_PROCESS_DEBUG
  259.                 printk("User process fault: interruption code 0x%lXn",
  260.                        interruption_code);
  261.                 show_regs(regs);
  262. #endif
  263. #else
  264. if (sysctl_userprocess_debug) {
  265. printk("User process fault: interruption code 0x%lXn",
  266.        interruption_code);
  267. show_regs(regs);
  268. }
  269. #endif
  270.         } else {
  271.                 unsigned long fixup = search_exception_table(regs->psw.addr);
  272.                 if (fixup)
  273.                         regs->psw.addr = fixup;
  274.                 else
  275.                         die(str, regs, interruption_code);
  276.         }
  277. }
  278. static inline void *get_check_address(struct pt_regs *regs)
  279. {
  280. return (void *) ADDR_BITS_REMOVE(regs->psw.addr-S390_lowcore.pgm_ilc);
  281. }
  282. int do_debugger_trap(struct pt_regs *regs,int signal)
  283. {
  284. if(regs->psw.mask&PSW_PROBLEM_STATE)
  285. {
  286. if(current->ptrace & PT_PTRACED)
  287. force_sig(signal,current);
  288. else
  289. return 1;
  290. }
  291. else
  292. {
  293. #if CONFIG_REMOTE_DEBUG
  294. if(gdb_stub_initialised)
  295. {
  296. gdb_stub_handle_exception(regs, signal);
  297. return 0;
  298. }
  299. #endif
  300. return 1;
  301. }
  302. return 0;
  303. }
  304. #define DO_ERROR(signr, str, name) 
  305. asmlinkage void name(struct pt_regs * regs, long interruption_code) 
  306. do_trap(interruption_code, signr, str, regs, NULL); 
  307. }
  308. #define DO_ERROR_INFO(signr, str, name, sicode, siaddr) 
  309. asmlinkage void name(struct pt_regs * regs, long interruption_code) 
  310.         siginfo_t info; 
  311.         info.si_signo = signr; 
  312.         info.si_errno = 0; 
  313.         info.si_code = sicode; 
  314.         info.si_addr = (void *)siaddr; 
  315.         do_trap(interruption_code, signr, str, regs, &info); 
  316. }
  317. DO_ERROR(SIGSEGV, "Unknown program exception", default_trap_handler)
  318. DO_ERROR_INFO(SIGBUS, "addressing exception", addressing_exception,
  319.       BUS_ADRERR, get_check_address(regs))
  320. DO_ERROR_INFO(SIGILL,  "execute exception", execute_exception,
  321.       ILL_ILLOPN, get_check_address(regs))
  322. DO_ERROR_INFO(SIGFPE,  "fixpoint divide exception", divide_exception,
  323.       FPE_INTDIV, get_check_address(regs))
  324. DO_ERROR_INFO(SIGILL,  "operand exception", operand_exception,
  325.       ILL_ILLOPN, get_check_address(regs))
  326. DO_ERROR_INFO(SIGILL,  "privileged operation", privileged_op,
  327.       ILL_PRVOPC, get_check_address(regs))
  328. DO_ERROR_INFO(SIGILL,  "special operation exception", special_op_exception,
  329.       ILL_ILLOPN, get_check_address(regs))
  330. DO_ERROR_INFO(SIGILL,  "translation exception", translation_exception,
  331.       ILL_ILLOPN, get_check_address(regs))
  332. static inline void
  333. do_fp_trap(struct pt_regs *regs, void *location,
  334.            int fpc, long interruption_code)
  335. {
  336. siginfo_t si;
  337. si.si_signo = SIGFPE;
  338. si.si_errno = 0;
  339. si.si_addr = location;
  340. si.si_code = 0;
  341. /* FPC[2] is Data Exception Code */
  342. if ((fpc & 0x00000300) == 0) {
  343. /* bits 6 and 7 of DXC are 0 iff IEEE exception */
  344. if (fpc & 0x8000) /* invalid fp operation */
  345. si.si_code = FPE_FLTINV;
  346. else if (fpc & 0x4000) /* div by 0 */
  347. si.si_code = FPE_FLTDIV;
  348. else if (fpc & 0x2000) /* overflow */
  349. si.si_code = FPE_FLTOVF;
  350. else if (fpc & 0x1000) /* underflow */
  351. si.si_code = FPE_FLTUND;
  352. else if (fpc & 0x0800) /* inexact */
  353. si.si_code = FPE_FLTRES;
  354. }
  355. current->thread.ieee_instruction_pointer = (addr_t) location;
  356. do_trap(interruption_code, SIGFPE,
  357. "floating point exception", regs, &si);
  358. }
  359. asmlinkage void illegal_op(struct pt_regs * regs, long interruption_code)
  360. {
  361.         __u8 opcode[6];
  362. __u16 *location;
  363. int signal = 0;
  364. location = (__u16 *)(regs->psw.addr-S390_lowcore.pgm_ilc);
  365. /*
  366.  * We got all needed information from the lowcore and can
  367.  * now safely switch on interrupts.
  368.  */
  369. if (regs->psw.mask & PSW_PROBLEM_STATE)
  370. __sti();
  371. if (regs->psw.mask & PSW_PROBLEM_STATE)
  372. get_user(*((__u16 *) opcode), location);
  373. else
  374. *((__u16 *)opcode)=*((__u16 *)location);
  375. if (*((__u16 *)opcode)==S390_BREAKPOINT_U16)
  376.         {
  377. if(do_debugger_trap(regs,SIGTRAP))
  378. signal = SIGILL;
  379. }
  380. #ifdef CONFIG_MATHEMU
  381.         else if (regs->psw.mask & PSW_PROBLEM_STATE)
  382. {
  383. if (opcode[0] == 0xb3) {
  384. get_user(*((__u16 *) (opcode+2)), location+1);
  385. signal = math_emu_b3(opcode, regs);
  386.                 } else if (opcode[0] == 0xed) {
  387. get_user(*((__u32 *) (opcode+2)),
  388.  (__u32 *)(location+1));
  389. signal = math_emu_ed(opcode, regs);
  390. } else if (*((__u16 *) opcode) == 0xb299) {
  391. get_user(*((__u16 *) (opcode+2)), location+1);
  392. signal = math_emu_srnm(opcode, regs);
  393. } else if (*((__u16 *) opcode) == 0xb29c) {
  394. get_user(*((__u16 *) (opcode+2)), location+1);
  395. signal = math_emu_stfpc(opcode, regs);
  396. } else if (*((__u16 *) opcode) == 0xb29d) {
  397. get_user(*((__u16 *) (opcode+2)), location+1);
  398. signal = math_emu_lfpc(opcode, regs);
  399. } else
  400. signal = SIGILL;
  401.         }
  402. #endif 
  403. else
  404. signal = SIGILL;
  405.         if (signal == SIGFPE)
  406. do_fp_trap(regs, location,
  407.                            current->thread.fp_regs.fpc, interruption_code);
  408.         else if (signal)
  409. do_trap(interruption_code, signal,
  410. "illegal operation", regs, NULL);
  411. }
  412. #ifdef CONFIG_MATHEMU
  413. asmlinkage void 
  414. specification_exception(struct pt_regs * regs, long interruption_code)
  415. {
  416.         __u8 opcode[6];
  417. __u16 *location = NULL;
  418. int signal = 0;
  419. location = (__u16 *) get_check_address(regs);
  420. /*
  421.  * We got all needed information from the lowcore and can
  422.  * now safely switch on interrupts.
  423.  */
  424. if (regs->psw.mask & PSW_PROBLEM_STATE)
  425. __sti();
  426.         if (regs->psw.mask & PSW_PROBLEM_STATE) {
  427. get_user(*((__u16 *) opcode), location);
  428. switch (opcode[0]) {
  429. case 0x28: /* LDR Rx,Ry   */
  430. signal = math_emu_ldr(opcode);
  431. break;
  432. case 0x38: /* LER Rx,Ry   */
  433. signal = math_emu_ler(opcode);
  434. break;
  435. case 0x60: /* STD R,D(X,B) */
  436. get_user(*((__u16 *) (opcode+2)), location+1);
  437. signal = math_emu_std(opcode, regs);
  438. break;
  439. case 0x68: /* LD R,D(X,B) */
  440. get_user(*((__u16 *) (opcode+2)), location+1);
  441. signal = math_emu_ld(opcode, regs);
  442. break;
  443. case 0x70: /* STE R,D(X,B) */
  444. get_user(*((__u16 *) (opcode+2)), location+1);
  445. signal = math_emu_ste(opcode, regs);
  446. break;
  447. case 0x78: /* LE R,D(X,B) */
  448. get_user(*((__u16 *) (opcode+2)), location+1);
  449. signal = math_emu_le(opcode, regs);
  450. break;
  451. default:
  452. signal = SIGILL;
  453. break;
  454.                 }
  455.         } else
  456. signal = SIGILL;
  457.         if (signal == SIGFPE)
  458. do_fp_trap(regs, location,
  459.                            current->thread.fp_regs.fpc, interruption_code);
  460.         else if (signal) {
  461. siginfo_t info;
  462. info.si_signo = signal;
  463. info.si_errno = 0;
  464. info.si_code = ILL_ILLOPN;
  465. info.si_addr = location;
  466. do_trap(interruption_code, signal, 
  467. "specification exception", regs, &info);
  468. }
  469. }
  470. #else
  471. DO_ERROR_INFO(SIGILL, "specification exception", specification_exception,
  472.       ILL_ILLOPN, get_check_address(regs));
  473. #endif
  474. asmlinkage void data_exception(struct pt_regs * regs, long interruption_code)
  475. {
  476.         __u8 opcode[6];
  477. __u16 *location;
  478. int signal = 0;
  479. location = (__u16 *) get_check_address(regs);
  480. /*
  481.  * We got all needed information from the lowcore and can
  482.  * now safely switch on interrupts.
  483.  */
  484. if (regs->psw.mask & PSW_PROBLEM_STATE)
  485. __sti();
  486. if (MACHINE_HAS_IEEE)
  487. __asm__ volatile ("stfpc %0nt" 
  488.   : "=m" (current->thread.fp_regs.fpc));
  489. #ifdef CONFIG_MATHEMU
  490.         else if (regs->psw.mask & PSW_PROBLEM_STATE) {
  491. get_user(*((__u16 *) opcode), location);
  492. switch (opcode[0]) {
  493. case 0x28: /* LDR Rx,Ry   */
  494. signal = math_emu_ldr(opcode);
  495. break;
  496. case 0x38: /* LER Rx,Ry   */
  497. signal = math_emu_ler(opcode);
  498. break;
  499. case 0x60: /* STD R,D(X,B) */
  500. get_user(*((__u16 *) (opcode+2)), location+1);
  501. signal = math_emu_std(opcode, regs);
  502. break;
  503. case 0x68: /* LD R,D(X,B) */
  504. get_user(*((__u16 *) (opcode+2)), location+1);
  505. signal = math_emu_ld(opcode, regs);
  506. break;
  507. case 0x70: /* STE R,D(X,B) */
  508. get_user(*((__u16 *) (opcode+2)), location+1);
  509. signal = math_emu_ste(opcode, regs);
  510. break;
  511. case 0x78: /* LE R,D(X,B) */
  512. get_user(*((__u16 *) (opcode+2)), location+1);
  513. signal = math_emu_le(opcode, regs);
  514. break;
  515. case 0xb3:
  516. get_user(*((__u16 *) (opcode+2)), location+1);
  517. signal = math_emu_b3(opcode, regs);
  518. break;
  519.                 case 0xed:
  520. get_user(*((__u32 *) (opcode+2)),
  521.  (__u32 *)(location+1));
  522. signal = math_emu_ed(opcode, regs);
  523. break;
  524.         case 0xb2:
  525. if (opcode[1] == 0x99) {
  526. get_user(*((__u16 *) (opcode+2)), location+1);
  527. signal = math_emu_srnm(opcode, regs);
  528. } else if (opcode[1] == 0x9c) {
  529. get_user(*((__u16 *) (opcode+2)), location+1);
  530. signal = math_emu_stfpc(opcode, regs);
  531. } else if (opcode[1] == 0x9d) {
  532. get_user(*((__u16 *) (opcode+2)), location+1);
  533. signal = math_emu_lfpc(opcode, regs);
  534. } else
  535. signal = SIGILL;
  536. break;
  537. default:
  538. signal = SIGILL;
  539. break;
  540.                 }
  541.         }
  542. #endif 
  543. if (current->thread.fp_regs.fpc & FPC_DXC_MASK)
  544. signal = SIGFPE;
  545. else
  546. signal = SIGILL;
  547.         if (signal == SIGFPE)
  548. do_fp_trap(regs, location,
  549.                            current->thread.fp_regs.fpc, interruption_code);
  550.         else if (signal) {
  551. siginfo_t info;
  552. info.si_signo = signal;
  553. info.si_errno = 0;
  554. info.si_code = ILL_ILLOPN;
  555. info.si_addr = location;
  556. do_trap(interruption_code, signal, 
  557. "data exception", regs, &info);
  558. }
  559. }
  560. /* init is done in lowcore.S and head.S */
  561. void __init trap_init(void)
  562. {
  563.         int i;
  564.         for (i = 0; i < 128; i++)
  565.           pgm_check_table[i] = &default_trap_handler;
  566.         pgm_check_table[1] = &illegal_op;
  567.         pgm_check_table[2] = &privileged_op;
  568.         pgm_check_table[3] = &execute_exception;
  569.         pgm_check_table[4] = &do_protection_exception;
  570.         pgm_check_table[5] = &addressing_exception;
  571.         pgm_check_table[6] = &specification_exception;
  572.         pgm_check_table[7] = &data_exception;
  573.         pgm_check_table[9] = &divide_exception;
  574.         pgm_check_table[0x10] = &do_segment_exception;
  575.         pgm_check_table[0x11] = &do_page_exception;
  576.         pgm_check_table[0x12] = &translation_exception;
  577.         pgm_check_table[0x13] = &special_op_exception;
  578.   pgm_check_table[0x14] = &do_pseudo_page_fault;
  579.         pgm_check_table[0x15] = &operand_exception;
  580.         pgm_check_table[0x1C] = &privileged_op;
  581. #ifdef CONFIG_PFAULT
  582. if (MACHINE_IS_VM) {
  583. /* request the 0x2603 external interrupt */
  584. if (register_early_external_interrupt(0x2603, pfault_interrupt,
  585.       &ext_int_pfault) != 0)
  586. panic("Couldn't request external interrupt 0x2603");
  587. /*
  588.  * First try to get pfault pseudo page faults going.
  589.  * If this isn't available turn on pagex page faults.
  590.  */
  591. if (pfault_init() != 0) {
  592. /* Tough luck, no pfault. */
  593. unregister_early_external_interrupt(0x2603,
  594.     pfault_interrupt,
  595.     &ext_int_pfault);
  596. cpcmd("SET PAGEX ON", NULL, 0);
  597. }
  598. }
  599. #else
  600. if (MACHINE_IS_VM)
  601. cpcmd("SET PAGEX ON", NULL, 0);
  602. #endif
  603. }
  604. void handle_per_exception(struct pt_regs *regs)
  605. {
  606. if(regs->psw.mask&PSW_PROBLEM_STATE)
  607. {
  608. per_struct *per_info=&current->thread.per_info;
  609. per_info->lowcore.words.perc_atmid=S390_lowcore.per_perc_atmid;
  610. per_info->lowcore.words.address=S390_lowcore.per_address;
  611. per_info->lowcore.words.access_id=S390_lowcore.per_access_id;
  612. }
  613. if(do_debugger_trap(regs,SIGTRAP))
  614. {
  615. /* I've seen this possibly a task structure being reused ? */
  616. printk("Spurious per exception detectedn");
  617. printk("switching off per tracing for this task.n");
  618. show_regs(regs);
  619. /* Hopefully switching off per tracing will help us survive */
  620. regs->psw.mask &= ~PSW_PER_MASK;
  621. }
  622. }