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