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
- Lines: 381
- Date:
Mon Jul 8 11:27:43 1996
- Orig file:
v2.0.3/linux/arch/ppc/mm/fault.c
- Orig date:
Tue May 28 08:09:55 1996
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(¤t->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(¤t->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(¤t->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(¤t->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