patch-2.0.4 linux/arch/ppc/mm/fault.c

Next file: linux/arch/ppc/mm/init.c
Previous file: linux/arch/ppc/kernel/traps.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.0.3/linux/arch/ppc/mm/fault.c linux/arch/ppc/mm/fault.c
@@ -23,107 +23,123 @@
 extern void die_if_kernel(char *, struct pt_regs *, long);
 extern void do_page_fault(struct pt_regs *, unsigned long, unsigned long);
 
-#define SHOW_FAULTS
-#undef  SHOW_FAULTS
-#define PAUSE_AFTER_FAULT
-#undef  PAUSE_AFTER_FAULT
+#undef SHOW_FAULTS
+#undef NOISY_INSTRFAULT
+#undef NOISY_DATAFAULT
+
+#define NEWMM 1
 
 void
 DataAccessException(struct pt_regs *regs)
 {
-	pgd_t *dir;
-	pmd_t *pmd;
-	pte_t *pte;
-	int tries, mode = 0;
-	if (user_mode(regs)) mode |= 0x04;
-	if (regs->dsisr & 0x02000000) mode |= 0x02;  /* Load/store */
-	if (regs->dsisr & 0x08000000) mode |= 0x01;  /* Protection violation */
-#ifdef SHOW_FAULTS
-	printk("Data Access Fault - Loc: %x, DSISR: %x, PC: %x\n", regs->dar, regs->dsisr, regs->nip);
-#ifdef PAUSE_AFTER_FAULT
-cnpause();
-#endif			
-#endif
-	if (mode & 0x01)
-	{
-#ifdef SHOW_FAULTS
-printk("Write Protect Fault - Loc: %x, DSISR: %x, PC: %x\n", regs->dar, regs->dsisr, regs->nip);
-#endif
-		do_page_fault(regs, regs->dar, mode);
-		return;
-	}
-	for (tries = 0;  tries < 1;  tries++)
-	{
-		dir = pgd_offset(current->mm, regs->dar & PAGE_MASK);
-		if (dir)
-		{
-			pmd = pmd_offset(dir, regs->dar & PAGE_MASK);
-			if (pmd && pmd_present(*pmd))
-			{
-				pte = pte_offset(pmd, regs->dar & PAGE_MASK);
-				if (pte && pte_present(*pte))
-				{
-#ifdef SHOW_FAULTS
-					printk("Page mapped - PTE: %x[%x], Context: %x\n", pte, *(long *)pte, current->mm->context);
-#endif					
-					MMU_hash_page(&current->tss, regs->dar & PAGE_MASK, pte);
-					return;
-				}
-			}
-		} else
-		{
-			printk("No PGD\n");
-		}
-		do_page_fault(regs, regs->dar, mode);
-	}
+  pgd_t *dir;
+  pmd_t *pmd;
+  pte_t *pte;
+  int tries, mode = 0;
+  
+#ifdef NOISY_DATAFAULT
+  printk("Data fault on %x\n",regs->dar);
+#endif
+  
+  if (user_mode(regs)) mode |= 0x04;
+  if (regs->dsisr & 0x02000000) mode |= 0x02;  /* Load/store */
+  if (regs->dsisr & 0x08000000) mode |= 0x01;  /* Protection violation */
+  if (mode & 0x01)
+  {
+#ifdef NOISY_DATAFAULT
+    printk("Write Protect fault\n ");
+#endif
+    do_page_fault(regs, regs->dar, mode);
+#ifdef NOISY_DATAFAULT    
+    printk("Write Protect fault handled\n");
+#endif
+    return;
+  }
+
+    
+  for (tries = 0;  tries < 1;  tries++)
+  {
+    dir = pgd_offset(current->mm, regs->dar & PAGE_MASK);
+    if (dir)
+    {
+      pmd = pmd_offset(dir, regs->dar & PAGE_MASK);
+      if (pmd && pmd_present(*pmd))
+      {
+	pte = pte_offset(pmd, regs->dar & PAGE_MASK);
+	if (pte && pte_present(*pte))
+	{
+#if NOISY_DATAFAULT
+	  printk("Page mapped - PTE: %x[%x]\n", pte, *(long *)pte);
+#endif
+	  MMU_hash_page(&current->tss, regs->dar & PAGE_MASK, pte);
+	  /*MMU_hash_page2(current->mm, regs->dar & PAGE_MASK, pte);*/
+	  return;
+	}
+      }
+    } else
+    {
+#if NOISY_DATAFAULT
+      printk("No PGD\n");      
+#endif 
+    }
+    do_page_fault(regs, regs->dar, mode);
+  }
 }
 
 void
 InstructionAccessException(struct pt_regs *regs)
 {
-	pgd_t *dir;
-	pmd_t *pmd;
-	pte_t *pte;
-	int tries, mode = 0;
-	unsigned long addr = regs->nip;
-	if (user_mode(regs)) mode |= 0x04;
-#ifdef SHOW_FAULTS
-	printk("Instruction Access Fault - Loc: %x, DSISR: %x, PC: %x\n", regs->dar, regs->dsisr, regs->nip);
-#ifdef PAUSE_AFTER_FAULT
-cnpause();
-#endif
-#endif	
-	if (mode & 0x01)
-	{
-		do_page_fault(regs, addr, mode);
-		return;
-	}
-	for (tries = 0;  tries < 1;  tries++)
-	{
-		dir = pgd_offset(current->mm, addr & PAGE_MASK);
-		if (dir)
-		{
-			pmd = pmd_offset(dir, addr & PAGE_MASK);
-			if (pmd && pmd_present(*pmd))
-			{
-				pte = pte_offset(pmd, addr & PAGE_MASK);
-				if (pte && pte_present(*pte))
-				{
-#ifdef SHOW_FAULTS
-					printk("Page mapped - PTE: %x[%x], Context: %x\n", pte, *(long *)pte, current->mm->context);
-#endif					
-					MMU_hash_page(&current->tss, addr & PAGE_MASK, pte);
-					return;
-				}
-			}
-		} else
-		{
-			printk("No PGD\n");
-		}
-		do_page_fault(regs, addr, mode);
-	}
+  pgd_t *dir;
+  pmd_t *pmd;
+  pte_t *pte;
+  int tries, mode = 0;
+  
+#if NOISY_INSTRFAULT
+  printk("Instr fault on %x\n",regs->dar);
+#endif
+
+#ifdef NEWMM
+  if (!user_mode(regs))
+  {
+    
+    panic("InstructionAcessException in kernel mode. PC %x addr %x",
+	  regs->nip, regs->dar);
+  }
+#endif
+  if (user_mode(regs)) mode |= 0x04;
+  if (regs->dsisr & 0x02000000) mode |= 0x02;  /* Load/store */
+  if (regs->dsisr & 0x08000000) mode |= 0x01;  /* Protection violation */
+  
+  if (mode & 0x01)
+  {
+    do_page_fault(regs, regs->dar, mode); 
+    return;
+  }
+  for (tries = 0;  tries < 1;  tries++)
+  {
+    dir = pgd_offset(current->mm, regs->dar & PAGE_MASK);
+    if (dir)
+    {
+      pmd = pmd_offset(dir, regs->dar & PAGE_MASK); 
+      if (pmd && pmd_present(*pmd))
+      {
+ 	pte = pte_offset(pmd, regs->dar & PAGE_MASK); 
+	if (pte && pte_present(*pte))
+	  {
+	    
+	    MMU_hash_page(&current->tss, regs->dar & PAGE_MASK, pte); 
+	    /*	  MMU_hash_page2(current->mm, regs->dar & PAGE_MASK, pte);*/
+	    return;
+	  }
+      }
+    } else
+      {
+      }
+    do_page_fault(regs, regs->dar, mode);
+  }
 }
 
+
 /*
  * This routine handles page faults.  It determines the address,
  * and the problem, and then passes it off to one of the appropriate
@@ -137,103 +153,66 @@
  */
 void do_page_fault(struct pt_regs *regs, unsigned long address, unsigned long error_code)
 {
-	struct vm_area_struct * vma;
-	unsigned long page;
+  struct vm_area_struct * vma;
+  unsigned long page;
 
-	for (vma = current->mm->mmap ; ; vma = vma->vm_next)
-	{
-#ifdef SHOW_FAULTS
-printk("VMA(%x) - Start: %x, End: %x, Flags: %x\n", vma, vma->vm_start, vma->vm_end, vma->vm_flags);		
-#endif
-		if (!vma)
-			goto bad_area;
-		if (vma->vm_end > address)
-			break;
-	}
-	if (vma->vm_start <= address)
-		goto good_area;
-	if (!(vma->vm_flags & VM_GROWSDOWN))
-		goto bad_area;
-	if (vma->vm_end - address > current->rlim[RLIMIT_STACK].rlim_cur)
-		goto bad_area;
-	vma->vm_offset -= vma->vm_start - (address & PAGE_MASK);
-	vma->vm_start = (address & PAGE_MASK);
-/*
- * Ok, we have a good vm_area for this memory access, so
- * we can handle it..
- */
-good_area:
-	/*
-	 * was it a write?
-	 */
-	if (error_code & 2) {
-		if (!(vma->vm_flags & VM_WRITE))
-			goto bad_area;
-	} else {
-		/* read with protection fault? */
-		if (error_code & 1)
-			goto bad_area;
-		if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
-			goto bad_area;
-	}
-	handle_mm_fault(vma, address, error_code & 2);
-	flush_page(address);  /* Flush & Invalidate cache - note: address is OK now */
-	return;
+  vma = find_vma(current, address);
+  if (!vma)
+  {
+    goto bad_area;
+  }
+
+  if (vma->vm_start <= address){
+    goto good_area;
+  }
+  if (!(vma->vm_flags & VM_GROWSDOWN))
+  {
+    goto bad_area;
+  }
+  if (vma->vm_end - address > current->rlim[RLIMIT_STACK].rlim_cur)
+  {
+    goto bad_area;
+  }
+  vma->vm_offset -= vma->vm_start - (address & PAGE_MASK);
 
-/*
- * Something tried to access memory that isn't in our memory map..
- * Fix it, but check if it's kernel or user first..
- */
+  vma->vm_start = (address & PAGE_MASK);
+  
+good_area:
+  /* a write */
+  if (error_code & 2) {
+    if (!(vma->vm_flags & VM_WRITE))
+    {
+      goto bad_area;
+    }
+  /* a read */
+  } else {
+    /* protection fault */
+    if (error_code & 1)
+    {
+      goto bad_area;
+    }
+    if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
+    {
+      goto bad_area; 
+    }
+  }
+  handle_mm_fault(vma, address, error_code & 2);
+  flush_page(address);  /* Flush & Invalidate cache - note: address is OK now */  
+  return;
+  
 bad_area:
-printk("Task: %x, PC: %x/%x, bad area! - Addr: %x\n", current, regs->nip, current->tss.last_pc, address);
-print_user_backtrace(current->tss.user_stack);
-print_kernel_backtrace();
-#if 0
-cnpause();
-if (!user_mode(regs))
-{
-   print_backtrace(regs->gpr[1]);
-}
-#endif
-dump_regs(regs);
-	if (user_mode(regs)) {
-#if 0
-		current->tss.cp0_badvaddr = address;
-		current->tss.error_code = error_code;
-		current->tss.trap_no = 14;
-#endif
-		force_sig(SIGSEGV, current);
-		return;
-	}
-printk("KERNEL! Task: %x, PC: %x, bad area! - Addr: %x, PGDIR: %x\n", current, regs->nip, address, current->tss.pg_tables);
-dump_regs(regs);
-while (1) ;
-#if 0	
-	/*
-	 * Oops. The kernel tried to access some bad page. We'll have to
-	 * terminate things with extreme prejudice.
-	 */
-	if ((unsigned long) (address-TASK_SIZE) < PAGE_SIZE) {
-		printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
-		pg0[0] = pte_val(mk_pte(0, PAGE_SHARED));
-	} else
-		printk(KERN_ALERT "Unable to handle kernel paging request");
-	printk(" at virtual address %08lx\n",address);
-	page = current->tss.pg_dir;
-	printk(KERN_ALERT "current->tss.pg_dir = %08lx\n", page);
-	page = ((unsigned long *) page)[address >> PGDIR_SHIFT];
-	printk(KERN_ALERT "*pde = %08lx\n", page);
-	if (page & 1) {
-		page &= PAGE_MASK;
-		address &= 0x003ff000;
-		page = ((unsigned long *) page)[address >> PAGE_SHIFT];
-		printk(KERN_ALERT "*pte = %08lx\n", page);
-	}
-	die_if_kernel("Oops", regs, error_code);
-#endif	
-	do_exit(SIGKILL);
+  if (user_mode(regs))
+  {
+/*    printk("Bad User Area: Addr %x PC %x Task %x pid %d %s\n",
+	   address,regs->nip, current,current->pid,current->comm);*/
+    send_sig(SIGSEGV, current, 1);
+    return;
+  }
+  panic("KERNEL access of bad area PC %x address %x vm_flags %x\n",
+	regs->nip,address,vma->vm_flags);
 }
 
+
 va_to_phys(unsigned long address)
 {
 	pgd_t *dir;
@@ -260,6 +239,7 @@
 	}
 	return (0);
 }
+
 
 /*
  * See if an address should be valid in the current context.

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov