📄 traps.c
字号:
/* * Architecture-specific trap handling. * * Copyright (C) 1998-2001 Hewlett-Packard Co * David Mosberger-Tang <davidm@hpl.hp.com> * * 05/12/00 grao <goutham.rao@intel.com> : added isr in siginfo for SIGFPE *//* * fp_emulate() 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 <linux/vt_kern.h> /* For unblank_screen() */#include <asm/hardirq.h>#include <asm/ia32.h>#include <asm/processor.h>#include <asm/uaccess.h>#include <asm/fpswa.h>extern spinlock_t timerlist_lock;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) /* FPSWA fixup: make the interface pointer a kernel virtual address: */ fpswa_interface = __va(ia64_boot_param->fpswa);}/* * Unlock any spinlocks which will prevent us from getting the message out (timerlist_lock * is acquired through the console unblank code) */voidbust_spinlocks (int yes){ spin_lock_init(&timerlist_lock); if (yes) { oops_in_progress = 1;#ifdef CONFIG_SMP global_irq_lock = 0; /* Many serial drivers do __global_cli() */#endif } else { int loglevel_save = console_loglevel;#ifdef CONFIG_VT unblank_screen();#endif oops_in_progress = 0; /* * OK, the message is on the console. Now we call printk() without * oops_in_progress set so that printk will give klogd a poke. Hold onto * your hats... */ console_loglevel = 15; /* NMI oopser may have shut the console up */ printk(" "); console_loglevel = loglevel_save; }}voiddie (const char *str, struct pt_regs *regs, long err){ static struct { spinlock_t lock; int lock_owner; int lock_owner_depth; } die = { lock: SPIN_LOCK_UNLOCKED, lock_owner: -1, lock_owner_depth: 0 }; if (die.lock_owner != smp_processor_id()) { console_verbose(); spin_lock_irq(&die.lock); die.lock_owner = smp_processor_id(); die.lock_owner_depth = 0; bust_spinlocks(1); } if (++die.lock_owner_depth < 3) { printk("%s[%d]: %s %ld\n", current->comm, current->pid, str, err); show_regs(regs); } else printk(KERN_ERR "Recursive die() failure, output suppressed\n"); bust_spinlocks(0); die.lock_owner = -1; spin_unlock_irq(&die.lock); do_exit(SIGSEGV);}voiddie_if_kernel (char *str, struct pt_regs *regs, long err){ if (!user_mode(regs)) die(str, regs, err);}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 f32..f127 * and 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 "Disabled 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){ struct ia64_fpreg f6_11[6]; fp_state_t fp_state; fpswa_ret_t ret; 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. */ fp_state.bitmask_low64 = 0xfc0; /* bit6..bit11 */ f6_11[0] = regs->f6; f6_11[1] = regs->f7; f6_11[2] = regs->f8; f6_11[3] = regs->f9; __asm__ ("stf.spill %0=f10%P0" : "=m"(f6_11[4])); __asm__ ("stf.spill %0=f11%P0" : "=m"(f6_11[5])); fp_state.fp_state_low_volatile = (fp_state_low_volatile_t *) f6_11; /* * unsigned long (*EFI_FPSWA) ( * unsigned long trap_type, * void *Bundle, * unsigned long *pipsr, * unsigned long *pfsr, * unsigned long *pisr, * unsigned long *ppreds,
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -