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