fault.c revision 1.4.2.11 1 1.4.2.11 nathanw /* $NetBSD: fault.c,v 1.4.2.11 2002/08/13 02:17:50 nathanw Exp $ */
2 1.4.2.2 thorpej
3 1.4.2.2 thorpej /*
4 1.4.2.2 thorpej * Copyright (c) 1994-1997 Mark Brinicombe.
5 1.4.2.2 thorpej * Copyright (c) 1994 Brini.
6 1.4.2.2 thorpej * All rights reserved.
7 1.4.2.2 thorpej *
8 1.4.2.2 thorpej * This code is derived from software written for Brini by Mark Brinicombe
9 1.4.2.2 thorpej *
10 1.4.2.2 thorpej * Redistribution and use in source and binary forms, with or without
11 1.4.2.2 thorpej * modification, are permitted provided that the following conditions
12 1.4.2.2 thorpej * are met:
13 1.4.2.2 thorpej * 1. Redistributions of source code must retain the above copyright
14 1.4.2.2 thorpej * notice, this list of conditions and the following disclaimer.
15 1.4.2.2 thorpej * 2. Redistributions in binary form must reproduce the above copyright
16 1.4.2.2 thorpej * notice, this list of conditions and the following disclaimer in the
17 1.4.2.2 thorpej * documentation and/or other materials provided with the distribution.
18 1.4.2.2 thorpej * 3. All advertising materials mentioning features or use of this software
19 1.4.2.2 thorpej * must display the following acknowledgement:
20 1.4.2.2 thorpej * This product includes software developed by Brini.
21 1.4.2.2 thorpej * 4. The name of the company nor the name of the author may be used to
22 1.4.2.2 thorpej * endorse or promote products derived from this software without specific
23 1.4.2.2 thorpej * prior written permission.
24 1.4.2.2 thorpej *
25 1.4.2.2 thorpej * THIS SOFTWARE IS PROVIDED BY BRINI ``AS IS'' AND ANY EXPRESS OR IMPLIED
26 1.4.2.2 thorpej * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
27 1.4.2.2 thorpej * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
28 1.4.2.2 thorpej * IN NO EVENT SHALL BRINI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
29 1.4.2.2 thorpej * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
30 1.4.2.2 thorpej * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
31 1.4.2.2 thorpej * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32 1.4.2.2 thorpej * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33 1.4.2.2 thorpej * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34 1.4.2.2 thorpej * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 1.4.2.2 thorpej * SUCH DAMAGE.
36 1.4.2.2 thorpej *
37 1.4.2.2 thorpej * RiscBSD kernel project
38 1.4.2.2 thorpej *
39 1.4.2.2 thorpej * fault.c
40 1.4.2.2 thorpej *
41 1.4.2.2 thorpej * Fault handlers
42 1.4.2.2 thorpej *
43 1.4.2.2 thorpej * Created : 28/11/94
44 1.4.2.2 thorpej */
45 1.4.2.2 thorpej
46 1.4.2.2 thorpej #include "opt_ddb.h"
47 1.4.2.2 thorpej #include "opt_pmap_debug.h"
48 1.4.2.2 thorpej
49 1.4.2.2 thorpej #include <sys/types.h>
50 1.4.2.11 nathanw __KERNEL_RCSID(0, "$NetBSD: fault.c,v 1.4.2.11 2002/08/13 02:17:50 nathanw Exp $");
51 1.4.2.11 nathanw
52 1.4.2.2 thorpej #include <sys/param.h>
53 1.4.2.2 thorpej #include <sys/systm.h>
54 1.4.2.2 thorpej #include <sys/proc.h>
55 1.4.2.2 thorpej #include <sys/user.h>
56 1.4.2.2 thorpej #include <sys/kernel.h>
57 1.4.2.2 thorpej
58 1.4.2.2 thorpej #include <uvm/uvm_extern.h>
59 1.4.2.2 thorpej
60 1.4.2.8 nathanw #include <arm/cpuconf.h>
61 1.4.2.8 nathanw
62 1.4.2.2 thorpej #include <machine/frame.h>
63 1.4.2.3 nathanw #include <arm/arm32/katelib.h>
64 1.4.2.2 thorpej #include <machine/cpu.h>
65 1.4.2.2 thorpej #include <machine/intr.h>
66 1.4.2.2 thorpej #ifdef DDB
67 1.4.2.2 thorpej #include <machine/db_machdep.h>
68 1.4.2.2 thorpej #endif
69 1.4.2.2 thorpej
70 1.4.2.2 thorpej #include <arch/arm/arm/disassem.h>
71 1.4.2.4 nathanw #include <arm/arm32/machdep.h>
72 1.4.2.4 nathanw
73 1.4.2.2 thorpej int cowfault __P((vaddr_t));
74 1.4.2.2 thorpej extern char fusubailout[];
75 1.4.2.2 thorpej
76 1.4.2.4 nathanw static void report_abort __P((const char *, u_int, u_int, u_int));
77 1.4.2.4 nathanw
78 1.4.2.2 thorpej /* Abort code */
79 1.4.2.2 thorpej
80 1.4.2.2 thorpej /* Define text descriptions of the different aborts */
81 1.4.2.2 thorpej
82 1.4.2.2 thorpej static const char *aborts[16] = {
83 1.4.2.2 thorpej "Write buffer fault",
84 1.4.2.2 thorpej "Alignment fault",
85 1.4.2.2 thorpej "Write buffer fault",
86 1.4.2.2 thorpej "Alignment fault",
87 1.4.2.2 thorpej "Bus error (LF section)",
88 1.4.2.2 thorpej "Translation fault (section)",
89 1.4.2.2 thorpej "Bus error (page)",
90 1.4.2.2 thorpej "Translation fault (page)",
91 1.4.2.2 thorpej "Bus error (section)",
92 1.4.2.2 thorpej "Domain error (section)",
93 1.4.2.2 thorpej "Bus error (page)",
94 1.4.2.2 thorpej "Domain error (page)",
95 1.4.2.2 thorpej "Bus error trans (L1)",
96 1.4.2.2 thorpej "Permission error (section)",
97 1.4.2.2 thorpej "Bus error trans (L2)",
98 1.4.2.2 thorpej "Permission error (page)"
99 1.4.2.2 thorpej };
100 1.4.2.2 thorpej
101 1.4.2.4 nathanw static void
102 1.4.2.2 thorpej report_abort(prefix, fault_status, fault_address, fault_pc)
103 1.4.2.2 thorpej const char *prefix;
104 1.4.2.2 thorpej u_int fault_status;
105 1.4.2.2 thorpej u_int fault_address;
106 1.4.2.2 thorpej u_int fault_pc;
107 1.4.2.2 thorpej {
108 1.4.2.2 thorpej #ifndef DEBUG
109 1.4.2.2 thorpej if (prefix == NULL) {
110 1.4.2.2 thorpej #endif
111 1.4.2.2 thorpej if (prefix)
112 1.4.2.2 thorpej printf("%s ", prefix);
113 1.4.2.2 thorpej printf("Data abort: '%s' status=%03x address=%08x PC=%08x\n",
114 1.4.2.2 thorpej aborts[fault_status & FAULT_TYPE_MASK],
115 1.4.2.2 thorpej fault_status & 0xfff, fault_address, fault_pc);
116 1.4.2.2 thorpej #ifndef DEBUG
117 1.4.2.2 thorpej }
118 1.4.2.2 thorpej #endif
119 1.4.2.2 thorpej }
120 1.4.2.2 thorpej
121 1.4.2.2 thorpej static __volatile int data_abort_expected;
122 1.4.2.2 thorpej static __volatile int data_abort_received;
123 1.4.2.2 thorpej
124 1.4.2.2 thorpej int
125 1.4.2.2 thorpej badaddr_read(void *addr, size_t size, void *rptr)
126 1.4.2.2 thorpej {
127 1.4.2.2 thorpej u_long rcpt;
128 1.4.2.2 thorpej int rv;
129 1.4.2.2 thorpej
130 1.4.2.2 thorpej /* Tell the Data Abort handler that we're expecting one. */
131 1.4.2.2 thorpej data_abort_received = 0;
132 1.4.2.2 thorpej data_abort_expected = 1;
133 1.4.2.2 thorpej
134 1.4.2.2 thorpej cpu_drain_writebuf();
135 1.4.2.2 thorpej
136 1.4.2.2 thorpej /* Read from the test address. */
137 1.4.2.2 thorpej switch (size) {
138 1.4.2.2 thorpej case sizeof(uint8_t):
139 1.4.2.2 thorpej __asm __volatile("ldrb %0, [%1]"
140 1.4.2.2 thorpej : "=r" (rcpt)
141 1.4.2.2 thorpej : "r" (addr));
142 1.4.2.2 thorpej break;
143 1.4.2.2 thorpej
144 1.4.2.2 thorpej case sizeof(uint16_t):
145 1.4.2.2 thorpej __asm __volatile("ldrh %0, [%1]"
146 1.4.2.2 thorpej : "=r" (rcpt)
147 1.4.2.2 thorpej : "r" (addr));
148 1.4.2.2 thorpej break;
149 1.4.2.2 thorpej
150 1.4.2.2 thorpej case sizeof(uint32_t):
151 1.4.2.2 thorpej __asm __volatile("ldr %0, [%1]"
152 1.4.2.2 thorpej : "=r" (rcpt)
153 1.4.2.2 thorpej : "r" (addr));
154 1.4.2.2 thorpej break;
155 1.4.2.2 thorpej
156 1.4.2.2 thorpej default:
157 1.4.2.2 thorpej data_abort_expected = 0;
158 1.4.2.2 thorpej panic("badaddr: invalid size (%lu)\n", (u_long) size);
159 1.4.2.2 thorpej }
160 1.4.2.2 thorpej
161 1.4.2.2 thorpej /* Disallow further Data Aborts. */
162 1.4.2.2 thorpej data_abort_expected = 0;
163 1.4.2.2 thorpej
164 1.4.2.2 thorpej rv = data_abort_received;
165 1.4.2.2 thorpej data_abort_received = 0;
166 1.4.2.2 thorpej
167 1.4.2.2 thorpej /* Copy the data back if no fault occurred. */
168 1.4.2.2 thorpej if (rptr != NULL && rv == 0) {
169 1.4.2.2 thorpej switch (size) {
170 1.4.2.2 thorpej case sizeof(uint8_t):
171 1.4.2.2 thorpej *(uint8_t *) rptr = rcpt;
172 1.4.2.2 thorpej break;
173 1.4.2.2 thorpej
174 1.4.2.2 thorpej case sizeof(uint16_t):
175 1.4.2.2 thorpej *(uint16_t *) rptr = rcpt;
176 1.4.2.2 thorpej break;
177 1.4.2.2 thorpej
178 1.4.2.2 thorpej case sizeof(uint32_t):
179 1.4.2.2 thorpej *(uint32_t *) rptr = rcpt;
180 1.4.2.2 thorpej break;
181 1.4.2.2 thorpej }
182 1.4.2.2 thorpej }
183 1.4.2.2 thorpej
184 1.4.2.2 thorpej /* Return true if the address was invalid. */
185 1.4.2.2 thorpej return (rv);
186 1.4.2.2 thorpej }
187 1.4.2.2 thorpej
188 1.4.2.2 thorpej /*
189 1.4.2.2 thorpej * void data_abort_handler(trapframe_t *frame)
190 1.4.2.2 thorpej *
191 1.4.2.2 thorpej * Abort handler called when read/write occurs at an address of
192 1.4.2.2 thorpej * a non existent or restricted (access permissions) memory page.
193 1.4.2.2 thorpej * We first need to identify the type of page fault.
194 1.4.2.2 thorpej */
195 1.4.2.2 thorpej
196 1.4.2.2 thorpej #define TRAP_CODE ((fault_status & 0x0f) | (fault_address & 0xfffffff0))
197 1.4.2.2 thorpej
198 1.4.2.2 thorpej void
199 1.4.2.2 thorpej data_abort_handler(frame)
200 1.4.2.2 thorpej trapframe_t *frame;
201 1.4.2.2 thorpej {
202 1.4.2.2 thorpej struct lwp *l;
203 1.4.2.2 thorpej struct proc *p;
204 1.4.2.2 thorpej struct pcb *pcb;
205 1.4.2.2 thorpej u_int fault_address;
206 1.4.2.2 thorpej u_int fault_status;
207 1.4.2.2 thorpej u_int fault_pc;
208 1.4.2.2 thorpej u_int fault_instruction;
209 1.4.2.2 thorpej int fault_code;
210 1.4.2.2 thorpej int user;
211 1.4.2.2 thorpej int error;
212 1.4.2.2 thorpej void *onfault;
213 1.4.2.2 thorpej
214 1.4.2.2 thorpej /*
215 1.4.2.2 thorpej * If we were expecting a Data Abort, signal that we got
216 1.4.2.2 thorpej * one, adjust the PC to skip the faulting insn, and
217 1.4.2.2 thorpej * return.
218 1.4.2.2 thorpej */
219 1.4.2.2 thorpej if (data_abort_expected) {
220 1.4.2.2 thorpej data_abort_received = 1;
221 1.4.2.2 thorpej frame->tf_pc += INSN_SIZE;
222 1.4.2.2 thorpej return;
223 1.4.2.2 thorpej }
224 1.4.2.2 thorpej
225 1.4.2.2 thorpej /*
226 1.4.2.2 thorpej * Must get fault address and status from the CPU before
227 1.4.2.2 thorpej * re-enabling interrupts. (Interrupt handlers may take
228 1.4.2.2 thorpej * R/M emulation faults.)
229 1.4.2.2 thorpej */
230 1.4.2.2 thorpej fault_address = cpu_faultaddress();
231 1.4.2.2 thorpej fault_status = cpu_faultstatus();
232 1.4.2.2 thorpej fault_pc = frame->tf_pc;
233 1.4.2.2 thorpej
234 1.4.2.2 thorpej /*
235 1.4.2.2 thorpej * Enable IRQ's (disabled by CPU on abort) if trapframe
236 1.4.2.2 thorpej * shows they were enabled.
237 1.4.2.2 thorpej */
238 1.4.2.2 thorpej if (!(frame->tf_spsr & I32_bit))
239 1.4.2.2 thorpej enable_interrupts(I32_bit);
240 1.4.2.2 thorpej
241 1.4.2.2 thorpej #ifdef DEBUG
242 1.4.2.2 thorpej if ((GetCPSR() & PSR_MODE) != PSR_SVC32_MODE)
243 1.4.2.2 thorpej panic("data_abort_handler: not in SVC32 mode");
244 1.4.2.2 thorpej #endif
245 1.4.2.2 thorpej
246 1.4.2.2 thorpej /* Update vmmeter statistics */
247 1.4.2.2 thorpej uvmexp.traps++;
248 1.4.2.2 thorpej
249 1.4.2.2 thorpej /* Extract the fault code from the fault status */
250 1.4.2.2 thorpej fault_code = fault_status & FAULT_TYPE_MASK;
251 1.4.2.2 thorpej
252 1.4.2.2 thorpej /* Get the current lwp structure or lwp0 if there is none */
253 1.4.2.10 nathanw l = curlwp == NULL ? &lwp0 : curlwp;
254 1.4.2.2 thorpej p = l->l_proc;
255 1.4.2.2 thorpej
256 1.4.2.2 thorpej /*
257 1.4.2.2 thorpej * can't use curpcb, as it might be NULL; and we have p in
258 1.4.2.2 thorpej * a register anyway
259 1.4.2.2 thorpej */
260 1.4.2.2 thorpej pcb = &l->l_addr->u_pcb;
261 1.4.2.2 thorpej
262 1.4.2.2 thorpej /* fusubailout is used by [fs]uswintr to avoid page faulting */
263 1.4.2.2 thorpej if (pcb->pcb_onfault
264 1.4.2.2 thorpej && ((fault_code != FAULT_TRANS_S && fault_code != FAULT_TRANS_P &&
265 1.4.2.2 thorpej fault_code != FAULT_PERM_S && fault_code != FAULT_PERM_P)
266 1.4.2.2 thorpej || pcb->pcb_onfault == fusubailout)) {
267 1.4.2.2 thorpej
268 1.4.2.11 nathanw frame->tf_r0 = EFAULT;
269 1.4.2.2 thorpej copyfault:
270 1.4.2.2 thorpej #ifdef DEBUG
271 1.4.2.2 thorpej printf("Using pcb_onfault=%p addr=%08x st=%08x l=%p\n",
272 1.4.2.2 thorpej pcb->pcb_onfault, fault_address, fault_status, l);
273 1.4.2.2 thorpej #endif
274 1.4.2.2 thorpej frame->tf_pc = (u_int)pcb->pcb_onfault;
275 1.4.2.2 thorpej if ((frame->tf_spsr & PSR_MODE) == PSR_USR32_MODE)
276 1.4.2.2 thorpej panic("Yikes pcb_onfault=%p during USR mode fault\n",
277 1.4.2.2 thorpej pcb->pcb_onfault);
278 1.4.2.2 thorpej return;
279 1.4.2.2 thorpej }
280 1.4.2.2 thorpej
281 1.4.2.2 thorpej /* More debug stuff */
282 1.4.2.2 thorpej
283 1.4.2.2 thorpej fault_instruction = ReadWord(fault_pc);
284 1.4.2.2 thorpej
285 1.4.2.2 thorpej #ifdef PMAP_DEBUG
286 1.4.2.2 thorpej if (pmap_debug_level >= 0) {
287 1.4.2.2 thorpej report_abort(NULL, fault_status, fault_address, fault_pc);
288 1.4.2.2 thorpej printf("Instruction @V%08x = %08x\n",
289 1.4.2.2 thorpej fault_pc, fault_instruction);
290 1.4.2.2 thorpej }
291 1.4.2.2 thorpej #endif
292 1.4.2.2 thorpej
293 1.4.2.2 thorpej /* Call the cpu specific abort fixup routine */
294 1.4.2.2 thorpej error = cpu_dataabt_fixup(frame);
295 1.4.2.2 thorpej if (error == ABORT_FIXUP_RETURN)
296 1.4.2.2 thorpej return;
297 1.4.2.2 thorpej if (error == ABORT_FIXUP_FAILED) {
298 1.4.2.6 nathanw printf("pc = 0x%08x, opcode 0x%08x, insn = ", fault_pc, *((u_int *)fault_pc));
299 1.4.2.2 thorpej disassemble(fault_pc);
300 1.4.2.6 nathanw printf("data abort handler: fixup failed for this instruction\n");
301 1.4.2.2 thorpej }
302 1.4.2.2 thorpej
303 1.4.2.2 thorpej #ifdef PMAP_DEBUG
304 1.4.2.2 thorpej if (pmap_debug_level >= 0)
305 1.4.2.2 thorpej printf("fault in process %p\n", p);
306 1.4.2.2 thorpej #endif
307 1.4.2.2 thorpej
308 1.4.2.2 thorpej #ifdef DEBUG
309 1.4.2.2 thorpej /* Is this needed ? */
310 1.4.2.2 thorpej if (pcb != curpcb) {
311 1.4.2.2 thorpej printf("data_abort: Alert ! pcb(%p) != curpcb(%p)\n",
312 1.4.2.2 thorpej pcb, curpcb);
313 1.4.2.10 nathanw printf("data_abort: Alert ! proc(%p), curlwp(%p)\n",
314 1.4.2.10 nathanw p, curlwp);
315 1.4.2.2 thorpej }
316 1.4.2.2 thorpej #endif /* DEBUG */
317 1.4.2.2 thorpej
318 1.4.2.2 thorpej /* Were we in user mode when the abort occurred ? */
319 1.4.2.2 thorpej if ((frame->tf_spsr & PSR_MODE) == PSR_USR32_MODE) {
320 1.4.2.2 thorpej /*
321 1.4.2.2 thorpej * Note that the fault was from USR mode.
322 1.4.2.2 thorpej */
323 1.4.2.2 thorpej user = 1;
324 1.4.2.2 thorpej l->l_addr->u_pcb.pcb_tf = frame;
325 1.4.2.2 thorpej } else
326 1.4.2.2 thorpej user = 0;
327 1.4.2.2 thorpej
328 1.4.2.6 nathanw /* check if this was a failed fixup */
329 1.4.2.6 nathanw if (error == ABORT_FIXUP_FAILED) {
330 1.4.2.6 nathanw if (user) {
331 1.4.2.7 thorpej trapsignal(l, SIGSEGV, TRAP_CODE);
332 1.4.2.7 thorpej userret(l);
333 1.4.2.6 nathanw return;
334 1.4.2.6 nathanw };
335 1.4.2.6 nathanw panic("Data abort fixup failed in kernel - we're dead\n");
336 1.4.2.6 nathanw };
337 1.4.2.6 nathanw
338 1.4.2.2 thorpej /* Now act on the fault type */
339 1.4.2.2 thorpej switch (fault_code) {
340 1.4.2.2 thorpej case FAULT_WRTBUF_0: /* Write Buffer Fault */
341 1.4.2.2 thorpej case FAULT_WRTBUF_1: /* Write Buffer Fault */
342 1.4.2.2 thorpej /* If this happens forget it no point in continuing */
343 1.4.2.2 thorpej
344 1.4.2.2 thorpej /* FALLTHROUGH */
345 1.4.2.2 thorpej
346 1.4.2.2 thorpej case FAULT_ALIGN_0: /* Alignment Fault */
347 1.4.2.2 thorpej case FAULT_ALIGN_1: /* Alignment Fault */
348 1.4.2.2 thorpej /*
349 1.4.2.2 thorpej * Really this should just kill the process.
350 1.4.2.2 thorpej * Alignment faults are turned off in the kernel
351 1.4.2.2 thorpej * in order to get better performance from shorts with
352 1.4.2.2 thorpej * GCC so an alignment fault means somebody has played
353 1.4.2.2 thorpej * with the control register in the CPU. Might as well
354 1.4.2.2 thorpej * panic as the kernel was not compiled for aligned accesses.
355 1.4.2.2 thorpej */
356 1.4.2.2 thorpej
357 1.4.2.2 thorpej /* FALLTHROUGH */
358 1.4.2.2 thorpej
359 1.4.2.2 thorpej case FAULT_BUSERR_0: /* Bus Error LF Section */
360 1.4.2.2 thorpej case FAULT_BUSERR_1: /* Bus Error Page */
361 1.4.2.2 thorpej case FAULT_BUSERR_2: /* Bus Error Section */
362 1.4.2.2 thorpej case FAULT_BUSERR_3: /* Bus Error Page */
363 1.4.2.2 thorpej /* What will accutally cause a bus error ? */
364 1.4.2.2 thorpej /* Real bus errors are not a process problem but hardware */
365 1.4.2.2 thorpej
366 1.4.2.2 thorpej /* FALLTHROUGH */
367 1.4.2.2 thorpej
368 1.4.2.2 thorpej case FAULT_DOMAIN_S: /* Section Domain Error Fault */
369 1.4.2.2 thorpej case FAULT_DOMAIN_P: /* Page Domain Error Fault*/
370 1.4.2.2 thorpej /*
371 1.4.2.2 thorpej * Right well we dont use domains, everything is
372 1.4.2.2 thorpej * always a client and thus subject to access permissions.
373 1.4.2.2 thorpej * If we get a domain error then we have corrupts PTE's
374 1.4.2.2 thorpej * so we might as well die !
375 1.4.2.2 thorpej * I suppose eventually this should just kill the process
376 1.4.2.2 thorpej * who owns the PTE's but if this happens it implies a
377 1.4.2.2 thorpej * kernel problem.
378 1.4.2.2 thorpej */
379 1.4.2.2 thorpej
380 1.4.2.2 thorpej /* FALLTHROUGH */
381 1.4.2.2 thorpej
382 1.4.2.2 thorpej case FAULT_BUSTRNL1: /* Bus Error Trans L1 Fault */
383 1.4.2.2 thorpej case FAULT_BUSTRNL2: /* Bus Error Trans L2 Fault */
384 1.4.2.2 thorpej /*
385 1.4.2.2 thorpej * These faults imply that the PTE is corrupt.
386 1.4.2.2 thorpej * Likely to be a kernel fault so we had better stop.
387 1.4.2.2 thorpej */
388 1.4.2.2 thorpej
389 1.4.2.2 thorpej /* FALLTHROUGH */
390 1.4.2.2 thorpej
391 1.4.2.2 thorpej default :
392 1.4.2.2 thorpej /* Are there any combinations I have missed ? */
393 1.4.2.2 thorpej report_abort(NULL, fault_status, fault_address, fault_pc);
394 1.4.2.2 thorpej
395 1.4.2.2 thorpej we_re_toast:
396 1.4.2.2 thorpej /*
397 1.4.2.2 thorpej * Were are dead, try and provide some debug
398 1.4.2.2 thorpej * information before dying.
399 1.4.2.2 thorpej */
400 1.4.2.2 thorpej #ifdef DDB
401 1.4.2.2 thorpej printf("Unhandled trap (frame = %p)\n", frame);
402 1.4.2.2 thorpej report_abort(NULL, fault_status, fault_address, fault_pc);
403 1.4.2.2 thorpej kdb_trap(-1, frame);
404 1.4.2.2 thorpej return;
405 1.4.2.2 thorpej #else
406 1.4.2.2 thorpej panic("Unhandled trap (frame = %p)", frame);
407 1.4.2.2 thorpej #endif /* DDB */
408 1.4.2.2 thorpej
409 1.4.2.2 thorpej case FAULT_TRANS_P: /* Page Translation Fault */
410 1.4.2.2 thorpej case FAULT_PERM_P: /* Page Permission Fault */
411 1.4.2.2 thorpej case FAULT_TRANS_S: /* Section Translation Fault */
412 1.4.2.2 thorpej case FAULT_PERM_S: /* Section Permission Fault */
413 1.4.2.2 thorpej /*
414 1.4.2.2 thorpej * Page/section translation/permission fault -- need to fault in
415 1.4.2.2 thorpej * the page and possibly the page table page.
416 1.4.2.2 thorpej */
417 1.4.2.6 nathanw {
418 1.4.2.2 thorpej register vaddr_t va;
419 1.4.2.2 thorpej register struct vmspace *vm = p->p_vmspace;
420 1.4.2.2 thorpej register struct vm_map *map;
421 1.4.2.2 thorpej int rv;
422 1.4.2.2 thorpej vm_prot_t ftype;
423 1.4.2.2 thorpej extern struct vm_map *kernel_map;
424 1.4.2.2 thorpej
425 1.4.2.2 thorpej va = trunc_page((vaddr_t)fault_address);
426 1.4.2.2 thorpej
427 1.4.2.2 thorpej #ifdef PMAP_DEBUG
428 1.4.2.2 thorpej if (pmap_debug_level >= 0)
429 1.4.2.2 thorpej printf("page fault: addr=V%08lx ", va);
430 1.4.2.2 thorpej #endif
431 1.4.2.2 thorpej
432 1.4.2.2 thorpej /*
433 1.4.2.2 thorpej * It is only a kernel address space fault iff:
434 1.4.2.2 thorpej * 1. user == 0 and
435 1.4.2.2 thorpej * 2. pcb_onfault not set or
436 1.4.2.2 thorpej * 3. pcb_onfault set but supervisor space fault
437 1.4.2.2 thorpej * The last can occur during an exec() copyin where the
438 1.4.2.2 thorpej * argument space is lazy-allocated.
439 1.4.2.2 thorpej */
440 1.4.2.2 thorpej if (!user &&
441 1.4.2.2 thorpej (va >= VM_MIN_KERNEL_ADDRESS || va < VM_MIN_ADDRESS)) {
442 1.4.2.2 thorpej /* Was the fault due to the FPE/IPKDB ? */
443 1.4.2.2 thorpej if ((frame->tf_spsr & PSR_MODE) == PSR_UND32_MODE) {
444 1.4.2.2 thorpej report_abort("UND32", fault_status,
445 1.4.2.2 thorpej fault_address, fault_pc);
446 1.4.2.2 thorpej trapsignal(l, SIGSEGV, TRAP_CODE);
447 1.4.2.2 thorpej
448 1.4.2.2 thorpej /*
449 1.4.2.2 thorpej * Force exit via userret()
450 1.4.2.2 thorpej * This is necessary as the FPE is an extension
451 1.4.2.2 thorpej * to userland that actually runs in a
452 1.4.2.2 thorpej * priveledged mode but uses USR mode
453 1.4.2.2 thorpej * permissions for its accesses.
454 1.4.2.2 thorpej */
455 1.4.2.2 thorpej userret(l);
456 1.4.2.2 thorpej return;
457 1.4.2.2 thorpej }
458 1.4.2.2 thorpej map = kernel_map;
459 1.4.2.2 thorpej } else
460 1.4.2.2 thorpej map = &vm->vm_map;
461 1.4.2.2 thorpej
462 1.4.2.2 thorpej #ifdef PMAP_DEBUG
463 1.4.2.2 thorpej if (pmap_debug_level >= 0)
464 1.4.2.2 thorpej printf("vmmap=%p ", map);
465 1.4.2.2 thorpej #endif
466 1.4.2.2 thorpej
467 1.4.2.2 thorpej if (map == NULL)
468 1.4.2.5 nathanw panic("No map for fault address va = 0x%08lx", va);
469 1.4.2.2 thorpej
470 1.4.2.2 thorpej /*
471 1.4.2.2 thorpej * We need to know whether the page should be mapped
472 1.4.2.2 thorpej * as R or R/W. The MMU does not give us the info as
473 1.4.2.2 thorpej * to whether the fault was caused by a read or a write.
474 1.4.2.2 thorpej * This means we need to disassemble the instruction
475 1.4.2.2 thorpej * responsible and determine if it was a read or write
476 1.4.2.2 thorpej * instruction.
477 1.4.2.2 thorpej */
478 1.4.2.2 thorpej /* STR instruction ? */
479 1.4.2.2 thorpej if ((fault_instruction & 0x0c100000) == 0x04000000)
480 1.4.2.5 nathanw ftype = VM_PROT_WRITE;
481 1.4.2.2 thorpej /* STM or CDT instruction ? */
482 1.4.2.2 thorpej else if ((fault_instruction & 0x0a100000) == 0x08000000)
483 1.4.2.5 nathanw ftype = VM_PROT_WRITE;
484 1.4.2.2 thorpej /* STRH, STRSH or STRSB instruction ? */
485 1.4.2.2 thorpej else if ((fault_instruction & 0x0e100090) == 0x00000090)
486 1.4.2.5 nathanw ftype = VM_PROT_WRITE;
487 1.4.2.2 thorpej /* SWP instruction ? */
488 1.4.2.2 thorpej else if ((fault_instruction & 0x0fb00ff0) == 0x01000090)
489 1.4.2.5 nathanw ftype = VM_PROT_READ | VM_PROT_WRITE;
490 1.4.2.2 thorpej else
491 1.4.2.2 thorpej ftype = VM_PROT_READ;
492 1.4.2.2 thorpej
493 1.4.2.2 thorpej #ifdef PMAP_DEBUG
494 1.4.2.2 thorpej if (pmap_debug_level >= 0)
495 1.4.2.2 thorpej printf("fault protection = %d\n", ftype);
496 1.4.2.2 thorpej #endif
497 1.4.2.2 thorpej
498 1.4.2.2 thorpej if ((ftype & VM_PROT_WRITE) ?
499 1.4.2.2 thorpej pmap_modified_emulation(map->pmap, va) :
500 1.4.2.2 thorpej pmap_handled_emulation(map->pmap, va))
501 1.4.2.2 thorpej goto out;
502 1.4.2.2 thorpej
503 1.4.2.2 thorpej if (current_intr_depth > 0) {
504 1.4.2.2 thorpej #ifdef DDB
505 1.4.2.2 thorpej printf("Non-emulated page fault with intr_depth > 0\n");
506 1.4.2.2 thorpej report_abort(NULL, fault_status, fault_address, fault_pc);
507 1.4.2.2 thorpej kdb_trap(-1, frame);
508 1.4.2.2 thorpej return;
509 1.4.2.2 thorpej #else
510 1.4.2.2 thorpej panic("Fault with intr_depth > 0");
511 1.4.2.2 thorpej #endif /* DDB */
512 1.4.2.2 thorpej }
513 1.4.2.2 thorpej
514 1.4.2.2 thorpej onfault = pcb->pcb_onfault;
515 1.4.2.2 thorpej pcb->pcb_onfault = NULL;
516 1.4.2.2 thorpej rv = uvm_fault(map, va, 0, ftype);
517 1.4.2.2 thorpej pcb->pcb_onfault = onfault;
518 1.4.2.2 thorpej if (rv == 0)
519 1.4.2.2 thorpej goto out;
520 1.4.2.2 thorpej
521 1.4.2.2 thorpej if (user == 0) {
522 1.4.2.11 nathanw if (pcb->pcb_onfault) {
523 1.4.2.11 nathanw frame->tf_r0 = rv;
524 1.4.2.2 thorpej goto copyfault;
525 1.4.2.11 nathanw }
526 1.4.2.2 thorpej printf("[u]vm_fault(%p, %lx, %x, 0) -> %x\n",
527 1.4.2.2 thorpej map, va, ftype, rv);
528 1.4.2.2 thorpej goto we_re_toast;
529 1.4.2.2 thorpej }
530 1.4.2.2 thorpej
531 1.4.2.2 thorpej report_abort("", fault_status, fault_address, fault_pc);
532 1.4.2.2 thorpej if (rv == ENOMEM) {
533 1.4.2.2 thorpej printf("UVM: pid %d (%s), uid %d killed: "
534 1.4.2.2 thorpej "out of swap\n", p->p_pid, p->p_comm,
535 1.4.2.2 thorpej p->p_cred && p->p_ucred ?
536 1.4.2.2 thorpej p->p_ucred->cr_uid : -1);
537 1.4.2.2 thorpej trapsignal(l, SIGKILL, TRAP_CODE);
538 1.4.2.2 thorpej } else
539 1.4.2.2 thorpej trapsignal(l, SIGSEGV, TRAP_CODE);
540 1.4.2.2 thorpej break;
541 1.4.2.6 nathanw }
542 1.4.2.2 thorpej }
543 1.4.2.2 thorpej
544 1.4.2.6 nathanw out:
545 1.4.2.2 thorpej /* Call userret() if it was a USR mode fault */
546 1.4.2.2 thorpej if (user)
547 1.4.2.2 thorpej userret(l);
548 1.4.2.2 thorpej }
549 1.4.2.2 thorpej
550 1.4.2.2 thorpej
551 1.4.2.2 thorpej /*
552 1.4.2.2 thorpej * void prefetch_abort_handler(trapframe_t *frame)
553 1.4.2.2 thorpej *
554 1.4.2.2 thorpej * Abort handler called when instruction execution occurs at
555 1.4.2.2 thorpej * a non existent or restricted (access permissions) memory page.
556 1.4.2.2 thorpej * If the address is invalid and we were in SVC mode then panic as
557 1.4.2.2 thorpej * the kernel should never prefetch abort.
558 1.4.2.2 thorpej * If the address is invalid and the page is mapped then the user process
559 1.4.2.2 thorpej * does no have read permission so send it a signal.
560 1.4.2.2 thorpej * Otherwise fault the page in and try again.
561 1.4.2.2 thorpej */
562 1.4.2.2 thorpej
563 1.4.2.2 thorpej extern int kernel_debug;
564 1.4.2.2 thorpej
565 1.4.2.2 thorpej void
566 1.4.2.2 thorpej prefetch_abort_handler(frame)
567 1.4.2.2 thorpej trapframe_t *frame;
568 1.4.2.2 thorpej {
569 1.4.2.2 thorpej struct lwp *l;
570 1.4.2.2 thorpej struct proc *p;
571 1.4.2.6 nathanw struct vm_map *map;
572 1.4.2.6 nathanw vaddr_t fault_pc, va;
573 1.4.2.2 thorpej int error;
574 1.4.2.2 thorpej
575 1.4.2.2 thorpej /*
576 1.4.2.2 thorpej * Enable IRQ's (disabled by the abort) This always comes
577 1.4.2.2 thorpej * from user mode so we know interrupts were not disabled.
578 1.4.2.2 thorpej * But we check anyway.
579 1.4.2.2 thorpej */
580 1.4.2.2 thorpej if (!(frame->tf_spsr & I32_bit))
581 1.4.2.2 thorpej enable_interrupts(I32_bit);
582 1.4.2.2 thorpej
583 1.4.2.2 thorpej #ifdef DEBUG
584 1.4.2.2 thorpej if ((GetCPSR() & PSR_MODE) != PSR_SVC32_MODE)
585 1.4.2.2 thorpej panic("prefetch_abort_handler: not in SVC32 mode");
586 1.4.2.2 thorpej #endif
587 1.4.2.2 thorpej
588 1.4.2.2 thorpej /* Update vmmeter statistics */
589 1.4.2.2 thorpej uvmexp.traps++;
590 1.4.2.2 thorpej
591 1.4.2.2 thorpej /* Call the cpu specific abort fixup routine */
592 1.4.2.2 thorpej error = cpu_prefetchabt_fixup(frame);
593 1.4.2.2 thorpej if (error == ABORT_FIXUP_RETURN)
594 1.4.2.2 thorpej return;
595 1.4.2.2 thorpej if (error == ABORT_FIXUP_FAILED)
596 1.4.2.2 thorpej panic("prefetch abort fixup failed\n");
597 1.4.2.2 thorpej
598 1.4.2.2 thorpej /* Get the current proc structure or proc0 if there is none */
599 1.4.2.10 nathanw if ((l = curlwp) == NULL) {
600 1.4.2.2 thorpej l = &lwp0;
601 1.4.2.2 thorpej #ifdef DEBUG
602 1.4.2.10 nathanw printf("Prefetch abort with curlwp == 0\n");
603 1.4.2.2 thorpej #endif
604 1.4.2.2 thorpej }
605 1.4.2.2 thorpej p = l->l_proc;
606 1.4.2.2 thorpej
607 1.4.2.2 thorpej #ifdef PMAP_DEBUG
608 1.4.2.2 thorpej if (pmap_debug_level >= 0)
609 1.4.2.2 thorpej printf("prefetch fault in process %p %s\n", p, p->p_comm);
610 1.4.2.2 thorpej #endif
611 1.4.2.2 thorpej
612 1.4.2.2 thorpej /* Get fault address */
613 1.4.2.2 thorpej fault_pc = frame->tf_pc;
614 1.4.2.6 nathanw va = trunc_page(fault_pc);
615 1.4.2.2 thorpej
616 1.4.2.2 thorpej /* Was the prefectch abort from USR32 mode ? */
617 1.4.2.2 thorpej if ((frame->tf_spsr & PSR_MODE) == PSR_USR32_MODE) {
618 1.4.2.2 thorpej l->l_addr->u_pcb.pcb_tf = frame;
619 1.4.2.2 thorpej } else {
620 1.4.2.2 thorpej /*
621 1.4.2.2 thorpej * All the kernel code pages are loaded at boot time
622 1.4.2.2 thorpej * and do not get paged
623 1.4.2.2 thorpej */
624 1.4.2.6 nathanw panic("Prefetch abort in non-USR mode (frame=%p PC=0x%08lx)\n",
625 1.4.2.2 thorpej frame, fault_pc);
626 1.4.2.2 thorpej }
627 1.4.2.2 thorpej
628 1.4.2.6 nathanw map = &p->p_vmspace->vm_map;
629 1.4.2.6 nathanw
630 1.4.2.2 thorpej #ifdef PMAP_DEBUG
631 1.4.2.2 thorpej if (pmap_debug_level >= 0)
632 1.4.2.8 nathanw printf("prefetch_abort: PC = %08lx\n", fault_pc);
633 1.4.2.2 thorpej #endif
634 1.4.2.2 thorpej /* Ok validate the address, can only execute in USER space */
635 1.4.2.2 thorpej if (fault_pc < VM_MIN_ADDRESS || fault_pc >= VM_MAXUSER_ADDRESS) {
636 1.4.2.2 thorpej #ifdef DEBUG
637 1.4.2.9 nathanw printf("prefetch: pc (%08lx) not in user process space\n",
638 1.4.2.2 thorpej fault_pc);
639 1.4.2.2 thorpej #endif
640 1.4.2.2 thorpej trapsignal(l, SIGSEGV, fault_pc);
641 1.4.2.2 thorpej userret(l);
642 1.4.2.2 thorpej return;
643 1.4.2.2 thorpej }
644 1.4.2.2 thorpej
645 1.4.2.6 nathanw #ifdef CPU_SA110
646 1.4.2.6 nathanw /*
647 1.4.2.6 nathanw * There are bugs in the rev K SA110. This is a check for one
648 1.4.2.6 nathanw * of them.
649 1.4.2.6 nathanw */
650 1.4.2.6 nathanw if (curcpu()->ci_cputype == CPU_ID_SA110 && curcpu()->ci_cpurev < 3) {
651 1.4.2.6 nathanw /* Always current pmap */
652 1.4.2.6 nathanw pt_entry_t *pte = vtopte((vaddr_t) fault_pc);
653 1.4.2.6 nathanw struct pmap *pmap = p->p_vmspace->vm_map.pmap;
654 1.4.2.6 nathanw
655 1.4.2.6 nathanw if (pmap_pde_v(pmap_pde(pmap, (vaddr_t) fault_pc)) &&
656 1.4.2.6 nathanw pmap_pte_v(pte)) {
657 1.4.2.6 nathanw if (kernel_debug & 1) {
658 1.4.2.6 nathanw printf("prefetch_abort: page is already "
659 1.4.2.6 nathanw "mapped - pte=%p *pte=%08x\n", pte, *pte);
660 1.4.2.6 nathanw printf("prefetch_abort: pc=%08lx proc=%p "
661 1.4.2.6 nathanw "process=%s\n", fault_pc, p, p->p_comm);
662 1.4.2.6 nathanw printf("prefetch_abort: far=%08x fs=%x\n",
663 1.4.2.6 nathanw cpu_faultaddress(), cpu_faultstatus());
664 1.4.2.6 nathanw printf("prefetch_abort: trapframe=%08x\n",
665 1.4.2.6 nathanw (u_int)frame);
666 1.4.2.6 nathanw }
667 1.4.2.2 thorpej #ifdef DDB
668 1.4.2.6 nathanw if (kernel_debug & 2)
669 1.4.2.6 nathanw Debugger();
670 1.4.2.2 thorpej #endif
671 1.4.2.8 nathanw }
672 1.4.2.2 thorpej }
673 1.4.2.6 nathanw #endif /* CPU_SA110 */
674 1.4.2.2 thorpej
675 1.4.2.6 nathanw if (pmap_handled_emulation(map->pmap, va))
676 1.4.2.6 nathanw goto out;
677 1.4.2.2 thorpej
678 1.4.2.6 nathanw if (current_intr_depth > 0) {
679 1.4.2.6 nathanw #ifdef DDB
680 1.4.2.6 nathanw printf("Non-emulated prefetch abort with intr_depth > 0\n");
681 1.4.2.6 nathanw kdb_trap(-1, frame);
682 1.4.2.6 nathanw return;
683 1.4.2.6 nathanw #else
684 1.4.2.6 nathanw panic("Prefetch Abort with intr_depth > 0");
685 1.4.2.6 nathanw #endif
686 1.4.2.2 thorpej }
687 1.4.2.2 thorpej
688 1.4.2.6 nathanw error = uvm_fault(map, va, 0, VM_PROT_READ);
689 1.4.2.6 nathanw if (error == 0)
690 1.4.2.6 nathanw goto out;
691 1.4.2.6 nathanw
692 1.4.2.6 nathanw if (error == ENOMEM) {
693 1.4.2.6 nathanw printf("UVM: pid %d (%s), uid %d killed: "
694 1.4.2.6 nathanw "out of swap\n", p->p_pid, p->p_comm,
695 1.4.2.6 nathanw p->p_cred && p->p_ucred ?
696 1.4.2.6 nathanw p->p_ucred->cr_uid : -1);
697 1.4.2.6 nathanw trapsignal(l, SIGKILL, fault_pc);
698 1.4.2.6 nathanw } else
699 1.4.2.6 nathanw trapsignal(l, SIGSEGV, fault_pc);
700 1.4.2.6 nathanw out:
701 1.4.2.2 thorpej userret(l);
702 1.4.2.2 thorpej }
703 1.4.2.2 thorpej
704 1.4.2.2 thorpej int
705 1.4.2.2 thorpej cowfault(va)
706 1.4.2.2 thorpej vaddr_t va;
707 1.4.2.2 thorpej {
708 1.4.2.2 thorpej struct vmspace *vm;
709 1.4.2.2 thorpej int error;
710 1.4.2.2 thorpej
711 1.4.2.2 thorpej if (va >= VM_MAXUSER_ADDRESS)
712 1.4.2.2 thorpej return (EFAULT);
713 1.4.2.2 thorpej
714 1.4.2.2 thorpej /* uvm_fault can't be called from within an interrupt */
715 1.4.2.2 thorpej KASSERT(current_intr_depth == 0);
716 1.4.2.2 thorpej
717 1.4.2.10 nathanw vm = curproc->p_vmspace;
718 1.4.2.5 nathanw error = uvm_fault(&vm->vm_map, va, 0, VM_PROT_WRITE);
719 1.4.2.2 thorpej return error;
720 1.4.2.2 thorpej }
721