You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
156 lines
3.7 KiB
156 lines
3.7 KiB
/*
|
|
* 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;
|
|
}
|
|
|