Import 2.3.12pre2
[davej-history.git] / arch / m68k / mm / fault.c
blob7ae87b23f5f8b453a100ca78e739f80d280732e0
1 /*
2 * linux/arch/m68k/mm/fault.c
4 * Copyright (C) 1995 Hamish Macdonald
5 */
7 #include <linux/mman.h>
8 #include <linux/mm.h>
9 #include <linux/kernel.h>
10 #include <linux/ptrace.h>
11 #include <linux/interrupt.h>
13 #include <asm/setup.h>
14 #include <asm/traps.h>
15 #include <asm/system.h>
16 #include <asm/uaccess.h>
17 #include <asm/pgtable.h>
19 extern void die_if_kernel(char *, struct pt_regs *, long);
20 extern const int frame_extra_sizes[]; /* in m68k/kernel/signal.c */
23 * This routine handles page faults. It determines the problem, and
24 * then passes it off to one of the appropriate routines.
26 * error_code:
27 * bit 0 == 0 means no page found, 1 means protection fault
28 * bit 1 == 0 means read, 1 means write
30 * If this routine detects a bad access, it returns 1, otherwise it
31 * returns 0.
33 asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long address,
34 unsigned long error_code)
36 struct mm_struct *mm = current->mm;
37 struct vm_area_struct * vma;
38 unsigned long fixup;
39 int write;
41 #ifdef DEBUG
42 printk ("regs->sr=%#x, regs->pc=%#lx, address=%#lx, %ld, %p\n",
43 regs->sr, regs->pc, address, error_code,
44 current->mm->pgd);
45 #endif
49 * If we're in an interrupt or have no user
50 * context, we must not take the fault..
52 if (in_interrupt() || !mm)
53 goto no_context;
55 down(&mm->mmap_sem);
57 vma = find_vma(mm, address);
58 if (!vma)
59 goto bad_area;
60 if (vma->vm_flags & VM_IO)
61 goto bad_area;
62 if (vma->vm_start <= address)
63 goto good_area;
64 if (!(vma->vm_flags & VM_GROWSDOWN))
65 goto bad_area;
66 if (user_mode(regs)) {
67 /* Accessing the stack below usp is always a bug. The
68 "+ 256" is there due to some instructions doing
69 pre-decrement on the stack and that doesn't show up
70 until later. */
71 if (address + 256 < rdusp())
72 goto bad_area;
74 if (expand_stack(vma, address))
75 goto bad_area;
78 * Ok, we have a good vm_area for this memory access, so
79 * we can handle it..
81 good_area:
82 write = 0;
83 switch (error_code & 3) {
84 default: /* 3: write, present */
85 /* fall through */
86 case 2: /* write, not present */
87 if (!(vma->vm_flags & VM_WRITE))
88 goto bad_area;
89 write++;
90 break;
91 case 1: /* read, present */
92 goto bad_area;
93 case 0: /* read, not present */
94 if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
95 goto bad_area;
99 * If for any reason at all we couldn't handle the fault,
100 * make sure we exit gracefully rather than endlessly redo
101 * the fault.
103 if (!handle_mm_fault(current, vma, address, write))
104 goto do_sigbus;
106 /* There seems to be a missing invalidate somewhere in do_no_page.
107 * Until I found it, this one cures the problem and makes
108 * 1.2 run on the 68040 (Martin Apel).
110 if (CPU_IS_040_OR_060)
111 flush_tlb_page(vma, address);
112 up(&mm->mmap_sem);
113 return 0;
116 * Something tried to access memory that isn't in our memory map..
117 * Fix it, but check if it's kernel or user first..
119 bad_area:
120 up(&mm->mmap_sem);
122 /* User mode accesses just cause a SIGSEGV */
123 if (user_mode(regs)) {
124 siginfo_t info;
125 info.si_signo = SIGSEGV;
126 info.si_code = SEGV_MAPERR;
127 info.si_addr = (void *)address;
128 force_sig_info(SIGSEGV, &info, current);
129 return 1;
132 no_context:
133 /* Are we prepared to handle this kernel fault? */
134 if ((fixup = search_exception_table(regs->pc)) != 0) {
135 struct pt_regs *tregs;
136 /* Create a new four word stack frame, discarding the old
137 one. */
138 regs->stkadj = frame_extra_sizes[regs->format];
139 tregs = (struct pt_regs *)((ulong)regs + regs->stkadj);
140 tregs->vector = regs->vector;
141 tregs->format = 0;
142 tregs->pc = fixup;
143 tregs->sr = regs->sr;
144 return -1;
148 * Oops. The kernel tried to access some bad page. We'll have to
149 * terminate things with extreme prejudice.
151 if ((unsigned long) address < PAGE_SIZE) {
152 printk(KERN_ALERT "Unable to handle kernel NULL pointer dereference");
153 } else
154 printk(KERN_ALERT "Unable to handle kernel access");
155 printk(" at virtual address %08lx\n",address);
156 die_if_kernel("Oops", regs, error_code);
157 do_exit(SIGKILL);
160 * We ran out of memory, or some other thing happened to us that made
161 * us unable to handle the page fault gracefully.
163 do_sigbus:
164 up(&mm->mmap_sem);
167 * Send a sigbus, regardless of whether we were in kernel
168 * or user mode.
170 force_sig(SIGBUS, current);
172 /* Kernel mode? Handle exceptions or die */
173 if (!user_mode(regs))
174 goto no_context;
176 return 1;