157 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			157 lines
		
	
	
		
			3.7 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/*
 | 
						|
 * 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;
 | 
						|
}
 |