patch-2.1.44 linux/arch/mips/mm/fault.c

Next file: linux/arch/mips/mm/init.c
Previous file: linux/arch/mips/mm/extable.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.1.43/linux/arch/mips/mm/fault.c linux/arch/mips/mm/fault.c
@@ -1,7 +1,7 @@
 /*
  *  arch/mips/mm/fault.c
  *
- *  Copyright (C) 1995 by Ralf Baechle
+ *  Copyright (C) 1995, 1996, 1997 by Ralf Baechle
  */
 #include <linux/signal.h>
 #include <linux/sched.h>
@@ -13,29 +13,43 @@
 #include <linux/ptrace.h>
 #include <linux/mman.h>
 #include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
 
-#include <asm/system.h>
-#include <asm/segment.h>
 #include <asm/pgtable.h>
+#include <asm/mmu_context.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
 
 extern void die_if_kernel(char *, struct pt_regs *, long);
 
+unsigned long asid_cache = ASID_FIRST_VERSION;
+
+/*
+ * Macro for exception fixup code to access integer registers.
+ */
+#define dpf_reg(r) (regs->regs[r])
+
 /*
  * This routine handles page faults.  It determines the address,
  * and the problem, and then passes it off to one of the appropriate
  * routines.
  */
-asmlinkage void
-do_page_fault(struct pt_regs *regs, unsigned long writeaccess, unsigned long address)
+asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long writeaccess,
+			      unsigned long address)
 {
 	struct vm_area_struct * vma;
+	struct task_struct *tsk = current;
+	struct mm_struct *mm = tsk->mm;
+	unsigned long fixup;
 
+	lock_kernel();
 #if 0
-	printk("do_page_fault() #1: %s %08lx (epc == %08lx, ra == %08lx)\n",
-	       writeaccess ? "writeaccess to" : "readaccess from",
-	       address, regs->cp0_epc, regs->reg31);
+	printk("[%s:%d:%08lx:%ld:%08lx]\n", current->comm, current->pid,
+	       address, writeaccess, regs->cp0_epc);
 #endif
-	vma = find_vma(current, address);
+	down(&mm->mmap_sem);
+	vma = find_vma(mm, address);
 	if (!vma)
 		goto bad_area;
 	if (vma->vm_start <= address)
@@ -56,29 +70,55 @@
 		if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
 			goto bad_area;
 	}
-	handle_mm_fault(vma, address, writeaccess);
-	/* FIXME: This flushes the cache far to often */
-	sys_cacheflush(address, PAGE_SIZE, BCACHE);
+	handle_mm_fault(tsk, vma, address, writeaccess);
+	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..
  */
 bad_area:
+	up(&mm->mmap_sem);
+	/* Did we have an exception handler installed? */
+
+	fixup = search_exception_table(regs->cp0_epc);
+	if (fixup) {
+		long new_epc;
+		new_epc = fixup_exception(dpf_reg, fixup, regs->cp0_epc);
+		printk(KERN_DEBUG "Exception at [<%lx>] (%lx)\n",
+		       regs->cp0_epc, new_epc);
+		regs->cp0_epc = new_epc;
+		goto out;
+	}
+
 	if (user_mode(regs)) {
+		tsk->tss.cp0_badvaddr = address;
+		tsk->tss.error_code = writeaccess;
+#if 1
+		printk("do_page_fault() #2: sending SIGSEGV to %s for illegal %s\n"
+		       "%08lx (epc == %08lx, ra == %08lx)\n",
+		       tsk->comm,
+		       writeaccess ? "writeaccess to" : "readaccess from",
+		       address,
+		       (unsigned long) regs->cp0_epc,
+		       (unsigned long) regs->regs[31]);
+#endif
+
 		current->tss.cp0_badvaddr = address;
 		current->tss.error_code = writeaccess;
-		send_sig(SIGSEGV, current, 1);
-		return;
+		force_sig(SIGSEGV, tsk);
+		goto out;
 	}
 	/*
 	 * Oops. The kernel tried to access some bad page. We'll have to
 	 * terminate things with extreme prejudice.
 	 */
 	printk(KERN_ALERT "Unable to handle kernel paging request at virtual "
-	       "address %08lx\n", address);
+	       "address %08lx, epc == %08lx\n", address, regs->cp0_epc);
 	die_if_kernel("Oops", regs, writeaccess);
 	do_exit(SIGKILL);
+out:
+	unlock_kernel();
 }

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov