summaryrefslogtreecommitdiffstats
path: root/arch/ppc/mm/fault.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/ppc/mm/fault.c')
-rw-r--r--arch/ppc/mm/fault.c121
1 files changed, 57 insertions, 64 deletions
diff --git a/arch/ppc/mm/fault.c b/arch/ppc/mm/fault.c
index fea722780..67b94d809 100644
--- a/arch/ppc/mm/fault.c
+++ b/arch/ppc/mm/fault.c
@@ -1,8 +1,12 @@
/*
* arch/ppc/mm/fault.c
*
- * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds
- * Ported to PPC by Gary Thomas
+ * PowerPC version
+ * Copyright (C) 1995-1996 Gary Thomas (gdt@linuxppc.org)
+ *
+ * Derived from "arch/i386/mm/fault.c"
+ * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds
+ *
* Modified by Cort Dougan and Paul Mackerras.
*
* This program is free software; you can redistribute it and/or
@@ -26,40 +30,42 @@
#include <asm/page.h>
#include <asm/pgtable.h>
+#include <asm/mmu.h>
#include <asm/mmu_context.h>
+#include <asm/system.h>
+#include <asm/uaccess.h>
-#ifdef CONFIG_PMAC
+#ifdef CONFIG_XMON
+extern void xmon(struct pt_regs *);
extern void (*xmon_fault_handler)(void);
-#endif
-
-/* the linux norm for the function name is show_regs() so
- make it call dump_regs() on the mac -- Cort */
-#ifdef CONFIG_PMAC
-#define show_regs dump_regs
+extern int xmon_dabr_match(struct pt_regs *);
+int xmon_kernel_faults;
#endif
extern void die_if_kernel(char *, struct pt_regs *, long);
void bad_page_fault(struct pt_regs *, unsigned long);
void do_page_fault(struct pt_regs *, unsigned long, unsigned long);
-void print_pte(struct _PTE);
-void do_page_fault(struct pt_regs *regs, unsigned long address, unsigned long error_code)
+/*
+ * The error_code parameter is DSISR for a data fault, SRR1 for
+ * an instruction fault.
+ */
+void do_page_fault(struct pt_regs *regs, unsigned long address,
+ unsigned long error_code)
{
- struct task_struct *tsk = current;
- extern unsigned _end[];
struct vm_area_struct * vma;
struct mm_struct *mm = current->mm;
- pgd_t *dir;
- pmd_t *pmd;
- pte_t *pte;
-
- /*printk("do_page_fault() %s/%d addr %x nip %x regs %x error %x\n",
- current->comm,current->pid,address,regs->nip,regs,error_code);*/
-#ifdef CONFIG_PMAC
+
+#ifdef CONFIG_XMON
if (xmon_fault_handler && regs->trap == 0x300) {
xmon_fault_handler();
return;
}
+ if (error_code & 0x00400000) {
+ /* DABR match */
+ if (xmon_dabr_match(regs))
+ return;
+ }
#endif
if (in_interrupt()) {
static int complained;
@@ -68,14 +74,18 @@ void do_page_fault(struct pt_regs *regs, unsigned long address, unsigned long er
printk("page fault in interrupt handler, addr=%lx\n",
address);
show_regs(regs);
+#ifdef CONFIG_XMON
+ if (xmon_kernel_faults)
+ xmon(regs);
+#endif
}
}
- if (current == NULL)
- goto bad_area;
-
-do_page:
+ if (current == NULL) {
+ bad_page_fault(regs, address);
+ return;
+ }
down(&mm->mmap_sem);
- vma = find_vma(tsk->mm, address);
+ vma = find_vma(mm, address);
if (!vma)
goto bad_area;
if (vma->vm_start <= address)
@@ -84,7 +94,7 @@ do_page:
goto bad_area;
if (expand_stack(vma, address))
goto bad_area;
-
+
good_area:
if (error_code & 0xb5700000)
/* an error such as lwarx to I/O controller space,
@@ -98,67 +108,45 @@ good_area:
/* a read */
} else {
/* protection fault */
- if ( error_code & 0x08000000 )
+ if (error_code & 0x08000000)
goto bad_area;
if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
goto bad_area;
}
handle_mm_fault(current, vma, address, error_code & 0x02000000);
- up(&mm->mmap_sem);
- /*printk("do_page_fault() return %s/%d addr %x msr %x\n",
- current->comm,current->pid,address,regs->msr);*/
- /* not needed since flush_page_to_ram() works */
-#if 0
- flush_page(address);
-#endif
+ up(&mm->mmap_sem);
return;
-
+
bad_area:
- up(&current->mm->mmap_sem);
+ up(&mm->mmap_sem);
bad_page_fault(regs, address);
}
-
void
bad_page_fault(struct pt_regs *regs, unsigned long address)
{
- extern unsigned int probingmem;
- struct task_struct *tsk = current;
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) {
- if ( user_mode(regs) )
- printk("Exception from user mode\n");
-#if 0
- printk(KERN_DEBUG "Exception at %lx (%lx)\n", regs->nip, fixup);
-#endif
regs->nip = fixup;
return;
}
- if ( user_mode(regs) )
- {
- force_sig(SIGSEGV, tsk);
- return;
- }
-
-bad_kernel_access:
- /* make sure it's not a bootup probe test */
- if ( probingmem )
- {
- probingmem = 0;
- return;
- }
/* kernel has accessed a bad area */
show_regs(regs);
- print_backtrace( regs->gpr[1] );
-#ifdef CONFIG_PMAC
- xmon(regs);
+ print_backtrace( (unsigned long *)regs->gpr[1] );
+#ifdef CONFIG_XMON
+ if (xmon_kernel_faults)
+ xmon(regs);
#endif
- panic("kernel access of bad area\n pc %x address %X tsk %s/%d",
- regs->nip,address,tsk->comm,tsk->pid);
+ panic("kernel access of bad area pc %lx lr %lx address %lX tsk %s/%d",
+ regs->nip,regs->link,address,current->comm,current->pid);
}
unsigned long va_to_phys(unsigned long address)
@@ -189,6 +177,10 @@ unsigned long va_to_phys(unsigned long address)
return (0);
}
+#if 0
+/*
+ * Misc debugging functions. Please leave them here. -- Cort
+ */
void print_pte(struct _PTE p)
{
printk(
@@ -210,7 +202,8 @@ unsigned long htab_phys_to_va(unsigned long address)
for ( ptr = Hash ; ptr < Hash_end ; ptr++ )
{
if ( ptr->rpn == (address>>12) )
- printk("phys %08X -> va ???\n",
+ printk("phys %08lX -> va ???\n",
address);
}
}
+#endif