patch-2.1.29 linux/arch/sparc/mm/fault.c
Next file: linux/arch/sparc/mm/srmmu.c
Previous file: linux/arch/sparc/lib/memset.S
Back to the patch index
Back to the overall index
- Lines: 175
- Date:
Wed Mar 5 17:04:30 1997
- Orig file:
v2.1.28/linux/arch/sparc/mm/fault.c
- Orig date:
Sun Jan 26 02:07:09 1997
diff -u --recursive --new-file v2.1.28/linux/arch/sparc/mm/fault.c linux/arch/sparc/mm/fault.c
@@ -1,8 +1,9 @@
-/* $Id: fault.c,v 1.86 1997/01/06 06:52:52 davem Exp $
+/* $Id: fault.c,v 1.89 1997/03/04 16:26:46 jj Exp $
* fault.c: Page fault handlers for the Sparc.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
* Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
*/
#include <asm/head.h>
@@ -133,6 +134,58 @@
prom_halt();
}
+void unhandled_fault(unsigned long address, struct task_struct *tsk,
+ struct pt_regs *regs)
+{
+ if((unsigned long) address < PAGE_SIZE) {
+ printk(KERN_ALERT "Unable to handle kernel NULL "
+ "pointer dereference");
+ } else {
+ printk(KERN_ALERT "Unable to handle kernel paging request "
+ "at virtual address %08lx\n", address);
+ }
+ printk(KERN_ALERT "tsk->mm->context = %08lx\n",
+ (unsigned long) tsk->mm->context);
+ printk(KERN_ALERT "tsk->mm->pgd = %08lx\n",
+ (unsigned long) tsk->mm->pgd);
+ die_if_kernel("Oops", regs);
+}
+
+asmlinkage int lookup_fault(unsigned long pc, unsigned long ret_pc,
+ unsigned long address)
+{
+ unsigned long g2;
+ int i;
+ unsigned insn;
+ struct pt_regs regs;
+
+ i = search_exception_table (ret_pc, &g2);
+ switch (i) {
+ /* load & store will be handled by fixup */
+ case 3: return 3;
+ /* store will be handled by fixup, load will bump out */
+ /* for _to_ macros */
+ case 1: insn = (unsigned *)pc; if ((insn >> 21) & 1) return 1; break;
+ /* load will be handled by fixup, store will bump out */
+ /* for _from_ macros */
+ case 2: insn = (unsigned *)pc;
+ if (!((insn >> 21) & 1) || ((insn>>19)&0x3f) == 15) return 2;
+ break;
+ default: break;
+ }
+ memset (®s, 0, sizeof (regs));
+ regs.pc = pc;
+ regs.npc = pc + 4;
+ __asm__ __volatile__ ("
+ rd %%psr, %0
+ nop
+ nop
+ nop" : "=r" (regs.psr));
+ unhandled_fault (address, current, ®s);
+ /* Not reached */
+ return 0;
+}
+
asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write,
unsigned long address)
{
@@ -142,34 +195,11 @@
unsigned int fixup;
unsigned long g2;
int from_user = !(regs->psr & PSR_PS);
-#if 0
- static unsigned long last_one;
-#endif
lock_kernel();
down(&mm->mmap_sem);
if(text_fault)
address = regs->pc;
-#if 0
- if(current->tss.ex.count) {
- printk("f<pid=%d,tf=%d,wr=%d,addr=%08lx,pc=%08lx>\n",
- tsk->pid, text_fault, write, address, regs->pc);
- printk("EX: count<%d> pc<%08lx> expc<%08lx> address<%08lx>\n",
- (int) current->tss.ex.count, current->tss.ex.pc,
- current->tss.ex.expc, current->tss.ex.address);
-#if 0
- if(last_one == address) {
- printk("Twice in a row, AIEEE. Spinning so you can see the dump.\n");
- show_regs(regs);
- sti();
- while(1)
- barrier();
- }
- last_one = address;
-#endif
- }
-#endif
-
/* The kernel referencing a bad kernel pointer can lock up
* a sun4c machine completely, so we must attempt recovery.
*/
@@ -211,32 +241,25 @@
g2 = regs->u_regs[UREG_G2];
if (!from_user && (fixup = search_exception_table (regs->pc, &g2))) {
- printk("Exception: PC<%08lx> faddr<%08lx>\n", regs->pc, address);
- printk("EX_TABLE: insn<%08lx> fixup<%08x> g2<%08lx>\n",
- regs->pc, fixup, g2);
- regs->pc = fixup;
- regs->npc = regs->pc + 4;
- regs->u_regs[UREG_G2] = g2;
- goto out;
- }
- /* Did we have an exception handler installed? */
- if(current->tss.ex.count == 1) {
- if(from_user) {
- printk("Yieee, exception signalled from user mode.\n");
- } else {
- /* Set pc to %g1, set %g1 to -EFAULT and %g2 to
- * the faulting address so we can cleanup.
- */
+ if (fixup > 10) { /* Values below are reserved for other things */
+ extern const unsigned __memset_start[];
+ extern const unsigned __memset_end[];
+ extern const unsigned __csum_partial_copy_start[];
+ extern const unsigned __csum_partial_copy_end[];
+
printk("Exception: PC<%08lx> faddr<%08lx>\n", regs->pc, address);
- printk("EX: count<%d> pc<%08lx> expc<%08lx> address<%08lx>\n",
- (int) current->tss.ex.count, current->tss.ex.pc,
- current->tss.ex.expc, current->tss.ex.address);
- current->tss.ex.count = 0;
- regs->pc = current->tss.ex.expc;
+ printk("EX_TABLE: insn<%08lx> fixup<%08x> g2<%08lx>\n",
+ regs->pc, fixup, g2);
+ if ((regs->pc >= (unsigned long)__memset_start &&
+ regs->pc < (unsigned long)__memset_end) ||
+ (regs->pc >= (unsigned long)__csum_partial_copy_start &&
+ regs->pc < (unsigned long)__csum_partial_copy_end)) {
+ regs->u_regs[UREG_I4] = address;
+ regs->u_regs[UREG_I5] = regs->pc;
+ }
+ regs->u_regs[UREG_G2] = g2;
+ regs->pc = fixup;
regs->npc = regs->pc + 4;
- regs->u_regs[UREG_G1] = -EFAULT;
- regs->u_regs[UREG_G2] = address - current->tss.ex.address;
- regs->u_regs[UREG_G3] = current->tss.ex.pc;
goto out;
}
}
@@ -250,18 +273,7 @@
send_sig(SIGSEGV, tsk, 1);
goto out;
}
- if((unsigned long) address < PAGE_SIZE) {
- printk(KERN_ALERT "Unable to handle kernel NULL "
- "pointer dereference");
- } else {
- printk(KERN_ALERT "Unable to handle kernel paging request "
- "at virtual address %08lx\n", address);
- }
- printk(KERN_ALERT "tsk->mm->context = %08lx\n",
- (unsigned long) tsk->mm->context);
- printk(KERN_ALERT "tsk->mm->pgd = %08lx\n",
- (unsigned long) tsk->mm->pgd);
- die_if_kernel("Oops", regs);
+ unhandled_fault (address, tsk, regs);
out:
unlock_kernel();
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov