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