patch-2.4.0-test12 linux/arch/m68k/mm/fault.c

Next file: linux/arch/m68k/mvme147/config.c
Previous file: linux/arch/m68k/mac/via.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.4.0-test11/linux/arch/m68k/mm/fault.c linux/arch/m68k/mm/fault.c
@@ -19,6 +19,55 @@
 extern void die_if_kernel(char *, struct pt_regs *, long);
 extern const int frame_extra_sizes[]; /* in m68k/kernel/signal.c */
 
+int send_fault_sig(struct pt_regs *regs)
+{
+	siginfo_t siginfo = { 0, 0, 0, };
+
+	siginfo.si_signo = current->thread.signo;
+	siginfo.si_code = current->thread.code;
+	siginfo.si_addr = (void *)current->thread.faddr;
+	printk("send_fault_sig: %p,%d,%d\n", siginfo.si_addr, siginfo.si_signo, siginfo.si_code);
+
+	if (user_mode(regs)) {
+		force_sig_info(siginfo.si_signo,
+			       &siginfo, current);
+	} else {
+		unsigned long fixup;
+
+		/* Are we prepared to handle this kernel fault? */
+		if ((fixup = search_exception_table(regs->pc))) {
+			struct pt_regs *tregs;
+			/* Create a new four word stack frame, discarding the old
+			   one.  */
+			regs->stkadj = frame_extra_sizes[regs->format];
+			tregs =	(struct pt_regs *)((ulong)regs + regs->stkadj);
+			tregs->vector = regs->vector;
+			tregs->format = 0;
+			tregs->pc = fixup;
+			tregs->sr = regs->sr;
+			return -1;
+		}
+
+		//if (siginfo.si_signo == SIGBUS)
+		//	force_sig_info(siginfo.si_signo,
+		//		       &siginfo, current);
+
+		/*
+		 * Oops. The kernel tried to access some bad page. We'll have to
+		 * terminate things with extreme prejudice.
+		 */
+		if ((unsigned long)siginfo.si_addr < PAGE_SIZE)
+			printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
+		else
+			printk(KERN_ALERT "Unable to handle kernel access");
+		printk(" at virtual address %p\n", siginfo.si_addr);
+		die_if_kernel("Oops", regs, 0 /*error_code*/);
+		do_exit(SIGKILL);
+	}
+
+	return 1;
+}
+
 /*
  * This routine handles page faults.  It determines the problem, and
  * then passes it off to one of the appropriate routines.
@@ -30,16 +79,15 @@
  * If this routine detects a bad access, it returns 1, otherwise it
  * returns 0.
  */
-asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address,
+int do_page_fault(struct pt_regs *regs, unsigned long address,
 			      unsigned long error_code)
 {
 	struct mm_struct *mm = current->mm;
 	struct vm_area_struct * vma;
-	unsigned long fixup;
 	int write, fault;
 
 #ifdef DEBUG
-	printk ("regs->sr=%#x, regs->pc=%#lx, address=%#lx, %ld, %p\n",
+	printk ("do page fault:\nregs->sr=%#x, regs->pc=%#lx, address=%#lx, %ld, %p\n",
 		regs->sr, regs->pc, address, error_code,
 		current->mm->pgd);
 #endif
@@ -55,43 +103,46 @@
 
 	vma = find_vma(mm, address);
 	if (!vma)
-		goto bad_area;
+		goto map_err;
 	if (vma->vm_flags & VM_IO)
-		goto bad_area;
+		goto acc_err;
 	if (vma->vm_start <= address)
 		goto good_area;
 	if (!(vma->vm_flags & VM_GROWSDOWN))
-		goto bad_area;
+		goto map_err;
 	if (user_mode(regs)) {
 		/* Accessing the stack below usp is always a bug.  The
 		   "+ 256" is there due to some instructions doing
 		   pre-decrement on the stack and that doesn't show up
 		   until later.  */
 		if (address + 256 < rdusp())
-			goto bad_area;
+			goto map_err;
 	}
 	if (expand_stack(vma, address))
-		goto bad_area;
+		goto map_err;
 
 /*
  * Ok, we have a good vm_area for this memory access, so
  * we can handle it..
  */
 good_area:
+#ifdef DEBUG
+	printk("do_page_fault: good_area\n");
+#endif
 	write = 0;
 	switch (error_code & 3) {
 		default:	/* 3: write, present */
 			/* fall through */
 		case 2:		/* write, not present */
 			if (!(vma->vm_flags & VM_WRITE))
-				goto bad_area;
+				goto acc_err;
 			write++;
 			break;
 		case 1:		/* read, present */
-			goto bad_area;
+			goto acc_err;
 		case 0:		/* read, not present */
 			if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
-				goto bad_area;
+				goto acc_err;
 	}
 
 	/*
@@ -100,87 +151,56 @@
 	 * the fault.
 	 */
 	fault = handle_mm_fault(mm, vma, address, write);
+#ifdef DEBUG
+ 	printk("handle_mm_fault returns %d\n",fault);
+#endif
 	if (fault < 0)
 		goto out_of_memory;
 	if (!fault)
-		goto do_sigbus;
+		goto bus_err;
 
 	/* There seems to be a missing invalidate somewhere in do_no_page.
 	 * Until I found it, this one cures the problem and makes
 	 * 1.2 run on the 68040 (Martin Apel).
 	 */
+	#warning should be obsolete now...
 	if (CPU_IS_040_OR_060)
 		flush_tlb_page(vma, address);
 	up(&mm->mmap_sem);
 	return 0;
 
 /*
- * 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);
-
-	/* User mode accesses just cause a SIGSEGV */
-	if (user_mode(regs)) {
-		siginfo_t info;
-		info.si_signo = SIGSEGV;
-		info.si_code = SEGV_MAPERR;
-		info.si_addr = (void *)address;
-		force_sig_info(SIGSEGV, &info, current);
-		return 1;
-	}
-
-no_context:
-	/* Are we prepared to handle this kernel fault?  */
-	if ((fixup = search_exception_table(regs->pc)) != 0) {
-		struct pt_regs *tregs;
-		/* Create a new four word stack frame, discarding the old
-		   one.  */
-		regs->stkadj = frame_extra_sizes[regs->format];
-		tregs =	(struct pt_regs *)((ulong)regs + regs->stkadj);
-		tregs->vector = regs->vector;
-		tregs->format = 0;
-		tregs->pc = fixup;
-		tregs->sr = regs->sr;
-		return -1;
-	}
-
-/*
- * Oops. The kernel tried to access some bad page. We'll have to
- * terminate things with extreme prejudice.
- */
-	if ((unsigned long) address < PAGE_SIZE) {
-		printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
-	} else
-		printk(KERN_ALERT "Unable to handle kernel access");
-	printk(" at virtual address %08lx\n",address);
-	die_if_kernel("Oops", regs, error_code);
-	do_exit(SIGKILL);
-
-/*
  * We ran out of memory, or some other thing happened to us that made
  * us unable to handle the page fault gracefully.
  */
 out_of_memory:
-	up(&mm->mmap_sem);
 	printk("VM: killing process %s\n", current->comm);
-	if (error_code & 4)
+	if (user_mode(regs))
 		do_exit(SIGKILL);
-	goto no_context;
 
-do_sigbus:
-	up(&mm->mmap_sem);
-
-	/*
-	 * Send a sigbus, regardless of whether we were in kernel
-	 * or user mode.
-	 */
-	force_sig(SIGBUS, current);
-
-	/* Kernel mode? Handle exceptions or die */
-	if (!user_mode(regs))
-		goto no_context;
+no_context:
+	current->thread.signo = SIGBUS;
+	current->thread.faddr = address;
+	return send_fault_sig(regs);
+
+bus_err:
+	current->thread.signo = SIGBUS;
+	current->thread.code = BUS_ADRERR;
+	current->thread.faddr = address;
+	goto send_sig;
+
+map_err:
+	current->thread.signo = SIGSEGV;
+	current->thread.code = SEGV_MAPERR;
+	current->thread.faddr = address;
+	goto send_sig;
+
+acc_err:
+	current->thread.signo = SIGSEGV;
+	current->thread.code = SEGV_ACCERR;
+	current->thread.faddr = address;
 
-	return 1;
+send_sig:
+	up(&mm->mmap_sem);
+	return send_fault_sig(regs);
 }

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)