root/arch/ppc/mm/fault.c

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

DEFINITIONS

This source file includes following definitions.
  1. DataAccessException
  2. InstructionAccessException
  3. do_page_fault
  4. va_to_phys

   1 /* * Last edited: Nov 29 18:14 1995 (cort) */
   2 /*
   3  *  ARCH/ppc/mm/fault.c
   4  *
   5  *  Copyright (C) 1991, 1992, 1993, 1994  Linus Torvalds
   6  *  Ported to PPC by Gary Thomas
   7  */
   8 
   9 /*#define NOISY_DATAFAULT*/
  10 /*#define NOISY_INSTRFAULT*/
  11 
  12 #include <linux/config.h>
  13 #include <linux/signal.h>
  14 #include <linux/sched.h>
  15 #include <linux/head.h>
  16 #include <linux/kernel.h>
  17 #include <linux/errno.h>
  18 #include <linux/string.h>
  19 #include <linux/types.h>
  20 #include <linux/ptrace.h>
  21 #include <linux/mman.h>
  22 #include <linux/mm.h>
  23 
  24 #include <asm/page.h>
  25 #include <asm/pgtable.h>
  26 
  27 extern void die_if_kernel(char *, struct pt_regs *, long);
  28 extern void do_page_fault(struct pt_regs *, unsigned long, unsigned long);
  29 
  30 #if 0
  31 #define SHOW_FAULTS
  32 #endif
  33 
  34 void
  35 DataAccessException(struct pt_regs *regs)
     /* [previous][next][first][last][top][bottom][index][help] */
  36 {
  37   pgd_t *dir;
  38   pmd_t *pmd;
  39   pte_t *pte;
  40   int tries, mode = 0;
  41   if (user_mode(regs)) mode |= 0x04;
  42   if (regs->dsisr & 0x02000000) mode |= 0x02;  /* Load/store */
  43   if (regs->dsisr & 0x08000000) mode |= 0x01;  /* Protection violation */
  44 #ifdef NOISY_DATAFAULT
  45   printk("Data fault on %x\n",regs->dar);
  46 #endif
  47   if (mode & 0x01)
  48   {
  49 #if 0
  50     printk("Write Protect Fault - Loc: %x, DSISR: %x, PC: %x\n", regs->dar, regs->dsisr, regs->nip);
  51 #endif
  52 #ifdef NOISY_DATAFAULT
  53     printk("Write Protect fault\n ");
  54 #endif
  55     do_page_fault(regs, regs->dar, mode);
  56 #ifdef NOISY_DATAFAULT    
  57     printk("Write Protect fault handled\n");
  58 #endif
  59     return;
  60   }
  61 /*   printk("trying\n"); */
  62   for (tries = 0;  tries < 1;  tries++)
  63   {
  64     dir = pgd_offset(current->mm, regs->dar & PAGE_MASK);
  65     if (dir)
  66     {
  67       pmd = pmd_offset(dir, regs->dar & PAGE_MASK);
  68       if (pmd && pmd_present(*pmd))
  69       {
  70         pte = pte_offset(pmd, regs->dar & PAGE_MASK);
  71         if (pte && pte_present(*pte))
  72         {
  73 #if 0
  74           printk("Page mapped - PTE: %x[%x]\n", pte, *(long *)pte);
  75 #endif
  76           MMU_hash_page(&current->tss, regs->dar & PAGE_MASK, pte);
  77           return;
  78         }
  79       }
  80     } else
  81     {
  82       printk("No PGD\n");
  83     }
  84 #ifdef NOISY_DATAFAULT    
  85     printk("fall through page fault addr=%x; ip=%x\n",
  86            regs->dar,regs->nip);
  87     printk("beforefault: pgd[0] = %x[%x]\n",current->mm->pgd,*(current->mm->pgd));
  88 #endif
  89     do_page_fault(regs, regs->dar, mode);
  90 #ifdef NOISY_DATAFAULT    
  91     printk("handled: pgd[0] = %x[%x]\n",current->mm->pgd,*(current->mm->pgd));
  92 #endif
  93   }
  94 }
  95 
  96 void
  97 InstructionAccessException(struct pt_regs *regs)
     /* [previous][next][first][last][top][bottom][index][help] */
  98 {
  99   pgd_t *dir;
 100   pmd_t *pmd;
 101   pte_t *pte;
 102   int tries, mode = 0;
 103   
 104 #if NOISY_INSTRFAULT
 105   printk("Instr fault on %x\n",regs->dar);
 106 #endif
 107   if (user_mode(regs)) mode |= 0x04;
 108   if (regs->dsisr & 0x02000000) mode |= 0x02;  /* Load/store */
 109   if (regs->dsisr & 0x08000000) mode |= 0x01;  /* Protection violation */
 110   
 111   if (mode & 0x01)
 112   {
 113     do_page_fault(regs, regs->dar, mode); 
 114     return;
 115   }
 116   for (tries = 0;  tries < 1;  tries++)
 117   {
 118     /*     dir = pgd_offset(current->mm, regs->nip & PAGE_MASK); */
 119     dir = pgd_offset(current->mm, regs->dar & PAGE_MASK);
 120 #ifdef NOISY_INSTRFAULT
 121 /*      printk("regs->dar=%x current=%x current->mm=%x current->mm->pgd=%x current->tss.pg_tables=%x\n",
 122                regs->dar,current,current->mm,current->mm->pgd,current->tss.pg_tables);*/
 123 #endif
 124     if (dir)
 125     {
 126       pmd = pmd_offset(dir, regs->dar & PAGE_MASK); 
 127       if (pmd && pmd_present(*pmd))
 128       {
 129         pte = pte_offset(pmd, regs->dar & PAGE_MASK); 
 130 
 131 #ifdef NOISY_INSTRFAULT
 132 /*      printk("dir %x(%x) pmd %x(%x) pte %x\n",dir,*dir,pmd,*pmd,pte);*/
 133 #if 0
 134         printk("pgd_offset mm=%x mm->pgd=%x dirshouldbe=%x\n",
 135                current->mm, current->mm->pgd,
 136                current->mm->pgd+((regs->dar&PAGE_MASK) >> PGDIR_SHIFT));
 137         printk("dir is %x\n", dir);
 138         
 139         /*      printk("got pte\n"); */
 140         if (pte) {
 141           printk("pgd=%x; dir=%x->%x; pmd=%x->%x; pte=%x; \n",
 142                  current->mm->pgd,dir,*dir,pmd,*pmd,pte);
 143           if (pte_present(*pte)) {
 144             printk("pte present\n");
 145           } else {
 146             printk("pte not present\n");
 147           }
 148         } else {
 149           printk("pte false\n");
 150         }
 151 #endif
 152 #endif
 153         if (pte && pte_present(*pte))
 154         {
 155 /*        MMU_hash_page(&current->tss, regs->nip & PAGE_MASK, pte); */
 156           MMU_hash_page(&current->tss, regs->dar & PAGE_MASK, pte); 
 157           return;
 158         }
 159       }
 160     } else
 161     {
 162 #ifdef NOISY_INSTRFAULT      
 163       panic("No PGD Instruction Access Fault - Loc: %x, DSISR: %x, PC: %x current->mm\n",
 164             regs->dar, regs->dsisr, regs->nip, current->mm);
 165 #endif
 166     }
 167 /*     do_page_fault(regs, regs->nip, mode); */
 168      do_page_fault(regs, regs->dar, mode);
 169   }
 170 }
 171 
 172 /*
 173  * This routine handles page faults.  It determines the address,
 174  * and the problem, and then passes it off to one of the appropriate
 175  * routines.
 176  *
 177  * The error_code parameter just the same as in the i386 version:
 178  *
 179  *      bit 0 == 0 means no page found, 1 means protection fault
 180  *      bit 1 == 0 means read, 1 means write
 181  *      bit 2 == 0 means kernel, 1 means user-mode
 182  */
 183 void do_page_fault(struct pt_regs *regs, unsigned long address, unsigned long error_code)
     /* [previous][next][first][last][top][bottom][index][help] */
 184 {
 185   struct vm_area_struct * vma;
 186   unsigned long page;
 187 
 188 /*   printk("In do_page_fault()\n"); */
 189 #if 1
 190   for (vma = current->mm->mmap ; ; vma = vma->vm_next)
 191   {
 192     if (!vma)
 193     {
 194       panic("!vma: ip = %x; current=%x[%d]; mm=%x; mmap=%x; address = %x error_code = %x\n",
 195             regs->nip, current,current->pid,current->mm,current->mm->mmap, address, error_code);
 196       goto bad_area;
 197     }
 198     if (vma->vm_end > address)
 199       break;
 200   }
 201 #else
 202   vma = find_vma(current, address);
 203   if (!vma)
 204   {
 205   }
 206     goto bad_area;
 207 #endif
 208   if (vma->vm_start <= address){
 209     goto good_area;
 210   }
 211   if (!(vma->vm_flags & VM_GROWSDOWN))
 212   {
 213     printk("stack: gpr[1]=%x ip = %x; current=%x[%d]; mm=%x; mmap=%x; address = %x error_code = %x\n",regs->gpr[1],regs->nip, current,current->pid,current->mm,current->mm->mmap, address, error_code);
 214     panic("stack\n");
 215     goto bad_area;
 216   }
 217   if (vma->vm_end - address > current->rlim[RLIMIT_STACK].rlim_cur)
 218   {
 219     printk("stack2: vma->vm_end-address %x rlim %x\n", vma->vm_end - address,
 220            current->rlim[RLIMIT_STACK].rlim_cur);
 221     printk("stack2: vm_end %x address = %x\n", vma->vm_end,address);
 222     printk("stack2: gpr[1]=%x ip = %x; current=%x[%d]; mm=%x; mmap=%x; address = %x error_code = %x\n",regs->gpr[1],regs->nip, current,current->pid,current->mm,current->mm->mmap, address, error_code);
 223     panic("stack2\n");
 224     goto bad_area;
 225   }
 226   vma->vm_offset -= vma->vm_start - (address & PAGE_MASK);
 227   vma->vm_start = (address & PAGE_MASK);
 228   
 229   /*
 230    * Ok, we have a good vm_area for this memory access, so
 231    * we can handle it..
 232    */
 233 good_area:
 234   /*
 235    * was it a write?
 236    */
 237   if (error_code & 2) {
 238     if (!(vma->vm_flags & VM_WRITE))
 239     {
 240       panic("do_page_fault()  write\n");
 241       panic("do_page_fault() write! current: %x, address:%x, vm_flags: %x, mm: %x; vma(%x) %x to %x\n",
 242             current,address,vma->vm_flags,current->mm,vma,vma->vm_start,vma->vm_end);
 243       goto bad_area;
 244     }
 245   } else {
 246     /* read with protection fault? */
 247     if (error_code & 1)
 248     {
 249       panic("do_page_fault()  error code thing\n");         
 250       goto bad_area;
 251     }
 252     if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
 253     {
 254 #if 0
 255       _printk("vma = %x\n", vma);
 256       _printk("vma->vm_flags = %x\n", vma->vm_flags);      
 257       _printk("VM_READ = %x VM_EXEC = %x\n",VM_READ,VM_EXEC);
 258 #endif
 259 #if 0
 260       printk("vma = %x VM_READ = %x VM_EXEC = %x\n",
 261              vma, VM_READ,VM_EXEC);
 262       printk("vma->vm_start = %x vma->vm_end = %d\n",
 263              vma->vm_start, vma->vm_end);
 264       printk("error_code = %x\n", error_code);      
 265       printk("regs = %x\n", regs);
 266       printk("vma->vm_flags = %x\n", vma->vm_flags);
 267 #endif
 268 /*      printk("do_page_fault()  multi thing\n"); */
 269       goto bad_area; 
 270     }
 271   }
 272 /*   printk("premm: pgd[0] = %x[%x]\n",current->mm->pgd,*(current->mm->pgd)); */
 273   handle_mm_fault(vma, address, error_code & 2); 
 274 /*   printk("handled fault for %x in %x to %x flags %x\n", */
 275 /*       address,vma->vm_start,vma->vm_end,vma->vm_flags); */
 276   return;
 277   
 278   /*
 279    * Something tried to access memory that isn't in our memory map..
 280    * Fix it, but check if it's kernel or user first..
 281    */
 282 bad_area:
 283   if (user_mode(regs)) {
 284     printk("Task: %x, PC: %x, bad area! - Addr: %x\n", current, regs->nip, address);
 285     send_sig(SIGSEGV, current, 1);
 286     return;
 287   }
 288 #if 0
 289   panic("KERNEL! Task: %x, PC: %x, bad area! - Addr: %x, PGDIR: %x\n",
 290          current, regs->nip, address, current->tss.pg_tables);
 291 #else
 292   /*  panic("KERNEL mm! current: %x,  address:%x, vm_flags: %x, mm: %x; \nvma(%x) %x to %x swapper_pg_dir %x\n",
 293         current,address,vma->vm_flags,current->mm,vma,vma->vm_start,vma->vm_end,
 294         swapper_pg_dir);*/
 295   printk("KERNEL mm! current: %x,  address:%x, vm_flags: %x, mm: %x; vma(%x) %x to %x\n",
 296         current,address,vma->vm_flags,current->mm,vma,vma->vm_start,vma->vm_end);
 297   panic("Kernel access of bad area\n");
 298          
 299 #endif
 300   
 301   while (1) ;
 302 }
 303 
 304 va_to_phys(unsigned long address)
     /* [previous][next][first][last][top][bottom][index][help] */
 305 {
 306   pgd_t *dir;
 307   pmd_t *pmd;
 308   pte_t *pte;
 309   dir = pgd_offset(current->mm, address & PAGE_MASK);
 310   if (dir)
 311   {
 312     pmd = pmd_offset(dir, address & PAGE_MASK);
 313     if (pmd && pmd_present(*pmd))
 314     {
 315       pte = pte_offset(pmd, address & PAGE_MASK);
 316       if (pte && pte_present(*pte))
 317       {
 318         return(pte_page(*pte) | (address & ~(PAGE_MASK-1)));
 319       }
 320     } else
 321     {
 322       return (0);
 323     }
 324   } else
 325   {
 326     return (0);
 327   }
 328 }
 329 
 330 
 331 
 332 
 333 
 334 
 335 
 336 
 337 
 338 
 339 
 340 
 341 

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