kernels/linux-2.4.0/arch/ppc/mm/fault.c
/*
 * For 600- and 800-family processors, the error_code parameter is DSISR
 * for a data fault, SRR1 for an instruction fault. For 400-family processors
 * the error_code parameter is ESR for a data fault, 0 for an instruction
 * fault.
 */
For 600- and 800-family processors, the error_code parameter is DSISR
for a data fault, SRR1 for an instruction fault. For 400-family processors
the error_code parameter is ESR for a data fault, 0 for an instruction
fault.
For 600 - and 800 - family processors the error_code parameter is DSISR for a data fault SRR1 for an instruction fault . For 400 - family processors the error_code parameter is ESR for a data fault 0 for an instruction fault .
void do_page_fault(struct pt_regs *regs, unsigned long address,
		   unsigned long error_code)
{
	struct vm_area_struct * vma;
	struct mm_struct *mm = current->mm;
	siginfo_t info;
	int code = SEGV_MAPERR;
#if defined(CONFIG_4xx)
	int is_write = error_code & ESR_DST;
#else
	int is_write = 0;
	if (regs->trap == 0x400)
		error_code &= 0x48200000;
	else
		is_write = error_code & 0x02000000;
#endif 
#if defined(CONFIG_XMON) || defined(CONFIG_KGDB)
	if (debugger_fault_handler && regs->trap == 0x300) {
		debugger_fault_handler(regs);
		return;
	}
#if !defined(CONFIG_4xx)
	if (error_code & 0x00400000) {
		if (debugger_dabr_match(regs))
			return;
	}
#endif 
#endif 
	if (in_interrupt() || mm == NULL) {
		bad_page_fault(regs, address);
		return;
	}
	down(&mm->mmap_sem);
	vma = find_vma(mm, address);
	if (!vma)
		goto bad_area;
	if (vma->vm_start <= address)
		goto good_area;
	if (!(vma->vm_flags & VM_GROWSDOWN))
		goto bad_area;
	if (expand_stack(vma, address))
		goto bad_area;
good_area:
	code = SEGV_ACCERR;
#if defined(CONFIG_6xx)
	if (error_code & 0x95700000)
		goto bad_area;
#endif 
#if defined(CONFIG_8xx)
	if (error_code & 0x10000000)
		goto bad_area;
#endif 
	if (is_write) {
		if (!(vma->vm_flags & VM_WRITE))
			goto bad_area;
	} else {
		if (error_code & 0x08000000)
			goto bad_area;
		if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
			goto bad_area;
	}
        switch (handle_mm_fault(mm, vma, address, is_write)) {
        case 1:
                current->min_flt++;
                break;
        case 2:
                current->maj_flt++;
                break;
        case 0:
                goto do_sigbus;
        default:
                goto out_of_memory;
	}
	up(&mm->mmap_sem);
	pte_misses++;
	return;
bad_area:
	up(&mm->mmap_sem);
	pte_errors++;	
	if (user_mode(regs)) {
		info.si_signo = SIGSEGV;
		info.si_errno = 0;
		info.si_code = code;
		info.si_addr = (void *) address;
		force_sig_info(SIGSEGV, &info, current);
		return;
	}
	bad_page_fault(regs, address);
	return;
out_of_memory:
	up(&mm->mmap_sem);
	printk("VM: killing process %s\n", current->comm);
	if (user_mode(regs))
		do_exit(SIGKILL);
	bad_page_fault(regs, address);
	return;
do_sigbus:
	up(&mm->mmap_sem);
	info.si_signo = SIGBUS;
	info.si_errno = 0;
	info.si_code = BUS_ADRERR;
	info.si_addr = (void *)address;
	force_sig_info (SIGBUS, &info, current);
	if (!user_mode(regs))
		bad_page_fault(regs, address);
}
void do_page_fault ( struct pt_regs * regs , unsigned long address , unsigned long error_code ) { struct vm_area_struct * vma ; struct mm_struct * mm = current -> mm ; siginfo_t info ; int code = SEGV_MAPERR ; #if defined ( CONFIG_4xx ) int is_write = error_code & ESR_DST ; #else int is_write = 0 ; if ( regs -> trap == 0x400 ) error_code &= 0x48200000 ; else is_write = error_code & 0x02000000 ; #endif #if defined ( CONFIG_XMON ) || defined ( CONFIG_KGDB ) if ( debugger_fault_handler && regs -> trap == 0x300 ) { debugger_fault_handler ( regs ) ; return ; } #if ! defined ( CONFIG_4xx ) if ( error_code & 0x00400000 ) { if ( debugger_dabr_match ( regs ) ) return ; } #endif #endif if ( in_interrupt ( ) || mm == NULL ) { bad_page_fault ( regs , address ) ; return ; } down ( & mm -> mmap_sem ) ; vma = find_vma ( mm , address ) ; if ( ! vma ) goto bad_area ; if ( vma -> vm_start <= address ) goto good_area ; if ( ! ( vma -> vm_flags & VM_GROWSDOWN ) ) goto bad_area ; if ( expand_stack ( vma , address ) ) goto bad_area ; good_area : code = SEGV_ACCERR ; #if defined ( CONFIG_6xx ) if ( error_code & 0x95700000 ) goto bad_area ; #endif #if defined ( CONFIG_8xx ) if ( error_code & 0x10000000 ) goto bad_area ; #endif if ( is_write ) { if ( ! ( vma -> vm_flags & VM_WRITE ) ) goto bad_area ; } else { if ( error_code & 0x08000000 ) goto bad_area ; if ( ! ( vma -> vm_flags & ( VM_READ | VM_EXEC ) ) ) goto bad_area ; } switch ( handle_mm_fault ( mm , vma , address , is_write ) ) { case 1 : current -> min_flt ++ ; break ; case 2 : current -> maj_flt ++ ; break ; case 0 : goto do_sigbus ; default : goto out_of_memory ; } up ( & mm -> mmap_sem ) ; pte_misses ++ ; return ; bad_area : up ( & mm -> mmap_sem ) ; pte_errors ++ ; if ( user_mode ( regs ) ) { info . si_signo = SIGSEGV ; info . si_errno = 0 ; info . si_code = code ; info . si_addr = ( void * ) address ; force_sig_info ( SIGSEGV , & info , current ) ; return ; } bad_page_fault ( regs , address ) ; return ; out_of_memory : up ( & mm -> mmap_sem ) ; printk ( " \n " , current -> comm ) ; if ( user_mode ( regs ) ) do_exit ( SIGKILL ) ; bad_page_fault ( regs , address ) ; return ; do_sigbus : up ( & mm -> mmap_sem ) ; info . si_signo = SIGBUS ; info . si_errno = 0 ; info . si_code = BUS_ADRERR ; info . si_addr = ( void * ) address ; force_sig_info ( SIGBUS , & info , current ) ; if ( ! user_mode ( regs ) ) bad_page_fault ( regs , address ) ; }
For 600- and 800-family processors, the error_code parameter is DSISR
 for a data fault, SRR1 for an instruction fault.
For 600 - and 800 - family processors the error_code parameter is DSISR for a data fault SRR1 for an instruction fault .
/*
	 * Fortunately the bit assignments in SRR1 for an instruction
	 * fault and DSISR for a data fault are mostly the same for the
	 * bits we are interested in.  But there are some bits which
	 * indicate errors in DSISR but can validly be set in SRR1.
	 */ /* CONFIG_4xx */ /* DABR match */ /* !CONFIG_4xx */ /* CONFIG_XMON || CONFIG_KGDB */ /* an error such as lwarx to I/O controller space,
		   address matching DABR, eciwx, etc. */ /* CONFIG_6xx */ /* The MPC8xx seems to always set 0x80000000, which is
         * "undefined".  Of those that can be set, this is the only
         * one which seems bad.
         */ /* Guarded storage error. */ /* CONFIG_8xx */ /* a write */ /* a read */ /* protection fault */ /*
	 * If for any reason at all we couldn't handle the fault,
	 * make sure we exit gracefully rather than endlessly redo
	 * the fault.
	 */ /*
	 * keep track of tlb+htab misses that are good addrs but
	 * just need pte's created via handle_mm_fault()
	 * -- Cort
	 */ /* User mode accesses cause a SIGSEGV */ /*
 * We ran out of memory, or some other thing happened to us that made
 * us unable to handle the page fault gracefully.
 */