patch-2.2.18 linux/arch/m68k/mm/fault.c
Next file: linux/arch/m68k/mm/init.c
Previous file: linux/arch/m68k/math-emu/multi_arith.h
Back to the patch index
Back to the overall index
- Lines: 214
- Date:
Fri Oct 13 23:30:47 2000
- Orig file:
v2.2.17/arch/m68k/mm/fault.c
- Orig date:
Fri Apr 21 12:45:46 2000
diff -u --new-file --recursive --exclude-from /usr/src/exclude v2.2.17/arch/m68k/mm/fault.c linux/arch/m68k/mm/fault.c
@@ -19,6 +19,48 @@
extern void die_if_kernel(char *, struct pt_regs *, long);
extern const int frame_extra_sizes[]; /* in m68k/kernel/signal.c */
+int send_fault_sig(struct pt_regs *regs)
+{
+ if (user_mode(regs)) {
+ force_sig_info(current->buserr_info.si_signo,
+ ¤t->buserr_info, current);
+ } else {
+ unsigned long fixup;
+
+ /* Are we prepared to handle this kernel fault? */
+ if ((fixup = search_exception_table(regs->pc))) {
+ struct pt_regs *tregs;
+ /* Create a new four word stack frame, discarding the old
+ one. */
+ regs->stkadj = frame_extra_sizes[regs->format];
+ tregs = (struct pt_regs *)((ulong)regs + regs->stkadj);
+ tregs->vector = regs->vector;
+ tregs->format = 0;
+ tregs->pc = fixup;
+ tregs->sr = regs->sr;
+ return -1;
+ }
+
+ if (current->buserr_info.si_signo == SIGBUS)
+ force_sig_info(current->buserr_info.si_signo,
+ ¤t->buserr_info, current);
+
+ /*
+ * Oops. The kernel tried to access some bad page. We'll have to
+ * terminate things with extreme prejudice.
+ */
+ if ((unsigned long)current->buserr_info.si_addr < PAGE_SIZE)
+ printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
+ else
+ printk(KERN_ALERT "Unable to handle kernel access");
+ printk(" at virtual address %p\n", current->buserr_info.si_addr);
+ die_if_kernel("Oops", regs, 0 /*error_code*/);
+ do_exit(SIGKILL);
+ }
+
+ return 1;
+}
+
/*
* This routine handles page faults. It determines the problem, and
* then passes it off to one of the appropriate routines.
@@ -30,12 +72,11 @@
* If this routine detects a bad access, it returns 1, otherwise it
* returns 0.
*/
-asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address,
- unsigned long error_code)
+int do_page_fault(struct pt_regs *regs, unsigned long address,
+ unsigned long error_code)
{
struct mm_struct *mm = current->mm;
struct vm_area_struct * vma;
- unsigned long fixup;
int write;
#ifdef DEBUG
@@ -56,23 +97,23 @@
vma = find_vma(mm, address);
if (!vma)
- goto bad_area;
+ goto map_err;
if (vma->vm_flags & VM_IO)
- goto bad_area;
+ goto acc_err;
if (vma->vm_start <= address)
goto good_area;
if (!(vma->vm_flags & VM_GROWSDOWN))
- goto bad_area;
+ goto map_err;
if (user_mode(regs)) {
/* Accessing the stack below usp is always a bug. The
"+ 256" is there due to some instructions doing
pre-decrement on the stack and that doesn't show up
until later. */
if (address + 256 < rdusp())
- goto bad_area;
+ goto map_err;
}
if (expand_stack(vma, address))
- goto bad_area;
+ goto map_err;
/*
* Ok, we have a good vm_area for this memory access, so
@@ -85,14 +126,14 @@
/* fall through */
case 2: /* write, not present */
if (!(vma->vm_flags & VM_WRITE))
- goto bad_area;
+ goto acc_err;
write++;
break;
case 1: /* read, present */
- goto bad_area;
+ goto acc_err;
case 0: /* read, not present */
if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
- goto bad_area;
+ goto acc_err;
}
/*
@@ -101,77 +142,42 @@
* the fault.
*/
if (!handle_mm_fault(current, vma, address, write))
- goto do_sigbus;
+ goto bus_err;
/* There seems to be a missing invalidate somewhere in do_no_page.
* Until I found it, this one cures the problem and makes
* 1.2 run on the 68040 (Martin Apel).
*/
+
if (CPU_IS_040_OR_060)
flush_tlb_page(vma, address);
- up(&mm->mmap_sem);
- return 0;
-/*
- * 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 (user_mode(regs)) {
- siginfo_t info;
- info.si_signo = SIGSEGV;
- info.si_code = SEGV_MAPERR;
- info.si_addr = (void *)address;
- force_sig_info(SIGSEGV, &info, current);
- return 1;
- }
+ return 0;
no_context:
- /* Are we prepared to handle this kernel fault? */
- if ((fixup = search_exception_table(regs->pc)) != 0) {
- struct pt_regs *tregs;
- /* Create a new four word stack frame, discarding the old
- one. */
- regs->stkadj = frame_extra_sizes[regs->format];
- tregs = (struct pt_regs *)((ulong)regs + regs->stkadj);
- tregs->vector = regs->vector;
- tregs->format = 0;
- tregs->pc = fixup;
- tregs->sr = regs->sr;
- return -1;
- }
+ current->buserr_info.si_signo = SIGBUS;
+ current->buserr_info.si_addr = (void *)address;
+ return send_fault_sig(regs);
+
+bus_err:
+ current->buserr_info.si_signo = SIGBUS;
+ current->buserr_info.si_code = BUS_ADRERR;
+ current->buserr_info.si_addr = (void *)address;
+ goto send_sig;
+
+map_err:
+ current->buserr_info.si_signo = SIGSEGV;
+ current->buserr_info.si_code = SEGV_MAPERR;
+ current->buserr_info.si_addr = (void *)address;
+ goto send_sig;
+
+acc_err:
+ current->buserr_info.si_signo = SIGSEGV;
+ current->buserr_info.si_code = SEGV_ACCERR;
+ current->buserr_info.si_addr = (void *)address;
-/*
- * Oops. The kernel tried to access some bad page. We'll have to
- * terminate things with extreme prejudice.
- */
- if ((unsigned long) address < PAGE_SIZE) {
- printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
- } else
- printk(KERN_ALERT "Unable to handle kernel access");
- printk(" at virtual address %08lx\n",address);
- die_if_kernel("Oops", regs, error_code);
- 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.
- */
-do_sigbus:
+send_sig:
up(&mm->mmap_sem);
-
- /*
- * Send a sigbus, regardless of whether we were in kernel
- * or user mode.
- */
- force_sig(SIGBUS, current);
-
- /* Kernel mode? Handle exceptions or die */
- if (!user_mode(regs))
- goto no_context;
-
- return 1;
+ return send_fault_sig(regs);
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)