patch-2.1.80 linux/arch/arm/mm/fault-armo.c
Next file: linux/arch/arm/mm/fault-armv.c
Previous file: linux/arch/arm/mm/extable.c
Back to the patch index
Back to the overall index
- Lines: 160
- Date:
Tue Jan 20 16:39:42 1998
- Orig file:
v2.1.79/linux/arch/arm/mm/fault-armo.c
- Orig date:
Wed Dec 31 16:00:00 1969
diff -u --recursive --new-file v2.1.79/linux/arch/arm/mm/fault-armo.c linux/arch/arm/mm/fault-armo.c
@@ -0,0 +1,159 @@
+/*
+ * linux/arch/arm/mm/fault.c
+ *
+ * Copyright (C) 1995 Linus Torvalds
+ * Modifications for ARM processor (c) 1995, 1996 Russell King
+ */
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/head.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/ptrace.h>
+#include <linux/mman.h>
+#include <linux/mm.h>
+#include <linux/smp.h>
+#include <linux/smp_lock.h>
+
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+
+#define FAULT_CODE_FORCECOW 0x80
+#define FAULT_CODE_PREFETCH 0x04
+#define FAULT_CODE_WRITE 0x02
+#define FAULT_CODE_USER 0x01
+
+extern void die_if_kernel(char *msg, struct pt_regs *regs, unsigned int err, unsigned int ret);
+
+static void kernel_page_fault (unsigned long addr, int mode, struct pt_regs *regs,
+ struct task_struct *tsk, struct mm_struct *mm)
+{
+ /*
+ * Oops. The kernel tried to access some bad page. We'll have to
+ * terminate things with extreme prejudice.
+ */
+ pgd_t *pgd;
+ if (addr < 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", addr);
+ printk (KERN_ALERT "current->tss.memmap = %08lX\n", tsk->tss.memmap);
+ pgd = pgd_offset (mm, addr);
+ printk (KERN_ALERT "*pgd = %08lx", pgd_val (*pgd));
+ if (!pgd_none (*pgd)) {
+ pmd_t *pmd;
+ pmd = pmd_offset (pgd, addr);
+ printk (", *pmd = %08lx", pmd_val (*pmd));
+ if (!pmd_none (*pmd))
+ printk (", *pte = %08lx", pte_val (*pte_offset (pmd, addr)));
+ }
+ printk ("\n");
+ die_if_kernel ("Oops", regs, mode, SIGKILL);
+ do_exit (SIGKILL);
+}
+
+static void
+handle_dataabort (unsigned long addr, int mode, struct pt_regs *regs)
+{
+ struct task_struct *tsk;
+ struct mm_struct *mm;
+ struct vm_area_struct *vma;
+ unsigned long fixup;
+
+ lock_kernel();
+ tsk = current;
+ mm = tsk->mm;
+
+ down(&mm->mmap_sem);
+ vma = find_vma (mm, addr);
+ if (!vma)
+ goto bad_area;
+ if (addr >= vma->vm_start)
+ goto good_area;
+ if (!(vma->vm_flags & VM_GROWSDOWN) || expand_stack (vma, addr))
+ goto bad_area;
+
+ /*
+ * Ok, we have a good vm_area for this memory access, so
+ * we can handle it..
+ */
+good_area:
+ if (!(mode & FAULT_CODE_WRITE)) { /* write? */
+ if (!(vma->vm_flags & (VM_READ|VM_EXEC)))
+ goto bad_area;
+ } else {
+ if (!(vma->vm_flags & VM_WRITE))
+ goto bad_area;
+ }
+ handle_mm_fault (tsk, vma, addr, mode & (FAULT_CODE_WRITE|FAULT_CODE_FORCECOW));
+ up(&mm->mmap_sem);
+ 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..
+ */
+bad_area:
+ up(&mm->mmap_sem);
+ if (mode & FAULT_CODE_USER) {
+extern int console_loglevel;
+cli();
+ tsk->tss.error_code = mode;
+ tsk->tss.trap_no = 14;
+console_loglevel = 9;
+ printk ("%s: memory violation at pc=0x%08lx, lr=0x%08lx (bad address=0x%08lx, code %d)\n",
+ tsk->comm, regs->ARM_pc, regs->ARM_lr, addr, mode);
+//#ifdef DEBUG
+ show_regs (regs);
+ c_backtrace (regs->ARM_fp, 0);
+//#endif
+ force_sig(SIGSEGV, tsk);
+while (1);
+ goto out;
+ }
+
+ /* Are we prepared to handle this kernel fault? */
+ if ((fixup = search_exception_table(regs->ARM_pc)) != 0) {
+ printk(KERN_DEBUG "%s: Exception at [<%lx>] addr=%lx (fixup: %lx)\n",
+ tsk->comm, regs->ARM_pc, addr, fixup);
+ regs->ARM_pc = fixup;
+ goto out;
+ }
+
+
+ kernel_page_fault (addr, mode, regs, tsk, mm);
+out:
+ unlock_kernel();
+}
+
+/*
+ * Handle a data abort. Note that we have to handle a range of addresses
+ * on ARM2/3 for ldm. If both pages are zero-mapped, then we have to force
+ * a copy-on-write
+ */
+asmlinkage void
+do_DataAbort (unsigned long min_addr, unsigned long max_addr, int mode, struct pt_regs *regs)
+{
+ handle_dataabort (min_addr, mode, regs);
+
+ if ((min_addr ^ max_addr) >> PAGE_SHIFT)
+ handle_dataabort (max_addr, mode | FAULT_CODE_FORCECOW, regs);
+}
+
+asmlinkage int
+do_PrefetchAbort (unsigned long addr, int mode, struct pt_regs *regs)
+{
+#if 0
+ if (the memc mapping for this page exists - can check now...) {
+ printk ("Page in, but got abort (undefined instruction?)\n");
+ return 0;
+ }
+#endif
+ handle_dataabort (addr, mode, regs);
+ return 1;
+}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov