patch-2.1.9 linux/arch/sparc/mm/fault.c
Next file: linux/arch/sparc/mm/generic.c
Previous file: linux/arch/sparc/mm/asyncd.c
Back to the patch index
Back to the overall index
- Lines: 241
- Date:
Sat Nov 9 10:12:16 1996
- Orig file:
v2.1.8/linux/arch/sparc/mm/fault.c
- Orig date:
Thu Apr 25 13:22:05 1996
diff -u --recursive --new-file v2.1.8/linux/arch/sparc/mm/fault.c linux/arch/sparc/mm/fault.c
@@ -1,7 +1,8 @@
-/* $Id: fault.c,v 1.62 1996/04/25 06:09:26 davem Exp $
+/* $Id: fault.c,v 1.77 1996/10/28 00:56:02 davem Exp $
* fault.c: Page fault handlers for the Sparc.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1996 Eddie C. Dost (ecd@skynet.be)
*/
#include <asm/head.h>
@@ -17,8 +18,6 @@
#include <asm/system.h>
#include <asm/segment.h>
-#include <asm/openprom.h>
-#include <asm/idprom.h>
#include <asm/page.h>
#include <asm/pgtable.h>
#include <asm/memreg.h>
@@ -122,6 +121,8 @@
printk(" Synchronous Vaddr %08lx\n", svaddr);
printk(" Asynchronous Error %08lx\n", aerr);
printk(" Asynchronous Vaddr %08lx\n", avaddr);
+ if (sun4c_memerr_reg)
+ printk(" Memory Parity Error %08lx\n", *sun4c_memerr_reg);
printk("REGISTER DUMP:\n");
show_regs(regs);
prom_halt();
@@ -131,36 +132,47 @@
unsigned long address)
{
struct vm_area_struct *vma;
+ struct task_struct *tsk = current;
+ struct mm_struct *mm = tsk->mm;
int from_user = !(regs->psr & PSR_PS);
-
#if 0
- printk("CPU[%d]: f<pid=%d,tf=%d,wr=%d,addr=%08lx",
- smp_processor_id(), current->pid, text_fault,
- write, address);
- printk(",pc=%08lx> ", regs->pc);
+ static unsigned long last_one;
#endif
+ down(&mm->mmap_sem);
if(text_fault)
address = regs->pc;
+#if 0
+ if(current->tss.ex.count) {
+ printk("f<pid=%d,tf=%d,wr=%d,addr=%08lx,pc=%08lx>\n",
+ tsk->pid, text_fault, write, address, regs->pc);
+ printk("EX: count<%d> pc<%08lx> expc<%08lx> address<%08lx>\n",
+ (int) current->tss.ex.count, current->tss.ex.pc,
+ current->tss.ex.expc, current->tss.ex.address);
+#if 0
+ if(last_one == address) {
+ printk("Twice in a row, AIEEE. Spinning so you can see the dump.\n");
+ show_regs(regs);
+ sti();
+ while(1)
+ barrier();
+ }
+ last_one = address;
+#endif
+ }
+#endif
/* Now actually handle the fault. Do kernel faults special,
* because on the sun4c we could have faulted trying to read
* the vma area of the task and without the following code
* we'd fault recursively until all our stack is gone. ;-(
*/
- if(!from_user && address >= KERNBASE) {
-#ifdef __SMP__
- printk("CPU[%d]: Kernel faults at addr=%08lx\n",
- smp_processor_id(), address);
- while(1)
- ;
-#else
+ if(!from_user && address >= PAGE_OFFSET) {
quick_kernel_fault(address);
return;
-#endif
}
- vma = find_vma(current, address);
+ vma = find_vma(mm, address);
if(!vma)
goto bad_area;
if(vma->vm_start <= address)
@@ -183,40 +195,98 @@
goto bad_area;
}
handle_mm_fault(vma, address, write);
+ up(&mm->mmap_sem);
return;
/*
* Something tried to access memory that isn't in our memory map..
* Fix it, but check if it's kernel or user first..
*/
bad_area:
+ up(&mm->mmap_sem);
+ /* Did we have an exception handler installed? */
+ if(current->tss.ex.count == 1) {
+ if(from_user) {
+ printk("Yieee, exception signalled from user mode.\n");
+ } else {
+ /* Set pc to %g1, set %g1 to -EFAULT and %g2 to
+ * the faulting address so we can cleanup.
+ */
+ printk("Exception: PC<%08lx> faddr<%08lx>\n", regs->pc, address);
+ printk("EX: count<%d> pc<%08lx> expc<%08lx> address<%08lx>\n",
+ (int) current->tss.ex.count, current->tss.ex.pc,
+ current->tss.ex.expc, current->tss.ex.address);
+ current->tss.ex.count = 0;
+ regs->pc = current->tss.ex.expc;
+ regs->npc = regs->pc + 4;
+ regs->u_regs[UREG_G1] = -EFAULT;
+ regs->u_regs[UREG_G2] = address - current->tss.ex.address;
+ regs->u_regs[UREG_G3] = current->tss.ex.pc;
+ return;
+ }
+ }
if(from_user) {
#if 0
- printk("%s [%d]: segfaults at %08lx pc=%08lx\n",
- current->comm, current->pid, address, regs->pc);
+ printk("Fault whee %s [%d]: segfaults at %08lx pc=%08lx\n",
+ tsk->comm, tsk->pid, address, regs->pc);
#endif
- current->tss.sig_address = address;
- current->tss.sig_desc = SUBSIG_NOMAPPING;
- send_sig(SIGSEGV, current, 1);
+ tsk->tss.sig_address = address;
+ tsk->tss.sig_desc = SUBSIG_NOMAPPING;
+ send_sig(SIGSEGV, tsk, 1);
return;
}
if((unsigned long) address < PAGE_SIZE) {
printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
} else
printk(KERN_ALERT "Unable to handle kernel paging request");
- printk(" at virtual address %08lx\n",address);
- printk(KERN_ALERT "current->mm->context = %08lx\n",
- (unsigned long) current->mm->context);
- printk(KERN_ALERT "current->mm->pgd = %08lx\n",
- (unsigned long) current->mm->pgd);
+ printk(KERN_ALERT " at virtual address %08lx\n",address);
+ printk(KERN_ALERT "tsk->mm->context = %08lx\n",
+ (unsigned long) tsk->mm->context);
+ printk(KERN_ALERT "tsk->mm->pgd = %08lx\n",
+ (unsigned long) tsk->mm->pgd);
die_if_kernel("Oops", regs);
}
+asmlinkage void do_sun4c_fault(struct pt_regs *regs, int text_fault, int write,
+ unsigned long address)
+{
+ extern void sun4c_update_mmu_cache(struct vm_area_struct *,unsigned long,pte_t);
+ extern pgd_t *sun4c_pgd_offset(struct mm_struct *,unsigned long);
+ extern pte_t *sun4c_pte_offset(pmd_t *,unsigned long);
+ struct task_struct *tsk = current;
+ struct mm_struct *mm = tsk->mm;
+ pgd_t *pgd;
+ pte_t *pte;
+
+ if(text_fault)
+ address = regs->pc;
+
+ pgd = sun4c_pgd_offset(mm, address);
+ pte = sun4c_pte_offset((pmd_t *) pgd, address);
+
+ /* This conditional is 'interesting'. */
+ if(pgd_val(*pgd) && !(write && !(pte_val(*pte) & _SUN4C_PAGE_WRITE))
+ && (pte_val(*pte) & _SUN4C_PAGE_VALID))
+ /* XXX Very bad, can't do this optimization when VMA arg is actually
+ * XXX used by update_mmu_cache()!
+ */
+ sun4c_update_mmu_cache((struct vm_area_struct *) 0, address, *pte);
+ else
+ do_sparc_fault(regs, text_fault, write, address);
+}
+
/* This always deals with user addresses. */
inline void force_user_fault(unsigned long address, int write)
{
struct vm_area_struct *vma;
+ struct task_struct *tsk = current;
+ struct mm_struct *mm = tsk->mm;
- vma = find_vma(current, address);
+#if 0
+ printk("wf<pid=%d,wr=%d,addr=%08lx>\n",
+ tsk->pid, write, address);
+#endif
+ down(&mm->mmap_sem);
+ vma = find_vma(mm, address);
if(!vma)
goto bad_area;
if(vma->vm_start <= address)
@@ -233,18 +303,25 @@
if(!(vma->vm_flags & (VM_READ | VM_EXEC)))
goto bad_area;
handle_mm_fault(vma, address, write);
+ up(&mm->mmap_sem);
return;
bad_area:
- current->tss.sig_address = address;
- current->tss.sig_desc = SUBSIG_NOMAPPING;
- send_sig(SIGSEGV, current, 1);
+ up(&mm->mmap_sem);
+#if 0
+ printk("Window whee %s [%d]: segfaults at %08lx\n",
+ tsk->comm, tsk->pid, address);
+#endif
+ tsk->tss.sig_address = address;
+ tsk->tss.sig_desc = SUBSIG_NOMAPPING;
+ send_sig(SIGSEGV, tsk, 1);
return;
}
void window_overflow_fault(void)
{
- unsigned long sp = current->tss.rwbuf_stkptrs[0];
+ unsigned long sp;
+ sp = current->tss.rwbuf_stkptrs[0];
if(((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK))
force_user_fault(sp + 0x38, 1);
force_user_fault(sp, 1);
@@ -259,8 +336,9 @@
void window_ret_fault(struct pt_regs *regs)
{
- unsigned long sp = regs->u_regs[UREG_FP];
+ unsigned long sp;
+ sp = regs->u_regs[UREG_FP];
if(((sp + 0x38) & PAGE_MASK) != (sp & PAGE_MASK))
force_user_fault(sp + 0x38, 0);
force_user_fault(sp, 0);
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov