patch-2.1.29 linux/arch/sparc64/mm/fault.c
Next file: linux/arch/sparc64/prom/Makefile
Previous file: linux/arch/sparc64/lib/memset.S
Back to the patch index
Back to the overall index
- Lines: 169
- Date:
Wed Mar 5 17:04:31 1997
- Orig file:
v2.1.28/linux/arch/sparc64/mm/fault.c
- Orig date:
Mon Dec 30 01:59:59 1996
diff -u --recursive --new-file v2.1.28/linux/arch/sparc64/mm/fault.c linux/arch/sparc64/mm/fault.c
@@ -1,7 +1,8 @@
-/* $Id: fault.c,v 1.2 1996/12/26 18:03:04 davem Exp $
+/* $Id: fault.c,v 1.3 1997/03/04 16:27:02 jj Exp $
* arch/sparc64/mm/fault.c: Page fault handlers for the 64-bit Sparc.
*
* Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu)
+ * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz)
*/
#define ELEMENTS(arr) (sizeof (arr)/sizeof (arr[0]))
@@ -70,6 +71,54 @@
return total;
}
+void unhandled_fault(unsigned long address, struct task_struct *tsk,
+ struct pt_regs *regs)
+{
+ 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 "
+ "at virtual address %016lx\n", (unsigned long)address);
+ }
+ printk(KERN_ALERT "tsk->mm->context = %016lx\n",
+ (unsigned long) tsk->mm->context);
+ printk(KERN_ALERT "tsk->mm->pgd = %016lx\n",
+ (unsigned long) tsk->mm->pgd);
+ die_if_kernel("Oops", regs);
+}
+
+asmlinkage int lookup_fault(unsigned long pc, unsigned long ret_pc,
+ unsigned long address)
+{
+ unsigned long g2;
+ int i;
+ unsigned insn;
+ struct pt_regs regs;
+
+ i = search_exception_table (ret_pc, &g2);
+ switch (i) {
+ /* load & store will be handled by fixup */
+ case 3: return 3;
+ /* store will be handled by fixup, load will bump out */
+ /* for _to_ macros */
+ case 1: insn = (unsigned *)pc; if ((insn >> 21) & 1) return 1; break;
+ /* load will be handled by fixup, store will bump out */
+ /* for _from_ macros */
+ case 2: insn = (unsigned *)pc;
+ if (!((insn >> 21) & 1) || ((insn>>19)&0x3f) == 15) return 2;
+ break;
+ default: break;
+ }
+ memset (®s, 0, sizeof (regs));
+ regs.pc = pc;
+ regs.npc = pc + 4;
+ /* FIXME: Should set up regs->tstate? */
+ unhandled_fault (address, current, ®s);
+ /* Not reached */
+ return 0;
+}
+
asmlinkage void do_sparc64_fault(struct pt_regs *regs, int text_fault, int write,
unsigned long address)
{
@@ -80,6 +129,7 @@
unsigned long g2;
int from_user = !(regs->tstate & TSTATE_PRIV);
+ lock_kernel ();
down(&mm->mmap_sem);
vma = find_vma(mm, address);
if(!vma)
@@ -105,33 +155,7 @@
}
handle_mm_fault(vma, address, write);
up(&mm->mmap_sem);
- return;
-
- vma = find_vma(mm, address);
- if(!vma)
- goto bad_area;
- if(vma->vm_start <= address)
- goto good_area;
- if(!(vma->vm_flags & VM_GROWSDOWN))
- goto bad_area;
- if(expand_stack(vma, address))
- goto bad_area;
- /*
- * Ok, we have a good vm_area for this memory access, so
- * we can handle it..
- */
-good_area:
- if(write) {
- if(!(vma->vm_flags & VM_WRITE))
- goto bad_area;
- } else {
- /* Allow reads even for write-only mappings */
- if(!(vma->vm_flags & (VM_READ | VM_EXEC)))
- goto bad_area;
- }
- handle_mm_fault(vma, address, write);
- up(&mm->mmap_sem);
- return;
+ goto out;
/*
* Something tried to access memory that isn't in our memory map..
* Fix it, but check if it's kernel or user first..
@@ -142,34 +166,13 @@
g2 = regs->u_regs[UREG_G2];
if (!from_user && (fixup = search_exception_table (regs->pc, &g2))) {
- printk("Exception: PC<%08lx> faddr<%08lx>\n", regs->pc, address);
- printk("EX_TABLE: insn<%08lx> fixup<%08x> g2<%08lx>\n",
+ printk("Exception: PC<%016lx> faddr<%016lx>\n", regs->pc, address);
+ printk("EX_TABLE: insn<%016lx> fixup<%016lx> g2<%016lx>\n",
regs->pc, fixup, g2);
regs->pc = fixup;
regs->npc = regs->pc + 4;
regs->u_regs[UREG_G2] = g2;
- return;
- }
- /* 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;
- }
+ goto out;
}
if(from_user) {
#if 0
@@ -179,18 +182,9 @@
tsk->tss.sig_address = address;
tsk->tss.sig_desc = SUBSIG_NOMAPPING;
send_sig(SIGSEGV, tsk, 1);
- return;
+ goto out;
}
- 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 "
- "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);
+ unhandled_fault (address, tsk, regs);
+out:
+ unlock_kernel();
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov