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