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