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