patch-2.1.43 linux/arch/sparc64/kernel/traps.c
Next file: linux/arch/sparc64/kernel/ttable.S
Previous file: linux/arch/sparc64/kernel/systbls.S
Back to the patch index
Back to the overall index
- Lines: 226
- Date:
Thu Jun 12 16:22:05 1997
- Orig file:
v2.1.42/linux/arch/sparc64/kernel/traps.c
- Orig date:
Thu May 29 21:53:04 1997
diff -u --recursive --new-file v2.1.42/linux/arch/sparc64/kernel/traps.c linux/arch/sparc64/kernel/traps.c
@@ -1,7 +1,7 @@
-/* $Id: traps.c,v 1.13 1997/05/27 19:30:08 jj Exp $
+/* $Id: traps.c,v 1.19 1997/06/05 06:22:49 davem Exp $
* arch/sparc/kernel/traps.c
*
- * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu)
* Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
*/
@@ -23,6 +23,7 @@
#include <asm/pgtable.h>
#include <asm/unistd.h>
#include <asm/uaccess.h>
+#include <asm/fpumacro.h>
/* #define SYSCALL_TRACING */
/* #define VERBOSE_SYSCALL_TRACING */
@@ -122,7 +123,8 @@
int i;
#endif
- printk("SYS[%s:%d]: <%d> ", current->comm, current->pid, (int)g1);
+ printk("SYS[%s:%d]: PC(%016lx) <%3d> ",
+ current->comm, current->pid, regs->tpc, (int)g1);
#ifdef VERBOSE_SYSCALL_TRACING
sdp = NULL;
for(i = 0; i < NUM_SDESC_ENTRIES; i++)
@@ -151,7 +153,7 @@
unsigned long syscall_trace_exit(unsigned long retval, struct pt_regs *regs)
{
- printk("ret[%08x]\n", (unsigned int) retval);
+ printk("ret[%016lx]\n", retval);
return retval;
}
#endif /* SYSCALL_TRACING */
@@ -254,25 +256,143 @@
barrier();
}
+static unsigned long init_fsr = 0x0UL;
+static unsigned int init_fregs[64] __attribute__ ((aligned (64))) =
+ { ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U,
+ ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U,
+ ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U,
+ ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U,
+ ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U,
+ ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U,
+ ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U,
+ ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U, ~0U };
+
void do_fpdis(struct pt_regs *regs)
{
- printk("FPDIS: at %016lx\n", regs->tpc);
- while(1)
- barrier();
+ lock_kernel();
+
+ regs->tstate |= TSTATE_PEF;
+ fprs_write(FPRS_FEF);
+
+ /* This is allowed now because the V9 ABI varargs passes floating
+ * point args in floating point registers, so vsprintf() and sprintf()
+ * cause problems. Luckily we never actually pass floating point values
+ * to those routines in the kernel and the code generated just does
+ * stores of them to the stack. Therefore, for the moment this fix
+ * is sufficient. -DaveM
+ */
+ if(regs->tstate & TSTATE_PRIV)
+ goto out;
+
+#ifndef __SMP__
+ if(last_task_used_math == current)
+ goto out;
+ if(last_task_used_math) {
+ struct task_struct *fptask = last_task_used_math;
+
+ if(fptask->tss.flags & SPARC_FLAG_32BIT)
+ fpsave32((unsigned long *)&fptask->tss.float_regs[0],
+ &fptask->tss.fsr);
+ else
+ fpsave((unsigned long *)&fptask->tss.float_regs[0],
+ &fptask->tss.fsr);
+ }
+ last_task_used_math = current;
+ if(current->used_math) {
+ if(current->tss.flags & SPARC_FLAG_32BIT)
+ fpload32(¤t->tss.float_regs[0],
+ ¤t->tss.fsr);
+ else
+ fpload(¤t->tss.float_regs[0],
+ ¤t->tss.fsr);
+ } else {
+ /* Set inital sane state. */
+ fpload(&init_fregs[0], &init_fsr);
+ current->used_math = 1;
+ }
+#else
+ if(!current->used_math) {
+ fpload(&init_fregs[0], &init_fsr);
+ current->used_math = 1;
+ } else {
+ if(current->tss.flags & SPARC_FLAG_32BIT)
+ fpload32(¤t->tss.float_regs[0],
+ ¤t->tss.fsr);
+ else
+ fpload(¤t->tss.float_regs[0],
+ ¤t->tss.fsr);
+ }
+ current->flags |= PF_USEDFPU;
+#endif
+#ifndef __SMP__
+out:
+#endif
+ unlock_kernel();
+}
+
+static unsigned long fake_regs[32] __attribute__ ((aligned (8)));
+static unsigned long fake_fsr;
+
+void do_fpe_common(struct pt_regs *regs)
+{
+ static int calls = 0;
+#ifndef __SMP__
+ struct task_struct *fpt = last_task_used_math;
+#else
+ struct task_struct *fpt = current;
+#endif
+
+ lock_kernel();
+ fprs_write(FPRS_FEF);
+
+#ifndef __SMP__
+ if(!fpt) {
+#else
+ if(!(fpt->flags & PF_USEDFPU)) {
+#endif
+ fpsave(&fake_regs[0], &fake_fsr);
+ regs->tstate &= ~(TSTATE_PEF);
+ goto out;
+ }
+ if(fpt->tss.flags & SPARC_FLAG_32BIT)
+ fpsave32((unsigned long *)&fpt->tss.float_regs[0], &fpt->tss.fsr);
+ else
+ fpsave((unsigned long *)&fpt->tss.float_regs[0], &fpt->tss.fsr);
+ fpt->tss.sig_address = regs->tpc;
+ fpt->tss.sig_desc = SUBSIG_FPERROR;
+#ifdef __SMP__
+ fpt->flags &= ~PF_USEDFPU;
+#endif
+ if(regs->tstate & TSTATE_PRIV) {
+ printk("WARNING: FPU exception from kernel mode. at pc=%016lx\n",
+ regs->tpc);
+ regs->tpc = regs->tnpc;
+ regs->tnpc += 4;
+ calls++;
+ if(calls > 2)
+ die_if_kernel("Too many Penguin-FPU traps from kernel mode",
+ regs);
+ goto out;
+ }
+ send_sig(SIGFPE, fpt, 1);
+#ifndef __SMP__
+ last_task_used_math = NULL;
+#endif
+ regs->tstate &= ~TSTATE_PEF;
+ if(calls > 0)
+ calls = 0;
+out:
+ unlock_kernel();
}
void do_fpieee(struct pt_regs *regs)
{
- printk("FPIEEE: at %016lx\n", regs->tpc);
- while(1)
- barrier();
+ do_fpe_common(regs);
}
void do_fpother(struct pt_regs *regs)
{
- printk("FPOTHER: at %016lx\n", regs->tpc);
- while(1)
- barrier();
+ do_fpe_common(regs);
}
void do_tof(struct pt_regs *regs)
@@ -352,23 +472,29 @@
printk("Ill instr. at pc=%016lx ", pc);
get_user(insn, ((unsigned int *)pc));
printk("insn=[%08x]\n", insn);
+ show_regs(regs);
}
#endif
current->tss.sig_address = pc;
current->tss.sig_desc = SUBSIG_ILLINST;
send_sig(SIGILL, current, 1);
unlock_kernel();
-
- while(1)
- barrier();
}
-void do_mna(struct pt_regs *regs)
+void mem_address_unaligned(struct pt_regs *regs)
{
printk("AIEEE: do_mna at %016lx\n", regs->tpc);
show_regs(regs);
- while(1)
- barrier();
+ if(regs->tstate & TSTATE_PRIV) {
+ printk("MNA from kernel, spinning\n");
+ sti();
+ while(1)
+ barrier();
+ } else {
+ current->tss.sig_address = regs->tpc;
+ current->tss.sig_desc = SUBSIG_PRIVINST;
+ send_sig(SIGBUS, current, 1);
+ }
}
void do_privop(struct pt_regs *regs)
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov