patch-2.4.0-test12 linux/arch/m68k/mm/fault.c
Next file: linux/arch/m68k/mvme147/config.c
Previous file: linux/arch/m68k/mac/via.c
Back to the patch index
Back to the overall index
- Lines: 248
- Date:
Mon Nov 27 17:11:26 2000
- Orig file:
v2.4.0-test11/linux/arch/m68k/mm/fault.c
- Orig date:
Mon Apr 24 15:51:29 2000
diff -u --recursive --new-file v2.4.0-test11/linux/arch/m68k/mm/fault.c linux/arch/m68k/mm/fault.c
@@ -19,6 +19,55 @@
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)
+{
+ siginfo_t siginfo = { 0, 0, 0, };
+
+ siginfo.si_signo = current->thread.signo;
+ siginfo.si_code = current->thread.code;
+ siginfo.si_addr = (void *)current->thread.faddr;
+ printk("send_fault_sig: %p,%d,%d\n", siginfo.si_addr, siginfo.si_signo, siginfo.si_code);
+
+ if (user_mode(regs)) {
+ force_sig_info(siginfo.si_signo,
+ &siginfo, 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 (siginfo.si_signo == SIGBUS)
+ // force_sig_info(siginfo.si_signo,
+ // &siginfo, current);
+
+ /*
+ * Oops. The kernel tried to access some bad page. We'll have to
+ * terminate things with extreme prejudice.
+ */
+ if ((unsigned long)siginfo.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", siginfo.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,16 +79,15 @@
* 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,
+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, fault;
#ifdef DEBUG
- printk ("regs->sr=%#x, regs->pc=%#lx, address=%#lx, %ld, %p\n",
+ printk ("do page fault:\nregs->sr=%#x, regs->pc=%#lx, address=%#lx, %ld, %p\n",
regs->sr, regs->pc, address, error_code,
current->mm->pgd);
#endif
@@ -55,43 +103,46 @@
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
* we can handle it..
*/
good_area:
+#ifdef DEBUG
+ printk("do_page_fault: good_area\n");
+#endif
write = 0;
switch (error_code & 3) {
default: /* 3: write, present */
/* 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;
}
/*
@@ -100,87 +151,56 @@
* the fault.
*/
fault = handle_mm_fault(mm, vma, address, write);
+#ifdef DEBUG
+ printk("handle_mm_fault returns %d\n",fault);
+#endif
if (fault < 0)
goto out_of_memory;
if (!fault)
- 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).
*/
+ #warning should be obsolete now...
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;
- }
-
-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;
- }
-
-/*
- * 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.
*/
out_of_memory:
- up(&mm->mmap_sem);
printk("VM: killing process %s\n", current->comm);
- if (error_code & 4)
+ if (user_mode(regs))
do_exit(SIGKILL);
- goto no_context;
-do_sigbus:
- 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;
+no_context:
+ current->thread.signo = SIGBUS;
+ current->thread.faddr = address;
+ return send_fault_sig(regs);
+
+bus_err:
+ current->thread.signo = SIGBUS;
+ current->thread.code = BUS_ADRERR;
+ current->thread.faddr = address;
+ goto send_sig;
+
+map_err:
+ current->thread.signo = SIGSEGV;
+ current->thread.code = SEGV_MAPERR;
+ current->thread.faddr = address;
+ goto send_sig;
+
+acc_err:
+ current->thread.signo = SIGSEGV;
+ current->thread.code = SEGV_ACCERR;
+ current->thread.faddr = address;
- return 1;
+send_sig:
+ up(&mm->mmap_sem);
+ 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)