diff options
Diffstat (limited to 'arch/ppc/mm/fault.c')
-rw-r--r-- | arch/ppc/mm/fault.c | 121 |
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(¤t->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 |