ia32_traps.c 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. /*
  2. * IA-32 exception handlers
  3. *
  4. * Copyright (C) 2000 Asit K. Mallick <asit.k.mallick@intel.com>
  5. * Copyright (C) 2001-2002 Hewlett-Packard Co
  6. * David Mosberger-Tang <davidm@hpl.hp.com>
  7. *
  8. * 06/16/00 A. Mallick added siginfo for most cases (close to IA32)
  9. * 09/29/00 D. Mosberger added ia32_intercept()
  10. */
  11. #include <linux/kernel.h>
  12. #include <linux/sched.h>
  13. #include "ia32priv.h"
  14. #include <asm/intrinsics.h>
  15. #include <asm/ptrace.h>
  16. int
  17. ia32_intercept (struct pt_regs *regs, unsigned long isr)
  18. {
  19. switch ((isr >> 16) & 0xff) {
  20. case 0: /* Instruction intercept fault */
  21. case 4: /* Locked Data reference fault */
  22. case 1: /* Gate intercept trap */
  23. return -1;
  24. case 2: /* System flag trap */
  25. if (((isr >> 14) & 0x3) >= 2) {
  26. /* MOV SS, POP SS instructions */
  27. ia64_psr(regs)->id = 1;
  28. return 0;
  29. } else
  30. return -1;
  31. }
  32. return -1;
  33. }
  34. int
  35. ia32_exception (struct pt_regs *regs, unsigned long isr)
  36. {
  37. struct siginfo siginfo;
  38. /* initialize these fields to avoid leaking kernel bits to user space: */
  39. siginfo.si_errno = 0;
  40. siginfo.si_flags = 0;
  41. siginfo.si_isr = 0;
  42. siginfo.si_imm = 0;
  43. switch ((isr >> 16) & 0xff) {
  44. case 1:
  45. case 2:
  46. siginfo.si_signo = SIGTRAP;
  47. if (isr == 0)
  48. siginfo.si_code = TRAP_TRACE;
  49. else if (isr & 0x4)
  50. siginfo.si_code = TRAP_BRANCH;
  51. else
  52. siginfo.si_code = TRAP_BRKPT;
  53. break;
  54. case 3:
  55. siginfo.si_signo = SIGTRAP;
  56. siginfo.si_code = TRAP_BRKPT;
  57. break;
  58. case 0: /* Divide fault */
  59. siginfo.si_signo = SIGFPE;
  60. siginfo.si_code = FPE_INTDIV;
  61. break;
  62. case 4: /* Overflow */
  63. case 5: /* Bounds fault */
  64. siginfo.si_signo = SIGFPE;
  65. siginfo.si_code = 0;
  66. break;
  67. case 6: /* Invalid Op-code */
  68. siginfo.si_signo = SIGILL;
  69. siginfo.si_code = ILL_ILLOPN;
  70. break;
  71. case 7: /* FP DNA */
  72. case 8: /* Double Fault */
  73. case 9: /* Invalid TSS */
  74. case 11: /* Segment not present */
  75. case 12: /* Stack fault */
  76. case 13: /* General Protection Fault */
  77. siginfo.si_signo = SIGSEGV;
  78. siginfo.si_code = 0;
  79. break;
  80. case 16: /* Pending FP error */
  81. {
  82. unsigned long fsr, fcr;
  83. fsr = ia64_getreg(_IA64_REG_AR_FSR);
  84. fcr = ia64_getreg(_IA64_REG_AR_FCR);
  85. siginfo.si_signo = SIGFPE;
  86. /*
  87. * (~cwd & swd) will mask out exceptions that are not set to unmasked
  88. * status. 0x3f is the exception bits in these regs, 0x200 is the
  89. * C1 reg you need in case of a stack fault, 0x040 is the stack
  90. * fault bit. We should only be taking one exception at a time,
  91. * so if this combination doesn't produce any single exception,
  92. * then we have a bad program that isn't synchronizing its FPU usage
  93. * and it will suffer the consequences since we won't be able to
  94. * fully reproduce the context of the exception
  95. */
  96. siginfo.si_isr = isr;
  97. siginfo.si_flags = __ISR_VALID;
  98. switch(((~fcr) & (fsr & 0x3f)) | (fsr & 0x240)) {
  99. case 0x000:
  100. default:
  101. siginfo.si_code = 0;
  102. break;
  103. case 0x001: /* Invalid Op */
  104. case 0x040: /* Stack Fault */
  105. case 0x240: /* Stack Fault | Direction */
  106. siginfo.si_code = FPE_FLTINV;
  107. break;
  108. case 0x002: /* Denormalize */
  109. case 0x010: /* Underflow */
  110. siginfo.si_code = FPE_FLTUND;
  111. break;
  112. case 0x004: /* Zero Divide */
  113. siginfo.si_code = FPE_FLTDIV;
  114. break;
  115. case 0x008: /* Overflow */
  116. siginfo.si_code = FPE_FLTOVF;
  117. break;
  118. case 0x020: /* Precision */
  119. siginfo.si_code = FPE_FLTRES;
  120. break;
  121. }
  122. break;
  123. }
  124. case 17: /* Alignment check */
  125. siginfo.si_signo = SIGSEGV;
  126. siginfo.si_code = BUS_ADRALN;
  127. break;
  128. case 19: /* SSE Numeric error */
  129. siginfo.si_signo = SIGFPE;
  130. siginfo.si_code = 0;
  131. break;
  132. default:
  133. return -1;
  134. }
  135. force_sig_info(siginfo.si_signo, &siginfo, current);
  136. return 0;
  137. }