📄 traps.c
字号:
/* * Architecture-specific trap handling. * * Copyright (C) 1998-2000 Hewlett-Packard Co * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com> * * 05/12/00 grao <goutham.rao@intel.com> : added isr in siginfo for SIGFPE */#define FPSWA_DEBUG 1/* * The fpu_fault() handler needs to be able to access and update all * floating point registers. Those saved in pt_regs can be accessed * through that structure, but those not saved, will be accessed * directly. To make this work, we need to ensure that the compiler * does not end up using a preserved floating point register on its * own. The following achieves this by declaring preserved registers * that are not marked as "fixed" as global register variables. */register double f2 asm ("f2"); register double f3 asm ("f3");register double f4 asm ("f4"); register double f5 asm ("f5");register long f16 asm ("f16"); register long f17 asm ("f17");register long f18 asm ("f18"); register long f19 asm ("f19");register long f20 asm ("f20"); register long f21 asm ("f21");register long f22 asm ("f22"); register long f23 asm ("f23");register double f24 asm ("f24"); register double f25 asm ("f25");register double f26 asm ("f26"); register double f27 asm ("f27");register double f28 asm ("f28"); register double f29 asm ("f29");register double f30 asm ("f30"); register double f31 asm ("f31");#include <linux/config.h>#include <linux/kernel.h>#include <linux/init.h>#include <linux/sched.h>#include <asm/ia32.h>#include <asm/processor.h>#include <asm/uaccess.h>#include <asm/fpswa.h>static fpswa_interface_t *fpswa_interface;void __inittrap_init (void){ printk("fpswa interface at %lx\n", ia64_boot_param.fpswa); if (ia64_boot_param.fpswa) {#define OLD_FIRMWARE#ifdef OLD_FIRMWARE /* * HACK to work around broken firmware. This code * applies the label fixup to the FPSWA interface and * works both with old and new (fixed) firmware. */ unsigned long addr = (unsigned long) __va(ia64_boot_param.fpswa); unsigned long gp_val = *(unsigned long *)(addr + 8); /* go indirect and indexed to get table address */ addr = gp_val; gp_val = *(unsigned long *)(addr + 8); while (gp_val == *(unsigned long *)(addr + 8)) { *(unsigned long *)addr |= PAGE_OFFSET; *(unsigned long *)(addr + 8) |= PAGE_OFFSET; addr += 16; }#endif /* FPSWA fixup: make the interface pointer a kernel virtual address: */ fpswa_interface = __va(ia64_boot_param.fpswa); }}voiddie_if_kernel (char *str, struct pt_regs *regs, long err){ if (user_mode(regs)) {#if 0 /* XXX for debugging only */ printk ("!!die_if_kernel: %s(%d): %s %ld\n", current->comm, current->pid, str, err); show_regs(regs);#endif return; } printk("%s[%d]: %s %ld\n", current->comm, current->pid, str, err); show_regs(regs); if (current->thread.flags & IA64_KERNEL_DEATH) { printk("die_if_kernel recursion detected.\n"); sti(); while (1); } current->thread.flags |= IA64_KERNEL_DEATH; do_exit(SIGSEGV);}voidia64_bad_break (unsigned long break_num, struct pt_regs *regs){ siginfo_t siginfo; int sig, code; /* SIGILL, SIGFPE, SIGSEGV, and SIGBUS want these field initialized: */ siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri); siginfo.si_imm = break_num; switch (break_num) { case 0: /* unknown error */ sig = SIGILL; code = ILL_ILLOPC; break; case 1: /* integer divide by zero */ sig = SIGFPE; code = FPE_INTDIV; break; case 2: /* integer overflow */ sig = SIGFPE; code = FPE_INTOVF; break; case 3: /* range check/bounds check */ sig = SIGFPE; code = FPE_FLTSUB; break; case 4: /* null pointer dereference */ sig = SIGSEGV; code = SEGV_MAPERR; break; case 5: /* misaligned data */ sig = SIGSEGV; code = BUS_ADRALN; break; case 6: /* decimal overflow */ sig = SIGFPE; code = __FPE_DECOVF; break; case 7: /* decimal divide by zero */ sig = SIGFPE; code = __FPE_DECDIV; break; case 8: /* packed decimal error */ sig = SIGFPE; code = __FPE_DECERR; break; case 9: /* invalid ASCII digit */ sig = SIGFPE; code = __FPE_INVASC; break; case 10: /* invalid decimal digit */ sig = SIGFPE; code = __FPE_INVDEC; break; case 11: /* paragraph stack overflow */ sig = SIGSEGV; code = __SEGV_PSTKOVF; break; default: if (break_num < 0x40000 || break_num > 0x100000) die_if_kernel("Bad break", regs, break_num); if (break_num < 0x80000) { sig = SIGILL; code = __ILL_BREAK; } else { sig = SIGTRAP; code = TRAP_BRKPT; } } siginfo.si_signo = sig; siginfo.si_errno = 0; siginfo.si_code = code; force_sig_info(sig, &siginfo, current);}/* * Unimplemented system calls. This is called only for stuff that * we're supposed to implement but haven't done so yet. Everything * else goes to sys_ni_syscall. */asmlinkage longia64_ni_syscall (unsigned long arg0, unsigned long arg1, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5, unsigned long arg6, unsigned long arg7, unsigned long stack){ struct pt_regs *regs = (struct pt_regs *) &stack; printk("<sc%ld(%lx,%lx,%lx,%lx)>\n", regs->r15, arg0, arg1, arg2, arg3); return -ENOSYS;}/* * disabled_fph_fault() is called when a user-level process attempts * to access one of the registers f32..f127 when it doesn't own the * fp-high register partition. When this happens, we save the current * fph partition in the task_struct of the fpu-owner (if necessary) * and then load the fp-high partition of the current task (if * necessary). Note that the kernel has access to fph by the time we * get here, as the IVT's "Diabled FP-Register" handler takes care of * clearing psr.dfh. */static inline voiddisabled_fph_fault (struct pt_regs *regs){ struct ia64_psr *psr = ia64_psr(regs); /* first, grant user-level access to fph partition: */ psr->dfh = 0;#ifndef CONFIG_SMP { struct task_struct *fpu_owner = ia64_get_fpu_owner(); if (fpu_owner == current) return; if (fpu_owner) ia64_flush_fph(fpu_owner); ia64_set_fpu_owner(current); }#endif /* !CONFIG_SMP */ if ((current->thread.flags & IA64_THREAD_FPH_VALID) != 0) { __ia64_load_fpu(current->thread.fph); psr->mfh = 0; } else { __ia64_init_fpu(); /* * Set mfh because the state in thread.fph does not match the state in * the fph partition. */ psr->mfh = 1; }}static inline intfp_emulate (int fp_fault, void *bundle, long *ipsr, long *fpsr, long *isr, long *pr, long *ifs, struct pt_regs *regs){ fp_state_t fp_state; fpswa_ret_t ret;#ifdef FPSWA_BUG struct ia64_fpreg f6_15[10];#endif if (!fpswa_interface) return -1; memset(&fp_state, 0, sizeof(fp_state_t)); /* * compute fp_state. only FP registers f6 - f11 are used by the * kernel, so set those bits in the mask and set the low volatile * pointer to point to these registers. */#ifndef FPSWA_BUG fp_state.bitmask_low64 = 0x3c0; /* bit 6..9 */ fp_state.fp_state_low_volatile = (fp_state_low_volatile_t *) ®s->f6;#else fp_state.bitmask_low64 = 0xffc0; /* bit6..bit15 */ f6_15[0] = regs->f6; f6_15[1] = regs->f7; f6_15[2] = regs->f8; f6_15[3] = regs->f9; __asm__ ("stf.spill %0=f10%P0" : "=m"(f6_15[4])); __asm__ ("stf.spill %0=f11%P0" : "=m"(f6_15[5])); __asm__ ("stf.spill %0=f12%P0" : "=m"(f6_15[6])); __asm__ ("stf.spill %0=f13%P0" : "=m"(f6_15[7])); __asm__ ("stf.spill %0=f14%P0" : "=m"(f6_15[8])); __asm__ ("stf.spill %0=f15%P0" : "=m"(f6_15[9])); fp_state.fp_state_low_volatile = (fp_state_low_volatile_t *) f6_15;#endif /* * unsigned long (*EFI_FPSWA) ( * unsigned long trap_type, * void *Bundle, * unsigned long *pipsr, * unsigned long *pfsr, * unsigned long *pisr, * unsigned long *ppreds, * unsigned long *pifs, * void *fp_state); */ ret = (*fpswa_interface->fpswa)((unsigned long) fp_fault, bundle, (unsigned long *) ipsr, (unsigned long *) fpsr, (unsigned long *) isr, (unsigned long *) pr, (unsigned long *) ifs, &fp_state);#ifdef FPSWA_BUG
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -