root/arch/m68k/mm/fault.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. do_page_fault

   1 /*
   2  *  linux/arch/m68k/mm/fault.c
   3  *
   4  *  Copyright (C) 1995  Hamish Macdonald
   5  */
   6 
   7 #include <linux/mman.h>
   8 #include <linux/mm.h>
   9 #include <linux/kernel.h>
  10 #include <linux/ptrace.h>
  11 
  12 #include <asm/system.h>
  13 #include <asm/pgtable.h>
  14 
  15 extern void die_if_kernel(char *, struct pt_regs *, long);
  16 
  17 /*
  18  * This routine handles page faults.  It determines the problem, and
  19  * then passes it off to one of the appropriate routines.
  20  *
  21  * error_code:
  22  *      bit 0 == 0 means no page found, 1 means protection fault
  23  *      bit 1 == 0 means read, 1 means write
  24  *
  25  * If this routine detects a bad access, it returns 1, otherwise it
  26  * returns 0.
  27  */
  28 asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address,
     /* [previous][next][first][last][top][bottom][index][help] */
  29                               unsigned long error_code)
  30 {
  31         struct vm_area_struct * vma;
  32 
  33 #ifdef DEBUG
  34         printk ("regs->sr=%#x, regs->pc=%#lx, address=%#lx, %ld, %p\n",
  35                 regs->sr, regs->pc, address, error_code,
  36                 current->tss.pagedir_v);
  37 #endif
  38 
  39         vma = find_vma(current, address);
  40         if (!vma)
  41           goto bad_area;
  42         if (vma->vm_start <= address)
  43                 goto good_area;
  44         if (!(vma->vm_flags & VM_GROWSDOWN))
  45                 goto bad_area;
  46         if (user_mode(regs)) {
  47                 /* Accessing the stack below usp is always a bug.  The
  48                    "+ 256" is there due to some instructions doing
  49                    pre-decrement on the stack and that doesn't show up
  50                    until later.  */
  51                 if (address + 256 < rdusp())
  52                         goto bad_area;
  53         }
  54         if (expand_stack(vma, address))
  55                 goto bad_area;
  56 
  57 /*
  58  * Ok, we have a good vm_area for this memory access, so
  59  * we can handle it..
  60  */
  61 good_area:
  62         /*
  63          * was it a write?
  64          */
  65         if (error_code & 2) {
  66           if (!(vma->vm_flags & VM_WRITE))
  67             goto bad_area;
  68         } else {
  69                 /* read with protection fault? */
  70           if (error_code & 1)
  71             goto bad_area;
  72           if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
  73             goto bad_area;
  74         }
  75         if (error_code & 1) {
  76                 do_wp_page(current, vma, address, error_code & 2);
  77                 return 0;
  78         }
  79         do_no_page(current, vma, address, error_code & 2);
  80 
  81         /* There seems to be a missing invalidate somewhere in do_no_page.
  82          * Until I found it, this one cures the problem and makes
  83          * 1.2 run on the 68040 (Martin Apel).
  84          */
  85         flush_tlb_all();
  86 
  87         return 0;
  88 
  89 /*
  90  * Something tried to access memory that isn't in our memory map..
  91  * Fix it, but check if it's kernel or user first..
  92  */
  93 bad_area:
  94         if (user_mode(regs)) {
  95                 /* User memory access */
  96                 send_sig (SIGSEGV, current, 1);
  97                 return 1;
  98         }
  99 
 100 /*
 101  * Oops. The kernel tried to access some bad page. We'll have to
 102  * terminate things with extreme prejudice.
 103  */
 104         if ((unsigned long) address < PAGE_SIZE) {
 105                 printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
 106         } else
 107                 printk(KERN_ALERT "Unable to handle kernel access");
 108         printk(" at virtual address %08lx\n",address);
 109         die_if_kernel("Oops", regs, error_code);
 110         do_exit(SIGKILL);
 111 
 112         return 1;
 113 }

/* [previous][next][first][last][top][bottom][index][help] */