patch-2.3.41 linux/arch/sparc/mm/fault.c
Next file: linux/arch/sparc/mm/init.c
Previous file: linux/arch/sparc/mm/asyncd.c
Back to the patch index
Back to the overall index
- Lines: 187
- Date:
Fri Jan 21 18:22:54 2000
- Orig file:
v2.3.40/linux/arch/sparc/mm/fault.c
- Orig date:
Wed Dec 29 13:13:13 1999
diff -u --recursive --new-file v2.3.40/linux/arch/sparc/mm/fault.c linux/arch/sparc/mm/fault.c
@@ -1,4 +1,4 @@
-/* $Id: fault.c,v 1.111 1999/10/24 13:45:59 anton Exp $
+/* $Id: fault.c,v 1.113 2000/01/21 11:38:47 jj Exp $
* fault.c: Page fault handlers for the Sparc.
*
* Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu)
@@ -197,8 +197,10 @@
struct mm_struct *mm = tsk->mm;
unsigned int fixup;
unsigned long g2;
+ siginfo_t info;
int from_user = !(regs->psr & PSR_PS);
+ info.si_code = SEGV_MAPERR;
if(text_fault)
address = regs->pc;
@@ -207,10 +209,12 @@
* context, we must not take the fault..
*/
if (in_interrupt() || !mm)
- goto do_kernel_fault;
+ goto no_context;
down(&mm->mmap_sem);
- /* The kernel referencing a bad kernel pointer can lock up
+
+ /*
+ * The kernel referencing a bad kernel pointer can lock up
* a sun4c machine completely, so we must attempt recovery.
*/
if(!from_user && address >= PAGE_OFFSET)
@@ -230,6 +234,7 @@
* we can handle it..
*/
good_area:
+ info.si_code = SEGV_ACCERR;
if(write) {
if(!(vma->vm_flags & VM_WRITE))
goto bad_area;
@@ -238,18 +243,47 @@
if(!(vma->vm_flags & (VM_READ | VM_EXEC)))
goto bad_area;
}
- if (!handle_mm_fault(current, vma, address, write))
- goto do_sigbus;
+
+ /*
+ * If for any reason at all we couldn't handle the fault,
+ * make sure we exit gracefully rather than endlessly redo
+ * the fault.
+ */
+ {
+ int fault = handle_mm_fault(tsk, vma, address, write);
+ if (fault < 0)
+ goto out_of_memory;
+ if (!fault)
+ goto do_sigbus;
+ }
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);
+
+ /* User mode accesses just cause a SIGSEGV */
+ if(from_user) {
+#if 0
+ printk("Fault whee %s [%d]: segfaults at %08lx pc=%08lx\n",
+ tsk->comm, tsk->pid, address, regs->pc);
+#endif
+ info.si_signo = SIGSEGV;
+ info.si_errno = 0;
+ /* info.si_code set above to make clear whether
+ this was a SEGV_MAPERR or SEGV_ACCERR fault. */
+ info.si_addr = (void *)address;
+ info.si_trapno = 0;
+ force_sig_info (SIGSEGV, &info, tsk);
+ return;
+ }
+
/* Is this in ex_table? */
-do_kernel_fault:
+no_context:
g2 = regs->u_regs[UREG_G2];
if (!from_user && (fixup = search_exception_table (regs->pc, &g2))) {
if (fixup > 10) { /* Values below are reserved for other things */
@@ -276,26 +310,31 @@
return;
}
}
- if(from_user) {
-#if 0
- printk("Fault whee %s [%d]: segfaults at %08lx pc=%08lx\n",
- tsk->comm, tsk->pid, address, regs->pc);
-#endif
- tsk->thread.sig_address = address;
- tsk->thread.sig_desc = SUBSIG_NOMAPPING;
- force_sig(SIGSEGV, tsk);
- return;
- }
+
unhandled_fault (address, tsk, regs);
- return;
+ do_exit(SIGKILL);
+
+/*
+ * We ran out of memory, or some other thing happened to us that made
+ * us unable to handle the page fault gracefully.
+ */
+out_of_memory:
+ up(&mm->mmap_sem);
+ printk("VM: killing process %s\n", tsk->comm);
+ if (from_user)
+ do_exit(SIGKILL);
+ goto no_context;
do_sigbus:
up(&mm->mmap_sem);
- tsk->thread.sig_address = address;
- tsk->thread.sig_desc = SUBSIG_MISCERROR;
- force_sig(SIGBUS, tsk);
- if (! from_user)
- goto do_kernel_fault;
+ info.si_signo = SIGBUS;
+ info.si_errno = 0;
+ info.si_code = BUS_ADRERR;
+ info.si_addr = (void *)address;
+ info.si_trapno = 0;
+ force_sig_info (SIGBUS, &info, tsk);
+ if (!from_user)
+ goto no_context;
}
asmlinkage void do_sun4c_fault(struct pt_regs *regs, int text_fault, int write,
@@ -385,6 +424,9 @@
struct vm_area_struct *vma;
struct task_struct *tsk = current;
struct mm_struct *mm = tsk->mm;
+ siginfo_t info;
+
+ info.si_code = SEGV_MAPERR;
#if 0
printk("wf<pid=%d,wr=%d,addr=%08lx>\n",
@@ -401,6 +443,7 @@
if(expand_stack(vma, address))
goto bad_area;
good_area:
+ info.si_code = SEGV_ACCERR;
if(write) {
if(!(vma->vm_flags & VM_WRITE))
goto bad_area;
@@ -418,16 +461,23 @@
printk("Window whee %s [%d]: segfaults at %08lx\n",
tsk->comm, tsk->pid, address);
#endif
- tsk->thread.sig_address = address;
- tsk->thread.sig_desc = SUBSIG_NOMAPPING;
- send_sig(SIGSEGV, tsk, 1);
+ info.si_signo = SIGSEGV;
+ info.si_errno = 0;
+ /* info.si_code set above to make clear whether
+ this was a SEGV_MAPERR or SEGV_ACCERR fault. */
+ info.si_addr = (void *)address;
+ info.si_trapno = 0;
+ force_sig_info (SIGSEGV, &info, tsk);
return;
do_sigbus:
up(&mm->mmap_sem);
- tsk->thread.sig_address = address;
- tsk->thread.sig_desc = SUBSIG_MISCERROR;
- force_sig(SIGBUS, tsk);
+ info.si_signo = SIGBUS;
+ info.si_errno = 0;
+ info.si_code = BUS_ADRERR;
+ info.si_addr = (void *)address;
+ info.si_trapno = 0;
+ force_sig_info (SIGBUS, &info, tsk);
}
void window_overflow_fault(void)
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)