home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / KERNEL-S / V1.2 / LINUX-1.2 / LINUX-1 / linux / arch / i386 / mm / fault.c next >
Encoding:
C/C++ Source or Header  |  1995-01-30  |  3.6 KB  |  136 lines

  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(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)
  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.     vma->vm_offset -= vma->vm_start - (address & PAGE_MASK);
  53.     vma->vm_start = (address & PAGE_MASK);
  54. /*
  55.  * Ok, we have a good vm_area for this memory access, so
  56.  * we can handle it..
  57.  */
  58. good_area:
  59.     /*
  60.      * was it a write?
  61.      */
  62.     if (error_code & 2) {
  63.         if (!(vma->vm_flags & VM_WRITE))
  64.             goto bad_area;
  65.     } else {
  66.         /* read with protection fault? */
  67.         if (error_code & 1)
  68.             goto bad_area;
  69.         if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
  70.             goto bad_area;
  71.     }
  72.     /*
  73.      * Did it hit the DOS screen memory VA from vm86 mode?
  74.      */
  75.     if (regs->eflags & VM_MASK) {
  76.         unsigned long bit = (address - 0xA0000) >> PAGE_SHIFT;
  77.         if (bit < 32)
  78.             current->tss.screen_bitmap |= 1 << bit;
  79.     }
  80.     if (error_code & 1) {
  81. #ifdef CONFIG_TEST_VERIFY_AREA
  82.         if (regs->cs == KERNEL_CS)
  83.             printk("WP fault at %08x\n", regs->eip);
  84. #endif
  85.         do_wp_page(vma, address, error_code & 2);
  86.         return;
  87.     }
  88.     do_no_page(vma, address, error_code & 2);
  89.     return;
  90.  
  91. /*
  92.  * Something tried to access memory that isn't in our memory map..
  93.  * Fix it, but check if it's kernel or user first..
  94.  */
  95. bad_area:
  96.     if (error_code & 4) {
  97.         current->tss.cr2 = address;
  98.         current->tss.error_code = error_code;
  99.         current->tss.trap_no = 14;
  100.         send_sig(SIGSEGV, current, 1);
  101.         return;
  102.     }
  103. /*
  104.  * Oops. The kernel tried to access some bad page. We'll have to
  105.  * terminate things with extreme prejudice.
  106.  *
  107.  * First we check if it was the bootup rw-test, though..
  108.  */
  109.     if (wp_works_ok < 0 && address == TASK_SIZE && (error_code & 1)) {
  110.         wp_works_ok = 1;
  111.         pg0[0] = pte_val(mk_pte(0, PAGE_SHARED));
  112.         invalidate();
  113.         printk("This processor honours the WP bit even when in supervisor mode. Good.\n");
  114.         return;
  115.     }
  116.     if ((unsigned long) (address-TASK_SIZE) < PAGE_SIZE) {
  117.         printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
  118.         pg0[0] = pte_val(mk_pte(0, PAGE_SHARED));
  119.     } else
  120.         printk(KERN_ALERT "Unable to handle kernel paging request");
  121.     printk(" at virtual address %08lx\n",address);
  122.     __asm__("movl %%cr3,%0" : "=r" (page));
  123.     printk(KERN_ALERT "current->tss.cr3 = %08lx, %%cr3 = %08lx\n",
  124.         current->tss.cr3, page);
  125.     page = ((unsigned long *) page)[address >> 22];
  126.     printk(KERN_ALERT "*pde = %08lx\n", page);
  127.     if (page & 1) {
  128.         page &= PAGE_MASK;
  129.         address &= 0x003ff000;
  130.         page = ((unsigned long *) page)[address >> PAGE_SHIFT];
  131.         printk(KERN_ALERT "*pte = %08lx\n", page);
  132.     }
  133.     die_if_kernel("Oops", regs, error_code);
  134.     do_exit(SIGKILL);
  135. }
  136.