patch-2.4.15 linux/arch/ia64/kernel/traps.c
Next file: linux/arch/ia64/kernel/unaligned.c
Previous file: linux/arch/ia64/kernel/time.c
Back to the patch index
Back to the overall index
- Lines: 195
- Date:
Fri Nov 9 14:26:17 2001
- Orig file:
v2.4.14/linux/arch/ia64/kernel/traps.c
- Orig date:
Sun Aug 12 13:27:58 2001
diff -u --recursive --new-file v2.4.14/linux/arch/ia64/kernel/traps.c linux/arch/ia64/kernel/traps.c
@@ -1,20 +1,19 @@
/*
* Architecture-specific trap handling.
*
- * Copyright (C) 1998-2000 Hewlett-Packard Co
- * Copyright (C) 1998-2000 David Mosberger-Tang <davidm@hpl.hp.com>
+ * 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
*/
/*
- * 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.
+ * 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");
@@ -33,13 +32,17 @@
#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 __init
@@ -51,30 +54,74 @@
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)
+ */
void
-die_if_kernel (char *str, struct pt_regs *regs, long err)
+bust_spinlocks (int yes)
{
- 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);
+ 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
- return;
+ } 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;
}
+}
- printk("%s[%d]: %s %ld\n", current->comm, current->pid, str, err);
-
- show_regs(regs);
+void
+die (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 (current->thread.flags & IA64_KERNEL_DEATH) {
- printk("die_if_kernel recursion detected.\n");
- sti();
- while (1);
+ 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);
}
- current->thread.flags |= IA64_KERNEL_DEATH;
- do_exit(SIGSEGV);
+
+ 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);
+}
+
+void
+die_if_kernel (char *str, struct pt_regs *regs, long err)
+{
+ if (!user_mode(regs))
+ die(str, regs, err);
}
void
@@ -169,14 +216,12 @@
}
/*
- * 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.
+ * 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 void
disabled_fph_fault (struct pt_regs *regs)
@@ -277,7 +322,7 @@
if (jiffies - last_time > 5*HZ)
fpu_swa_count = 0;
- if (++fpu_swa_count < 5) {
+ if ((++fpu_swa_count < 5) && !(current->thread.flags & IA64_THREAD_FPEMU_NOPRINT)) {
last_time = jiffies;
printk(KERN_WARNING "%s(%d): floating-point assist fault at ip %016lx\n",
current->comm, current->pid, regs->cr_iip + ia64_psr(regs)->ri);
@@ -478,12 +523,12 @@
case 32: /* fp fault */
case 33: /* fp trap */
result = handle_fpu_swa((vector == 32) ? 1 : 0, regs, isr);
- if (result < 0) {
+ if ((result < 0) || (current->thread.flags & IA64_THREAD_FPEMU_SIGFPE)) {
siginfo.si_signo = SIGFPE;
siginfo.si_errno = 0;
siginfo.si_code = FPE_FLTINV;
siginfo.si_addr = (void *) (regs->cr_iip + ia64_psr(regs)->ri);
- force_sig(SIGFPE, current);
+ force_sig_info(SIGFPE, &siginfo, current);
}
return;
@@ -510,6 +555,10 @@
break;
case 46:
+#ifdef CONFIG_IA32_SUPPORT
+ if (ia32_intercept(regs, isr) == 0)
+ return;
+#endif
printk("Unexpected IA-32 intercept trap (Trap 46)\n");
printk(" iip - 0x%lx, ifa - 0x%lx, isr - 0x%lx, iim - 0x%lx\n",
regs->cr_iip, ifa, isr, iim);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)