| Linus Torvalds | 1da177e | 2005-04-16 15:20:36 -0700 | [diff] [blame] | 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 |  | 
|  | 20 | int | 
|  | 21 | ia32_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 |  | 
|  | 40 | int | 
|  | 41 | ia32_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 | } |