Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * linux/arch/arm26/mm/fault.c | |
3 | * | |
4 | * Copyright (C) 1995 Linus Torvalds | |
5 | * Modifications for ARM processor (c) 1995-2001 Russell King | |
6 | * | |
7 | * This program is free software; you can redistribute it and/or modify | |
8 | * it under the terms of the GNU General Public License version 2 as | |
9 | * published by the Free Software Foundation. | |
10 | */ | |
1da177e4 LT |
11 | #include <linux/signal.h> |
12 | #include <linux/sched.h> | |
13 | #include <linux/kernel.h> | |
14 | #include <linux/errno.h> | |
15 | #include <linux/string.h> | |
16 | #include <linux/types.h> | |
17 | #include <linux/ptrace.h> | |
18 | #include <linux/mman.h> | |
19 | #include <linux/mm.h> | |
20 | #include <linux/interrupt.h> | |
21 | #include <linux/proc_fs.h> | |
22 | #include <linux/init.h> | |
23 | ||
24 | #include <asm/system.h> | |
25 | #include <asm/pgtable.h> | |
26 | #include <asm/uaccess.h> //FIXME this header may be bogusly included | |
27 | ||
28 | #include "fault.h" | |
29 | ||
30 | #define FAULT_CODE_LDRSTRPOST 0x80 | |
31 | #define FAULT_CODE_LDRSTRPRE 0x40 | |
32 | #define FAULT_CODE_LDRSTRREG 0x20 | |
33 | #define FAULT_CODE_LDMSTM 0x10 | |
34 | #define FAULT_CODE_LDCSTC 0x08 | |
35 | #define FAULT_CODE_PREFETCH 0x04 | |
36 | #define FAULT_CODE_WRITE 0x02 | |
37 | #define FAULT_CODE_FORCECOW 0x01 | |
38 | ||
39 | #define DO_COW(m) ((m) & (FAULT_CODE_WRITE|FAULT_CODE_FORCECOW)) | |
40 | #define READ_FAULT(m) (!((m) & FAULT_CODE_WRITE)) | |
41 | #define DEBUG | |
42 | /* | |
43 | * This is useful to dump out the page tables associated with | |
44 | * 'addr' in mm 'mm'. | |
45 | */ | |
46 | void show_pte(struct mm_struct *mm, unsigned long addr) | |
47 | { | |
48 | pgd_t *pgd; | |
49 | ||
50 | if (!mm) | |
51 | mm = &init_mm; | |
52 | ||
53 | printk(KERN_ALERT "pgd = %p\n", mm->pgd); | |
54 | pgd = pgd_offset(mm, addr); | |
55 | printk(KERN_ALERT "[%08lx] *pgd=%08lx", addr, pgd_val(*pgd)); | |
56 | ||
57 | do { | |
58 | pmd_t *pmd; | |
59 | pte_t *pte; | |
60 | ||
61 | pmd = pmd_offset(pgd, addr); | |
62 | ||
63 | if (pmd_none(*pmd)) | |
64 | break; | |
65 | ||
66 | if (pmd_bad(*pmd)) { | |
67 | printk("(bad)"); | |
68 | break; | |
69 | } | |
70 | ||
71 | /* We must not map this if we have highmem enabled */ | |
72 | /* FIXME */ | |
73 | pte = pte_offset_map(pmd, addr); | |
74 | printk(", *pte=%08lx", pte_val(*pte)); | |
75 | pte_unmap(pte); | |
76 | } while(0); | |
77 | ||
78 | printk("\n"); | |
79 | } | |
80 | ||
81 | /* | |
82 | * Oops. The kernel tried to access some page that wasn't present. | |
83 | */ | |
84 | static void | |
85 | __do_kernel_fault(struct mm_struct *mm, unsigned long addr, unsigned int fsr, | |
86 | struct pt_regs *regs) | |
87 | { | |
88 | /* | |
89 | * Are we prepared to handle this kernel fault? | |
90 | */ | |
91 | if (fixup_exception(regs)) | |
92 | return; | |
93 | ||
94 | /* | |
95 | * No handler, we'll have to terminate things with extreme prejudice. | |
96 | */ | |
97 | bust_spinlocks(1); | |
98 | printk(KERN_ALERT | |
99 | "Unable to handle kernel %s at virtual address %08lx\n", | |
100 | (addr < PAGE_SIZE) ? "NULL pointer dereference" : | |
101 | "paging request", addr); | |
102 | ||
103 | show_pte(mm, addr); | |
104 | die("Oops", regs, fsr); | |
105 | bust_spinlocks(0); | |
106 | do_exit(SIGKILL); | |
107 | } | |
108 | ||
109 | /* | |
110 | * Something tried to access memory that isn't in our memory map.. | |
111 | * User mode accesses just cause a SIGSEGV | |
112 | */ | |
113 | static void | |
114 | __do_user_fault(struct task_struct *tsk, unsigned long addr, | |
115 | unsigned int fsr, int code, struct pt_regs *regs) | |
116 | { | |
117 | struct siginfo si; | |
118 | ||
119 | #ifdef CONFIG_DEBUG_USER | |
120 | printk("%s: unhandled page fault at 0x%08lx, code 0x%03x\n", | |
121 | tsk->comm, addr, fsr); | |
122 | show_pte(tsk->mm, addr); | |
123 | show_regs(regs); | |
124 | //dump_backtrace(regs, tsk); // FIXME ARM32 dropped this - why? | |
125 | while(1); //FIXME - hack to stop debug going nutso | |
126 | #endif | |
127 | ||
128 | tsk->thread.address = addr; | |
129 | tsk->thread.error_code = fsr; | |
130 | tsk->thread.trap_no = 14; | |
131 | si.si_signo = SIGSEGV; | |
132 | si.si_errno = 0; | |
133 | si.si_code = code; | |
134 | si.si_addr = (void *)addr; | |
135 | force_sig_info(SIGSEGV, &si, tsk); | |
136 | } | |
137 | ||
138 | static int | |
139 | __do_page_fault(struct mm_struct *mm, unsigned long addr, unsigned int fsr, | |
140 | struct task_struct *tsk) | |
141 | { | |
142 | struct vm_area_struct *vma; | |
143 | int fault, mask; | |
144 | ||
145 | vma = find_vma(mm, addr); | |
146 | fault = -2; /* bad map area */ | |
147 | if (!vma) | |
148 | goto out; | |
149 | if (vma->vm_start > addr) | |
150 | goto check_stack; | |
151 | ||
152 | /* | |
153 | * Ok, we have a good vm_area for this | |
154 | * memory access, so we can handle it. | |
155 | */ | |
156 | good_area: | |
157 | if (READ_FAULT(fsr)) /* read? */ | |
df67b3da | 158 | mask = VM_READ|VM_EXEC|VM_WRITE; |
1da177e4 LT |
159 | else |
160 | mask = VM_WRITE; | |
161 | ||
162 | fault = -1; /* bad access type */ | |
163 | if (!(vma->vm_flags & mask)) | |
164 | goto out; | |
165 | ||
166 | /* | |
167 | * If for any reason at all we couldn't handle | |
168 | * the fault, make sure we exit gracefully rather | |
169 | * than endlessly redo the fault. | |
170 | */ | |
171 | survive: | |
172 | fault = handle_mm_fault(mm, vma, addr & PAGE_MASK, DO_COW(fsr)); | |
173 | ||
174 | /* | |
175 | * Handle the "normal" cases first - successful and sigbus | |
176 | */ | |
177 | switch (fault) { | |
6e346228 | 178 | case VM_FAULT_MAJOR: |
1da177e4 LT |
179 | tsk->maj_flt++; |
180 | return fault; | |
6e346228 | 181 | case VM_FAULT_MINOR: |
1da177e4 | 182 | tsk->min_flt++; |
6e346228 | 183 | case VM_FAULT_SIGBUS: |
1da177e4 LT |
184 | return fault; |
185 | } | |
186 | ||
187 | fault = -3; /* out of memory */ | |
f400e198 | 188 | if (!is_init(tsk)) |
1da177e4 LT |
189 | goto out; |
190 | ||
191 | /* | |
192 | * If we are out of memory for pid1, | |
193 | * sleep for a while and retry | |
194 | */ | |
195 | yield(); | |
196 | goto survive; | |
197 | ||
198 | check_stack: | |
199 | if (vma->vm_flags & VM_GROWSDOWN && !expand_stack(vma, addr)) | |
200 | goto good_area; | |
201 | out: | |
202 | return fault; | |
203 | } | |
204 | ||
205 | int do_page_fault(unsigned long addr, unsigned int fsr, struct pt_regs *regs) | |
206 | { | |
207 | struct task_struct *tsk; | |
208 | struct mm_struct *mm; | |
209 | int fault; | |
210 | ||
211 | tsk = current; | |
212 | mm = tsk->mm; | |
213 | ||
214 | /* | |
215 | * If we're in an interrupt or have no user | |
216 | * context, we must not take the fault.. | |
217 | */ | |
6edaf68a | 218 | if (in_atomic() || !mm) |
1da177e4 LT |
219 | goto no_context; |
220 | ||
221 | down_read(&mm->mmap_sem); | |
222 | fault = __do_page_fault(mm, addr, fsr, tsk); | |
223 | up_read(&mm->mmap_sem); | |
224 | ||
225 | /* | |
226 | * Handle the "normal" case first | |
227 | */ | |
6e346228 LT |
228 | switch (fault) { |
229 | case VM_FAULT_MINOR: | |
230 | case VM_FAULT_MAJOR: | |
1da177e4 | 231 | return 0; |
6e346228 | 232 | case VM_FAULT_SIGBUS: |
1da177e4 LT |
233 | goto do_sigbus; |
234 | } | |
235 | ||
236 | /* | |
237 | * If we are in kernel mode at this point, we | |
238 | * have no context to handle this fault with. | |
239 | * FIXME - is this test right? | |
240 | */ | |
241 | if (!user_mode(regs)){ | |
242 | goto no_context; | |
243 | } | |
244 | ||
245 | if (fault == -3) { | |
246 | /* | |
247 | * We ran out of memory, or some other thing happened to | |
248 | * us that made us unable to handle the page fault gracefully. | |
249 | */ | |
250 | printk("VM: killing process %s\n", tsk->comm); | |
251 | do_exit(SIGKILL); | |
252 | } | |
253 | else{ | |
254 | __do_user_fault(tsk, addr, fsr, fault == -1 ? SEGV_ACCERR : SEGV_MAPERR, regs); | |
255 | } | |
256 | ||
257 | return 0; | |
258 | ||
259 | ||
260 | /* | |
261 | * We ran out of memory, or some other thing happened to us that made | |
262 | * us unable to handle the page fault gracefully. | |
263 | */ | |
264 | do_sigbus: | |
265 | /* | |
266 | * Send a sigbus, regardless of whether we were in kernel | |
267 | * or user mode. | |
268 | */ | |
269 | tsk->thread.address = addr; //FIXME - need other bits setting? | |
270 | tsk->thread.error_code = fsr; | |
271 | tsk->thread.trap_no = 14; | |
272 | force_sig(SIGBUS, tsk); | |
273 | #ifdef CONFIG_DEBUG_USER | |
274 | printk(KERN_DEBUG "%s: sigbus at 0x%08lx, pc=0x%08lx\n", | |
275 | current->comm, addr, instruction_pointer(regs)); | |
276 | #endif | |
277 | ||
278 | /* Kernel mode? Handle exceptions or die */ | |
279 | if (user_mode(regs)) | |
280 | return 0; | |
281 | ||
282 | no_context: | |
283 | __do_kernel_fault(mm, addr, fsr, regs); | |
284 | return 0; | |
285 | } | |
286 | ||
287 | /* | |
288 | * Handle a data abort. Note that we have to handle a range of addresses | |
289 | * on ARM2/3 for ldm. If both pages are zero-mapped, then we have to force | |
290 | * a copy-on-write. However, on the second page, we always force COW. | |
291 | */ | |
292 | asmlinkage void | |
293 | do_DataAbort(unsigned long min_addr, unsigned long max_addr, int mode, struct pt_regs *regs) | |
294 | { | |
295 | do_page_fault(min_addr, mode, regs); | |
296 | ||
297 | if ((min_addr ^ max_addr) >> PAGE_SHIFT){ | |
298 | do_page_fault(max_addr, mode | FAULT_CODE_FORCECOW, regs); | |
299 | } | |
300 | } | |
301 | ||
302 | asmlinkage int | |
303 | do_PrefetchAbort(unsigned long addr, struct pt_regs *regs) | |
304 | { | |
305 | #if 0 | |
306 | if (the memc mapping for this page exists) { | |
307 | printk ("Page in, but got abort (undefined instruction?)\n"); | |
308 | return 0; | |
309 | } | |
310 | #endif | |
311 | do_page_fault(addr, FAULT_CODE_PREFETCH, regs); | |
312 | return 1; | |
313 | } | |
314 |