traps.c 7.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. /*
  2. * S390 version
  3. * Copyright IBM Corp. 1999, 2000
  4. * Author(s): Martin Schwidefsky (schwidefsky@de.ibm.com),
  5. * Denis Joseph Barrow (djbarrow@de.ibm.com,barrow_dj@yahoo.com),
  6. *
  7. * Derived from "arch/i386/kernel/traps.c"
  8. * Copyright (C) 1991, 1992 Linus Torvalds
  9. */
  10. /*
  11. * 'Traps.c' handles hardware traps and faults after we have saved some
  12. * state in 'asm.s'.
  13. */
  14. #include <linux/kprobes.h>
  15. #include <linux/kdebug.h>
  16. #include <linux/extable.h>
  17. #include <linux/ptrace.h>
  18. #include <linux/sched.h>
  19. #include <linux/sched/debug.h>
  20. #include <linux/mm.h>
  21. #include <linux/slab.h>
  22. #include <linux/uaccess.h>
  23. #include <asm/fpu/api.h>
  24. #include "entry.h"
  25. static inline void __user *get_trap_ip(struct pt_regs *regs)
  26. {
  27. unsigned long address;
  28. if (regs->int_code & 0x200)
  29. address = *(unsigned long *)(current->thread.trap_tdb + 24);
  30. else
  31. address = regs->psw.addr;
  32. return (void __user *) (address - (regs->int_code >> 16));
  33. }
  34. int is_valid_bugaddr(unsigned long addr)
  35. {
  36. return 1;
  37. }
  38. void do_report_trap(struct pt_regs *regs, int si_signo, int si_code, char *str)
  39. {
  40. siginfo_t info;
  41. if (user_mode(regs)) {
  42. info.si_signo = si_signo;
  43. info.si_errno = 0;
  44. info.si_code = si_code;
  45. info.si_addr = get_trap_ip(regs);
  46. force_sig_info(si_signo, &info, current);
  47. report_user_fault(regs, si_signo, 0);
  48. } else {
  49. const struct exception_table_entry *fixup;
  50. fixup = search_exception_tables(regs->psw.addr);
  51. if (fixup)
  52. regs->psw.addr = extable_fixup(fixup);
  53. else {
  54. enum bug_trap_type btt;
  55. btt = report_bug(regs->psw.addr, regs);
  56. if (btt == BUG_TRAP_TYPE_WARN)
  57. return;
  58. die(regs, str);
  59. }
  60. }
  61. }
  62. static void do_trap(struct pt_regs *regs, int si_signo, int si_code, char *str)
  63. {
  64. if (notify_die(DIE_TRAP, str, regs, 0,
  65. regs->int_code, si_signo) == NOTIFY_STOP)
  66. return;
  67. do_report_trap(regs, si_signo, si_code, str);
  68. }
  69. NOKPROBE_SYMBOL(do_trap);
  70. void do_per_trap(struct pt_regs *regs)
  71. {
  72. siginfo_t info;
  73. if (notify_die(DIE_SSTEP, "sstep", regs, 0, 0, SIGTRAP) == NOTIFY_STOP)
  74. return;
  75. if (!current->ptrace)
  76. return;
  77. info.si_signo = SIGTRAP;
  78. info.si_errno = 0;
  79. info.si_code = TRAP_HWBKPT;
  80. info.si_addr =
  81. (void __force __user *) current->thread.per_event.address;
  82. force_sig_info(SIGTRAP, &info, current);
  83. }
  84. NOKPROBE_SYMBOL(do_per_trap);
  85. void default_trap_handler(struct pt_regs *regs)
  86. {
  87. if (user_mode(regs)) {
  88. report_user_fault(regs, SIGSEGV, 0);
  89. do_exit(SIGSEGV);
  90. } else
  91. die(regs, "Unknown program exception");
  92. }
  93. #define DO_ERROR_INFO(name, signr, sicode, str) \
  94. void name(struct pt_regs *regs) \
  95. { \
  96. do_trap(regs, signr, sicode, str); \
  97. }
  98. DO_ERROR_INFO(addressing_exception, SIGILL, ILL_ILLADR,
  99. "addressing exception")
  100. DO_ERROR_INFO(execute_exception, SIGILL, ILL_ILLOPN,
  101. "execute exception")
  102. DO_ERROR_INFO(divide_exception, SIGFPE, FPE_INTDIV,
  103. "fixpoint divide exception")
  104. DO_ERROR_INFO(overflow_exception, SIGFPE, FPE_INTOVF,
  105. "fixpoint overflow exception")
  106. DO_ERROR_INFO(hfp_overflow_exception, SIGFPE, FPE_FLTOVF,
  107. "HFP overflow exception")
  108. DO_ERROR_INFO(hfp_underflow_exception, SIGFPE, FPE_FLTUND,
  109. "HFP underflow exception")
  110. DO_ERROR_INFO(hfp_significance_exception, SIGFPE, FPE_FLTRES,
  111. "HFP significance exception")
  112. DO_ERROR_INFO(hfp_divide_exception, SIGFPE, FPE_FLTDIV,
  113. "HFP divide exception")
  114. DO_ERROR_INFO(hfp_sqrt_exception, SIGFPE, FPE_FLTINV,
  115. "HFP square root exception")
  116. DO_ERROR_INFO(operand_exception, SIGILL, ILL_ILLOPN,
  117. "operand exception")
  118. DO_ERROR_INFO(privileged_op, SIGILL, ILL_PRVOPC,
  119. "privileged operation")
  120. DO_ERROR_INFO(special_op_exception, SIGILL, ILL_ILLOPN,
  121. "special operation exception")
  122. DO_ERROR_INFO(transaction_exception, SIGILL, ILL_ILLOPN,
  123. "transaction constraint exception")
  124. static inline void do_fp_trap(struct pt_regs *regs, __u32 fpc)
  125. {
  126. int si_code = 0;
  127. /* FPC[2] is Data Exception Code */
  128. if ((fpc & 0x00000300) == 0) {
  129. /* bits 6 and 7 of DXC are 0 iff IEEE exception */
  130. if (fpc & 0x8000) /* invalid fp operation */
  131. si_code = FPE_FLTINV;
  132. else if (fpc & 0x4000) /* div by 0 */
  133. si_code = FPE_FLTDIV;
  134. else if (fpc & 0x2000) /* overflow */
  135. si_code = FPE_FLTOVF;
  136. else if (fpc & 0x1000) /* underflow */
  137. si_code = FPE_FLTUND;
  138. else if (fpc & 0x0800) /* inexact */
  139. si_code = FPE_FLTRES;
  140. }
  141. do_trap(regs, SIGFPE, si_code, "floating point exception");
  142. }
  143. void translation_exception(struct pt_regs *regs)
  144. {
  145. /* May never happen. */
  146. panic("Translation exception");
  147. }
  148. void illegal_op(struct pt_regs *regs)
  149. {
  150. siginfo_t info;
  151. __u8 opcode[6];
  152. __u16 __user *location;
  153. int is_uprobe_insn = 0;
  154. int signal = 0;
  155. location = get_trap_ip(regs);
  156. if (user_mode(regs)) {
  157. if (get_user(*((__u16 *) opcode), (__u16 __user *) location))
  158. return;
  159. if (*((__u16 *) opcode) == S390_BREAKPOINT_U16) {
  160. if (current->ptrace) {
  161. info.si_signo = SIGTRAP;
  162. info.si_errno = 0;
  163. info.si_code = TRAP_BRKPT;
  164. info.si_addr = location;
  165. force_sig_info(SIGTRAP, &info, current);
  166. } else
  167. signal = SIGILL;
  168. #ifdef CONFIG_UPROBES
  169. } else if (*((__u16 *) opcode) == UPROBE_SWBP_INSN) {
  170. is_uprobe_insn = 1;
  171. #endif
  172. } else
  173. signal = SIGILL;
  174. }
  175. /*
  176. * We got either an illegal op in kernel mode, or user space trapped
  177. * on a uprobes illegal instruction. See if kprobes or uprobes picks
  178. * it up. If not, SIGILL.
  179. */
  180. if (is_uprobe_insn || !user_mode(regs)) {
  181. if (notify_die(DIE_BPT, "bpt", regs, 0,
  182. 3, SIGTRAP) != NOTIFY_STOP)
  183. signal = SIGILL;
  184. }
  185. if (signal)
  186. do_trap(regs, signal, ILL_ILLOPC, "illegal operation");
  187. }
  188. NOKPROBE_SYMBOL(illegal_op);
  189. DO_ERROR_INFO(specification_exception, SIGILL, ILL_ILLOPN,
  190. "specification exception");
  191. void vector_exception(struct pt_regs *regs)
  192. {
  193. int si_code, vic;
  194. if (!MACHINE_HAS_VX) {
  195. do_trap(regs, SIGILL, ILL_ILLOPN, "illegal operation");
  196. return;
  197. }
  198. /* get vector interrupt code from fpc */
  199. save_fpu_regs();
  200. vic = (current->thread.fpu.fpc & 0xf00) >> 8;
  201. switch (vic) {
  202. case 1: /* invalid vector operation */
  203. si_code = FPE_FLTINV;
  204. break;
  205. case 2: /* division by zero */
  206. si_code = FPE_FLTDIV;
  207. break;
  208. case 3: /* overflow */
  209. si_code = FPE_FLTOVF;
  210. break;
  211. case 4: /* underflow */
  212. si_code = FPE_FLTUND;
  213. break;
  214. case 5: /* inexact */
  215. si_code = FPE_FLTRES;
  216. break;
  217. default: /* unknown cause */
  218. si_code = 0;
  219. }
  220. do_trap(regs, SIGFPE, si_code, "vector exception");
  221. }
  222. void data_exception(struct pt_regs *regs)
  223. {
  224. int signal = 0;
  225. save_fpu_regs();
  226. if (current->thread.fpu.fpc & FPC_DXC_MASK)
  227. signal = SIGFPE;
  228. else
  229. signal = SIGILL;
  230. if (signal == SIGFPE)
  231. do_fp_trap(regs, current->thread.fpu.fpc);
  232. else if (signal)
  233. do_trap(regs, signal, ILL_ILLOPN, "data exception");
  234. }
  235. void space_switch_exception(struct pt_regs *regs)
  236. {
  237. /* Set user psw back to home space mode. */
  238. if (user_mode(regs))
  239. regs->psw.mask |= PSW_ASC_HOME;
  240. /* Send SIGILL. */
  241. do_trap(regs, SIGILL, ILL_PRVOPC, "space switch event");
  242. }
  243. void kernel_stack_overflow(struct pt_regs *regs)
  244. {
  245. bust_spinlocks(1);
  246. printk("Kernel stack overflow.\n");
  247. show_regs(regs);
  248. bust_spinlocks(0);
  249. panic("Corrupt kernel stack, can't continue.");
  250. }
  251. NOKPROBE_SYMBOL(kernel_stack_overflow);
  252. void __init trap_init(void)
  253. {
  254. local_mcck_enable();
  255. }