patch-2.2.15 linux/arch/ppc/mm/fault.c
Next file: linux/arch/s390/boot/Makefile
Previous file: linux/arch/ppc/kernel/smp.c
Back to the patch index
Back to the overall index
- Lines: 161
- Date:
Fri Apr 21 12:45:47 2000
- Orig file:
v2.2.14/arch/ppc/mm/fault.c
- Orig date:
Sat Aug 14 02:26:47 1999
diff -u --new-file --recursive --exclude-from ../../exclude v2.2.14/arch/ppc/mm/fault.c linux/arch/ppc/mm/fault.c
@@ -48,7 +48,7 @@
unsigned int probingmem = 0;
extern void die_if_kernel(char *, struct pt_regs *, long);
-void bad_page_fault(struct pt_regs *, unsigned long);
+void bad_page_fault(struct pt_regs *, unsigned long, unsigned long);
void do_page_fault(struct pt_regs *, unsigned long, unsigned long);
/*
@@ -60,6 +60,7 @@
{
struct vm_area_struct * vma;
struct mm_struct *mm = current->mm;
+ int fault;
/*printk("address: %08lx nip:%08lx code: %08lx %s%s%s%s%s%s\n",
address,regs->nip,error_code,
@@ -82,23 +83,11 @@
return;
}
#endif
- if (in_interrupt()) {
- static int complained;
- if (complained < 20) {
- ++complained;
- printk("page fault in interrupt handler, addr=%lx\n",
- address);
- show_regs(regs);
-#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
- if (debugger_kernel_faults)
- debugger(regs);
-#endif
- }
- }
- if (current == NULL) {
- bad_page_fault(regs, address);
+ if (in_interrupt() || mm == &init_mm) {
+ bad_page_fault(regs, address, error_code);
return;
}
+
down(&mm->mmap_sem);
vma = find_vma(mm, address);
if (!vma)
@@ -115,6 +104,7 @@
if (error_code & 0x95700000)
/* an error such as lwarx to I/O controller space,
address matching DABR, eciwx, etc. */
+ goto bad_area;
#endif /* CONFIG_6xx */
#ifdef CONFIG_8xx
/* The MPC8xx seems to always set 0x80000000, which is
@@ -123,10 +113,9 @@
*/
if (error_code & 0x10000000)
/* Guarded storage error. */
-#endif /* CONFIG_8xx */
goto bad_area;
-
-
+#endif /* CONFIG_8xx */
+
/* a write */
if (error_code & 0x02000000) {
if (!(vma->vm_flags & VM_WRITE))
@@ -139,8 +128,13 @@
if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
goto bad_area;
}
- if (!handle_mm_fault(current, vma, address, error_code & 0x02000000))
- goto bad_area;
+
+ survive:
+ fault = handle_mm_fault(current, vma, address, error_code & 0x2000000);
+ if (!fault)
+ goto do_sigbus;
+ if (fault < 0)
+ goto out_of_memory;
up(&mm->mmap_sem);
/*
* keep track of tlb+htab misses that are good addrs but
@@ -151,36 +145,72 @@
return;
bad_area:
-
up(&mm->mmap_sem);
pte_errors++;
- bad_page_fault(regs, address);
+ bad_page_fault(regs, address, error_code);
+ return;
+
+/*
+ * 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:
+ if (current->pid == 1) {
+ current->policy |= SCHED_YIELD;
+ schedule();
+ goto survive;
+ }
+ up(&mm->mmap_sem);
+ if (user_mode(regs)) {
+ printk("VM: killing process %s\n", current->comm);
+ do_exit(SIGKILL);
+ }
+ bad_page_fault(regs, address, error_code);
+ return;
+
+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))
+ bad_page_fault(regs, address, error_code);
}
void
-bad_page_fault(struct pt_regs *regs, unsigned long address)
+bad_page_fault(struct pt_regs *regs, unsigned long address, unsigned long err)
{
unsigned long fixup;
if (user_mode(regs)) {
force_sig(SIGSEGV, current);
return;
}
-
+
/* Are we prepared to handle this fault? */
if ((fixup = search_exception_table(regs->nip)) != 0) {
regs->nip = fixup;
return;
}
- /* kernel has accessed a bad area */
+ /* kernel has accessed a bad address */
+ if (address < PAGE_SIZE)
+ printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
+ else
+ printk(KERN_ALERT "Unable to handle kernel paging request");
+ printk(" at virtual address %08lx (error %lx)\n", address, err);
show_regs(regs);
- print_backtrace( (unsigned long *)regs->gpr[1] );
#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
if (debugger_kernel_faults)
debugger(regs);
#endif
+ print_backtrace((unsigned long *)regs->gpr[1]);
panic("kernel access of bad area pc %lx lr %lx address %lX tsk %s/%d",
- regs->nip,regs->link,address,current->comm,current->pid);
+ regs->nip, regs->link, address, current->comm, current->pid);
}
#ifdef CONFIG_8xx
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)