|  | /* | 
|  | * 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; | 
|  | } |