patch-2.1.29 linux/arch/sparc64/mm/fault.c

Next file: linux/arch/sparc64/prom/Makefile
Previous file: linux/arch/sparc64/lib/memset.S
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.28/linux/arch/sparc64/mm/fault.c linux/arch/sparc64/mm/fault.c
@@ -1,7 +1,8 @@
-/* $Id: fault.c,v 1.2 1996/12/26 18:03:04 davem Exp $
+/* $Id: fault.c,v 1.3 1997/03/04 16:27:02 jj Exp $
  * arch/sparc64/mm/fault.c: Page fault handlers for the 64-bit Sparc.
  *
  * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
  */
 
 #define ELEMENTS(arr) (sizeof (arr)/sizeof (arr[0]))
@@ -70,6 +71,54 @@
 	return total;
 }
 
+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 %016lx\n", (unsigned long)address);
+	}
+	printk(KERN_ALERT "tsk->mm->context = %016lx\n",
+	       (unsigned long) tsk->mm->context);
+	printk(KERN_ALERT "tsk->mm->pgd = %016lx\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 (&regs, 0, sizeof (regs));
+	regs.pc = pc;
+	regs.npc = pc + 4;
+	/* FIXME: Should set up regs->tstate? */
+	unhandled_fault (address, current, &regs);
+	/* Not reached */
+	return 0;
+}
+
 asmlinkage void do_sparc64_fault(struct pt_regs *regs, int text_fault, int write,
 				 unsigned long address)
 {
@@ -80,6 +129,7 @@
 	unsigned long g2;
 	int from_user = !(regs->tstate & TSTATE_PRIV);
 
+	lock_kernel ();
 	down(&mm->mmap_sem);
 	vma = find_vma(mm, address);
 	if(!vma)
@@ -105,33 +155,7 @@
 	}
 	handle_mm_fault(vma, address, write);
 	up(&mm->mmap_sem);
-	return;
-
-	vma = find_vma(mm, address);
-	if(!vma)
-		goto bad_area;
-	if(vma->vm_start <= address)
-		goto good_area;
-	if(!(vma->vm_flags & VM_GROWSDOWN))
-		goto bad_area;
-	if(expand_stack(vma, address))
-		goto bad_area;
-	/*
-	 * Ok, we have a good vm_area for this memory access, so
-	 * we can handle it..
-	 */
-good_area:
-	if(write) {
-		if(!(vma->vm_flags & VM_WRITE))
-			goto bad_area;
-	} else {
-		/* Allow reads even for write-only mappings */
-		if(!(vma->vm_flags & (VM_READ | VM_EXEC)))
-			goto bad_area;
-	}
-	handle_mm_fault(vma, address, write);
-	up(&mm->mmap_sem);
-	return;
+	goto out;
 	/*
 	 * Something tried to access memory that isn't in our memory map..
 	 * Fix it, but check if it's kernel or user first..
@@ -142,34 +166,13 @@
 	
 	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",
+		printk("Exception: PC<%016lx> faddr<%016lx>\n", regs->pc, address);
+		printk("EX_TABLE: insn<%016lx> fixup<%016lx> g2<%016lx>\n",
 			regs->pc, fixup, g2);
 		regs->pc = fixup;
 		regs->npc = regs->pc + 4;
 		regs->u_regs[UREG_G2] = g2;
-		return;
-	}
-	/* 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.
-			 */
-			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;
-			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;
-			return;
-		}
+		goto out;
 	}
 	if(from_user) {
 #if 0
@@ -179,18 +182,9 @@
 		tsk->tss.sig_address = address;
 		tsk->tss.sig_desc = SUBSIG_NOMAPPING;
 		send_sig(SIGSEGV, tsk, 1);
-		return;
+		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