root/arch/i386/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/i386/mm/fault.c
   3  *
   4  *  Copyright (C) 1995  Linus Torvalds
   5  */
   6 
   7 #include <linux/config.h>
   8 #include <linux/signal.h>
   9 #include <linux/sched.h>
  10 #include <linux/head.h>
  11 #include <linux/kernel.h>
  12 #include <linux/errno.h>
  13 #include <linux/string.h>
  14 #include <linux/types.h>
  15 #include <linux/ptrace.h>
  16 #include <linux/mman.h>
  17 #include <linux/mm.h>
  18 
  19 #include <asm/system.h>
  20 #include <asm/segment.h>
  21 #include <asm/pgtable.h>
  22 
  23 extern void die_if_kernel(const char *,struct pt_regs *,long);
  24 
  25 /*
  26  * This routine handles page faults.  It determines the address,
  27  * and the problem, and then passes it off to one of the appropriate
  28  * routines.
  29  *
  30  * error_code:
  31  *      bit 0 == 0 means no page found, 1 means protection fault
  32  *      bit 1 == 0 means read, 1 means write
  33  *      bit 2 == 0 means kernel, 1 means user-mode
  34  */
  35 asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
     /* [previous][next][first][last][top][bottom][index][help] */
  36 {
  37         struct vm_area_struct * vma;
  38         unsigned long address;
  39         unsigned long page;
  40 
  41         /* get the address */
  42         __asm__("movl %%cr2,%0":"=r" (address));
  43         vma = find_vma(current, address);
  44         if (!vma)
  45                 goto bad_area;
  46         if (vma->vm_start <= address)
  47                 goto good_area;
  48         if (!(vma->vm_flags & VM_GROWSDOWN))
  49                 goto bad_area;
  50         if (vma->vm_end - address > current->rlim[RLIMIT_STACK].rlim_cur)
  51                 goto bad_area;
  52         if (error_code & 4) {
  53                 /*
  54                  * accessing the stack below %esp is always a bug.
  55                  * The "+ 32" is there due to some instructions (like
  56                  * pusha) doing pre-decrement on the stack and that
  57                  * doesn't show up until later..
  58                  */
  59                 if (address + 32 < regs->esp)
  60                         goto bad_area;
  61         }
  62         vma->vm_offset -= vma->vm_start - (address & PAGE_MASK);
  63         vma->vm_start = (address & PAGE_MASK);
  64 /*
  65  * Ok, we have a good vm_area for this memory access, so
  66  * we can handle it..
  67  */
  68 good_area:
  69         /*
  70          * was it a write?
  71          */
  72         if (error_code & 2) {
  73                 if (!(vma->vm_flags & VM_WRITE))
  74                         goto bad_area;
  75         } else {
  76                 /* read with protection fault? */
  77                 if (error_code & 1)
  78                         goto bad_area;
  79                 if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
  80                         goto bad_area;
  81         }
  82         /*
  83          * Did it hit the DOS screen memory VA from vm86 mode?
  84          */
  85         if (regs->eflags & VM_MASK) {
  86                 unsigned long bit = (address - 0xA0000) >> PAGE_SHIFT;
  87                 if (bit < 32)
  88                         current->tss.screen_bitmap |= 1 << bit;
  89         }
  90         if (error_code & 1) {
  91 #ifdef CONFIG_TEST_VERIFY_AREA
  92                 if (regs->cs == KERNEL_CS)
  93                         printk("WP fault at %08x\n", regs->eip);
  94 #endif
  95                 do_wp_page(current, vma, address, error_code & 2);
  96                 return;
  97         }
  98         do_no_page(current, vma, address, error_code & 2);
  99         return;
 100 
 101 /*
 102  * Something tried to access memory that isn't in our memory map..
 103  * Fix it, but check if it's kernel or user first..
 104  */
 105 bad_area:
 106         if (error_code & 4) {
 107                 current->tss.cr2 = address;
 108                 current->tss.error_code = error_code;
 109                 current->tss.trap_no = 14;
 110                 send_sig(SIGSEGV, current, 1);
 111                 return;
 112         }
 113 /*
 114  * Oops. The kernel tried to access some bad page. We'll have to
 115  * terminate things with extreme prejudice.
 116  *
 117  * First we check if it was the bootup rw-test, though..
 118  */
 119         if (wp_works_ok < 0 && address == TASK_SIZE && (error_code & 1)) {
 120                 wp_works_ok = 1;
 121                 pg0[0] = pte_val(mk_pte(0, PAGE_SHARED));
 122                 invalidate();
 123                 printk("This processor honours the WP bit even when in supervisor mode. Good.\n");
 124                 return;
 125         }
 126         if ((unsigned long) (address-TASK_SIZE) < PAGE_SIZE) {
 127                 printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
 128                 pg0[0] = pte_val(mk_pte(0, PAGE_SHARED));
 129         } else
 130                 printk(KERN_ALERT "Unable to handle kernel paging request");
 131         printk(" at virtual address %08lx\n",address);
 132         __asm__("movl %%cr3,%0" : "=r" (page));
 133         printk(KERN_ALERT "current->tss.cr3 = %08lx, %%cr3 = %08lx\n",
 134                 current->tss.cr3, page);
 135         page = ((unsigned long *) page)[address >> 22];
 136         printk(KERN_ALERT "*pde = %08lx\n", page);
 137         if (page & 1) {
 138                 page &= PAGE_MASK;
 139                 address &= 0x003ff000;
 140                 page = ((unsigned long *) page)[address >> PAGE_SHIFT];
 141                 printk(KERN_ALERT "*pte = %08lx\n", page);
 142         }
 143         die_if_kernel("Oops", regs, error_code);
 144         do_exit(SIGKILL);
 145 }

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