1 /* $NetBSD: fault.c,v 1.1 2001/07/28 13:28:03 chris 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/irqhandler.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