1 /* $NetBSD: trap.c,v 1.14 2012/02/19 21:06:22 rmind Exp $ */ 2 /*- 3 * Copyright (c) 2010, 2011 The NetBSD Foundation, Inc. 4 * All rights reserved. 5 * 6 * This code is derived from software contributed to The NetBSD Foundation 7 * by Raytheon BBN Technologies Corp and Defense Advanced Research Projects 8 * Agency and which was developed by Matt Thomas of 3am Software Foundry. 9 * 10 * This material is based upon work supported by the Defense Advanced Research 11 * Projects Agency and Space and Naval Warfare Systems Center, Pacific, under 12 * Contract No. N66001-09-C-2073. 13 * Approved for Public Release, Distribution Unlimited 14 * 15 * Redistribution and use in source and binary forms, with or without 16 * modification, are permitted provided that the following conditions 17 * are met: 18 * 1. Redistributions of source code must retain the above copyright 19 * notice, this list of conditions and the following disclaimer. 20 * 2. Redistributions in binary form must reproduce the above copyright 21 * notice, this list of conditions and the following disclaimer in the 22 * documentation and/or other materials provided with the distribution. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 25 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 26 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 27 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 28 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 29 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 30 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 31 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 32 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 33 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 34 * POSSIBILITY OF SUCH DAMAGE. 35 */ 36 37 #include "opt_ddb.h" 38 39 #include <sys/cdefs.h> 40 41 __KERNEL_RCSID(1, "$NetBSD: trap.c,v 1.14 2012/02/19 21:06:22 rmind Exp $"); 42 43 #include <sys/param.h> 44 #include <sys/systm.h> 45 #include <sys/siginfo.h> 46 #include <sys/lwp.h> 47 #include <sys/proc.h> 48 #include <sys/cpu.h> 49 #include <sys/kauth.h> 50 #include <sys/ras.h> 51 52 #include <uvm/uvm_extern.h> 53 54 #include <powerpc/pcb.h> 55 #include <powerpc/userret.h> 56 #include <powerpc/psl.h> 57 #include <powerpc/instr.h> 58 #include <powerpc/altivec.h> /* use same interface for SPE */ 59 60 #include <powerpc/spr.h> 61 #include <powerpc/booke/spr.h> 62 #include <powerpc/booke/cpuvar.h> 63 64 #include <powerpc/db_machdep.h> 65 #include <ddb/db_interface.h> 66 67 #include <powerpc/trap.h> 68 #include <powerpc/booke/trap.h> 69 #include <powerpc/booke/pte.h> 70 71 void trap(enum ppc_booke_exceptions, struct trapframe *); 72 static void dump_trapframe(const struct trapframe *); 73 74 static const char trap_names[][8] = { 75 [T_CRITIAL_INPUT] = "CRIT", 76 [T_EXTERNAL_INPUT] = "EXT", 77 [T_DECREMENTER] = "DECR", 78 [T_FIXED_INTERVAL] = "FIT", 79 [T_WATCHDOG] = "WDOG", 80 [T_SYSTEM_CALL] = "SC", 81 [T_MACHINE_CHECK] = "MCHK", 82 [T_DSI] = "DSI", 83 [T_ISI] = "ISI", 84 [T_ALIGNMENT] = "ALN", 85 [T_PROGRAM] = "PGM", 86 [T_FP_UNAVAILABLE] = "FP", 87 [T_AP_UNAVAILABLE] = "AP", 88 [T_DATA_TLB_ERROR] = "DTLB", 89 [T_INSTRUCTION_TLB_ERROR] = "ITLB", 90 [T_DEBUG] = "DEBUG", 91 [T_SPE_UNAVAILABLE] = "SPE", 92 [T_EMBEDDED_FP_DATA] = "FPDATA", 93 [T_EMBEDDED_FP_ROUND] = "FPROUND", 94 [T_EMBEDDED_PERF_MONITOR] = "PERFMON", 95 [T_AST] = "AST", 96 }; 97 98 static inline bool 99 usertrap_p(struct trapframe *tf) 100 { 101 return (tf->tf_srr1 & PSL_PR) != 0; 102 } 103 104 static int 105 mchk_exception(struct trapframe *tf, ksiginfo_t *ksi) 106 { 107 const bool usertrap = usertrap_p(tf); 108 const vaddr_t faultva = tf->tf_mcar; 109 struct cpu_info * const ci = curcpu(); 110 int rv = EFAULT; 111 112 if (usertrap) 113 ci->ci_ev_umchk.ev_count++; 114 115 if (rv != 0 && usertrap) { 116 KSI_INIT_TRAP(ksi); 117 ksi->ksi_signo = SIGSEGV; 118 ksi->ksi_trap = EXC_DSI; 119 ksi->ksi_code = SEGV_ACCERR; 120 ksi->ksi_addr = (void *)faultva; 121 } 122 123 return rv; 124 } 125 126 static inline vm_prot_t 127 get_faulttype(const struct trapframe * const tf) 128 { 129 return VM_PROT_READ | (tf->tf_esr & ESR_ST ? VM_PROT_WRITE : 0); 130 } 131 132 static inline struct vm_map * 133 get_faultmap(const struct trapframe * const tf, register_t psl_mask) 134 { 135 return (tf->tf_srr1 & psl_mask) 136 ? &curlwp->l_proc->p_vmspace->vm_map 137 : kernel_map; 138 } 139 140 /* 141 * We could use pmap_pte_lookip but this slightly faster since we already 142 * the segtab pointers in cpu_info. 143 */ 144 static inline pt_entry_t * 145 trap_pte_lookup(struct trapframe *tf, vaddr_t va, register_t psl_mask) 146 { 147 struct pmap_segtab ** const stps = &curcpu()->ci_pmap_kern_segtab; 148 struct pmap_segtab * const stp = stps[(tf->tf_srr1 / psl_mask) & 1]; 149 if (__predict_false(stp == NULL)) 150 return NULL; 151 pt_entry_t *ptep = stp->seg_tab[va >> SEGSHIFT]; 152 if (__predict_false(ptep == NULL)) 153 return NULL; 154 return ptep + ((va & SEGOFSET) >> PAGE_SHIFT); 155 } 156 157 static int 158 pagefault(struct vm_map *map, vaddr_t va, vm_prot_t ftype, bool usertrap) 159 { 160 struct lwp * const l = curlwp; 161 int rv; 162 163 // printf("%s(%p,%#lx,%u,%u)\n", __func__, map, va, ftype, usertrap); 164 165 if (usertrap) { 166 rv = uvm_fault(map, trunc_page(va), ftype); 167 if (rv == 0) 168 uvm_grow(l->l_proc, trunc_page(va)); 169 if (rv == EACCES) 170 rv = EFAULT; 171 } else { 172 if (cpu_intr_p()) 173 return EFAULT; 174 175 struct pcb * const pcb = lwp_getpcb(l); 176 struct faultbuf * const fb = pcb->pcb_onfault; 177 pcb->pcb_onfault = NULL; 178 rv = uvm_fault(map, trunc_page(va), ftype); 179 pcb->pcb_onfault = fb; 180 if (map != kernel_map) { 181 if (rv == 0) 182 uvm_grow(l->l_proc, trunc_page(va)); 183 } 184 if (rv == EACCES) 185 rv = EFAULT; 186 } 187 return rv; 188 } 189 190 static int 191 dsi_exception(struct trapframe *tf, ksiginfo_t *ksi) 192 { 193 const vaddr_t faultva = tf->tf_dear; 194 const vm_prot_t ftype = get_faulttype(tf); 195 struct vm_map * const faultmap = get_faultmap(tf, PSL_DS); 196 const bool usertrap = usertrap_p(tf); 197 198 kpreempt_disable(); 199 struct cpu_info * const ci = curcpu(); 200 201 if (usertrap) 202 ci->ci_ev_udsi.ev_count++; 203 else 204 ci->ci_ev_kdsi.ev_count++; 205 206 /* 207 * If we had a TLB entry (which we must have had to get this exception), 208 * we certainly have a PTE. 209 */ 210 pt_entry_t * const ptep = trap_pte_lookup(tf, trunc_page(faultva), 211 PSL_DS); 212 KASSERT(ptep != NULL); 213 pt_entry_t pte = *ptep; 214 215 if ((ftype & VM_PROT_WRITE) 216 && ((pte & (PTE_xW|PTE_UNMODIFIED)) == (PTE_xW|PTE_UNMODIFIED))) { 217 const paddr_t pa = pte_to_paddr(pte); 218 struct vm_page * const pg = PHYS_TO_VM_PAGE(pa); 219 KASSERT(pg); 220 struct vm_page_md * const mdpg = VM_PAGE_TO_MD(pg); 221 222 if (!VM_PAGEMD_MODIFIED_P(mdpg)) { 223 pmap_page_set_attributes(mdpg, VM_PAGEMD_MODIFIED); 224 } 225 pte &= ~PTE_UNMODIFIED; 226 *ptep = pte; 227 pmap_tlb_update_addr(faultmap->pmap, trunc_page(faultva), 228 pte, 0); 229 kpreempt_enable(); 230 return 0; 231 } 232 kpreempt_enable(); 233 234 int rv = pagefault(faultmap, faultva, ftype, usertrap); 235 236 /* 237 * We can't get a MAPERR here since that's a different exception. 238 */ 239 if (__predict_false(rv != 0 && usertrap)) { 240 ci->ci_ev_udsi_fatal.ev_count++; 241 KSI_INIT_TRAP(ksi); 242 ksi->ksi_signo = SIGSEGV; 243 ksi->ksi_trap = EXC_DSI; 244 ksi->ksi_code = SEGV_ACCERR; 245 ksi->ksi_addr = (void *)faultva; 246 } 247 return rv; 248 } 249 250 static int 251 isi_exception(struct trapframe *tf, ksiginfo_t *ksi) 252 { 253 const vaddr_t faultva = trunc_page(tf->tf_srr0); 254 struct vm_map * const faultmap = get_faultmap(tf, PSL_IS); 255 const bool usertrap = usertrap_p(tf); 256 257 kpreempt_disable(); 258 struct cpu_info * const ci = curcpu(); 259 260 if (usertrap) 261 ci->ci_ev_isi.ev_count++; 262 else 263 ci->ci_ev_kisi.ev_count++; 264 265 /* 266 * If we had a TLB entry (which we must have had to get this exception), 267 * we certainly have a PTE. 268 */ 269 pt_entry_t * const ptep = trap_pte_lookup(tf, trunc_page(faultva), 270 PSL_IS); 271 if (ptep == NULL) 272 dump_trapframe(tf); 273 KASSERT(ptep != NULL); 274 pt_entry_t pte = *ptep; 275 276 UVMHIST_FUNC(__func__); UVMHIST_CALLED(pmapexechist); 277 278 if ((pte & PTE_UNSYNCED) == PTE_UNSYNCED) { 279 const paddr_t pa = pte_to_paddr(pte); 280 struct vm_page * const pg = PHYS_TO_VM_PAGE(pa); 281 KASSERT(pg); 282 struct vm_page_md * const mdpg = VM_PAGE_TO_MD(pg); 283 284 UVMHIST_LOG(pmapexechist, 285 "srr0=%#x pg=%p (pa %#"PRIxPADDR"): %s", 286 tf->tf_srr0, pg, pa, 287 (VM_PAGEMD_EXECPAGE_P(mdpg) 288 ? "no syncicache (already execpage)" 289 : "performed syncicache (now execpage)")); 290 291 if (!VM_PAGEMD_EXECPAGE_P(mdpg)) { 292 ci->ci_softc->cpu_ev_exec_trap_sync.ev_count++; 293 dcache_wb_page(pa); 294 icache_inv_page(pa); 295 pmap_page_set_attributes(mdpg, VM_PAGEMD_EXECPAGE); 296 } 297 pte &= ~PTE_UNSYNCED; 298 pte |= PTE_xX; 299 *ptep = pte; 300 301 pmap_tlb_update_addr(faultmap->pmap, trunc_page(faultva), 302 pte, 0); 303 kpreempt_enable(); 304 UVMHIST_LOG(pmapexechist, "<- 0", 0,0,0,0); 305 return 0; 306 } 307 kpreempt_enable(); 308 309 int rv = pagefault(faultmap, faultva, VM_PROT_READ|VM_PROT_EXECUTE, 310 usertrap); 311 312 if (__predict_false(rv != 0 && usertrap)) { 313 /* 314 * We can't get a MAPERR here since 315 * that's a different exception. 316 */ 317 ci->ci_ev_isi_fatal.ev_count++; 318 KSI_INIT_TRAP(ksi); 319 ksi->ksi_signo = SIGSEGV; 320 ksi->ksi_trap = EXC_ISI; 321 ksi->ksi_code = SEGV_ACCERR; 322 ksi->ksi_addr = (void *)tf->tf_srr0; /* not truncated */ 323 } 324 UVMHIST_LOG(pmapexechist, "<- %d", rv, 0,0,0); 325 return rv; 326 } 327 328 static int 329 dtlb_exception(struct trapframe *tf, ksiginfo_t *ksi) 330 { 331 const vaddr_t faultva = tf->tf_dear; 332 const vm_prot_t ftype = get_faulttype(tf); 333 struct vm_map * const faultmap = get_faultmap(tf, PSL_DS); 334 struct cpu_info * const ci = curcpu(); 335 const bool usertrap = usertrap_p(tf); 336 337 #if 0 338 /* 339 * This is what pte_load in trap_subr.S does for us. 340 */ 341 const pt_entry_t * const ptep = 342 trap_pte_lookup(tf, trunc_page(faultva), PSL_DS); 343 if (ptep != NULL && !usertrap && pte_valid_p(*ptep)) { 344 tlb_update_addr(trunc_page(faultva), KERNEL_PID, *ptep, true); 345 ci->ci_ev_tlbmiss_soft.ev_count++; 346 return 0; 347 } 348 #endif 349 350 ci->ci_ev_dtlbmiss_hard.ev_count++; 351 352 // printf("pagefault(%p,%#lx,%u,%u)", faultmap, faultva, ftype, usertrap); 353 int rv = pagefault(faultmap, faultva, ftype, usertrap); 354 // printf(": %d\n", rv); 355 356 if (__predict_false(rv != 0 && usertrap)) { 357 ci->ci_ev_udsi_fatal.ev_count++; 358 KSI_INIT_TRAP(ksi); 359 ksi->ksi_signo = SIGSEGV; 360 ksi->ksi_trap = EXC_DSI; 361 ksi->ksi_code = (rv == EACCES ? SEGV_ACCERR : SEGV_MAPERR); 362 ksi->ksi_addr = (void *)faultva; 363 } 364 return rv; 365 } 366 367 static int 368 itlb_exception(struct trapframe *tf, ksiginfo_t *ksi) 369 { 370 struct vm_map * const faultmap = get_faultmap(tf, PSL_IS); 371 const vaddr_t faultva = tf->tf_srr0; 372 struct cpu_info * const ci = curcpu(); 373 const bool usertrap = usertrap_p(tf); 374 375 ci->ci_ev_itlbmiss_hard.ev_count++; 376 377 int rv = pagefault(faultmap, faultva, VM_PROT_READ|VM_PROT_EXECUTE, 378 usertrap); 379 380 if (__predict_false(rv != 0 && usertrap)) { 381 ci->ci_ev_isi_fatal.ev_count++; 382 KSI_INIT_TRAP(ksi); 383 ksi->ksi_signo = SIGSEGV; 384 ksi->ksi_trap = EXC_ISI; 385 ksi->ksi_code = (rv == EACCES ? SEGV_ACCERR : SEGV_MAPERR); 386 ksi->ksi_addr = (void *)tf->tf_srr0; 387 } 388 return rv; 389 } 390 391 static int 392 spe_exception(struct trapframe *tf, ksiginfo_t *ksi) 393 { 394 struct cpu_info * const ci = curcpu(); 395 396 if (!usertrap_p(tf)) 397 return EPERM; 398 399 ci->ci_ev_vec.ev_count++; 400 401 #ifdef PPC_HAVE_SPE 402 vec_load(); 403 return 0; 404 #else 405 KSI_INIT_TRAP(ksi); 406 ksi->ksi_signo = SIGILL; 407 ksi->ksi_trap = EXC_PGM; 408 ksi->ksi_code = ILL_ILLOPC; 409 ksi->ksi_addr = (void *)tf->tf_srr0; 410 return EPERM; 411 #endif 412 } 413 414 static bool 415 emulate_opcode(struct trapframe *tf, ksiginfo_t *ksi) 416 { 417 uint32_t opcode; 418 if (copyin((void *)tf->tf_srr0, &opcode, sizeof(opcode)) != 0) 419 return false; 420 421 if (opcode == OPC_LWSYNC) 422 return true; 423 424 if (OPC_MFSPR_P(opcode, SPR_PVR)) { 425 __asm ("mfpvr %0" : "=r"(tf->tf_fixreg[OPC_MFSPR_REG(opcode)])); 426 return true; 427 } 428 429 /* 430 * If we bothered to emulate FP, we would try to do so here. 431 */ 432 return false; 433 } 434 435 static int 436 pgm_exception(struct trapframe *tf, ksiginfo_t *ksi) 437 { 438 struct cpu_info * const ci = curcpu(); 439 int rv = EPERM; 440 441 if (!usertrap_p(tf)) 442 return rv; 443 444 UVMHIST_FUNC(__func__); UVMHIST_CALLED(pmapexechist); 445 446 UVMHIST_LOG(pmapexechist, " srr0/1=%#x/%#x esr=%#x pte=%#x", 447 tf->tf_srr0, tf->tf_srr1, tf->tf_esr, 448 *trap_pte_lookup(tf, trunc_page(tf->tf_srr0), PSL_IS)); 449 450 ci->ci_ev_pgm.ev_count++; 451 452 if (tf->tf_esr & ESR_PTR) { 453 struct proc *p = curlwp->l_proc; 454 if (p->p_raslist != NULL 455 && ras_lookup(p, (void *)tf->tf_srr0) != (void *) -1) { 456 tf->tf_srr0 += 4; 457 return 0; 458 } 459 } 460 461 if (tf->tf_esr & (ESR_PIL|ESR_PPR)) { 462 if (emulate_opcode(tf, ksi)) { 463 tf->tf_srr0 += 4; 464 return 0; 465 } 466 } 467 468 KSI_INIT_TRAP(ksi); 469 ksi->ksi_signo = SIGILL; 470 ksi->ksi_trap = EXC_PGM; 471 if (tf->tf_esr & ESR_PIL) { 472 ksi->ksi_code = ILL_ILLOPC; 473 } else if (tf->tf_esr & ESR_PPR) { 474 ksi->ksi_code = ILL_PRVOPC; 475 } else if (tf->tf_esr & ESR_PTR) { 476 ksi->ksi_signo = SIGTRAP; 477 ksi->ksi_code = TRAP_BRKPT; 478 } else { 479 ksi->ksi_code = 0; 480 } 481 ksi->ksi_addr = (void *)tf->tf_srr0; 482 return rv; 483 } 484 485 static int 486 debug_exception(struct trapframe *tf, ksiginfo_t *ksi) 487 { 488 struct cpu_info * const ci = curcpu(); 489 int rv = EPERM; 490 491 if (!usertrap_p(tf)) 492 return rv; 493 494 ci->ci_ev_debug.ev_count++; 495 496 /* 497 * Ack the interrupt. 498 */ 499 mtspr(SPR_DBSR, tf->tf_esr); 500 KASSERT(tf->tf_esr & (DBSR_IAC1|DBSR_IAC2)); 501 KASSERT((tf->tf_srr1 & PSL_SE) == 0); 502 503 /* 504 * Disable debug events 505 */ 506 mtspr(SPR_DBCR1, 0); 507 mtspr(SPR_DBCR0, 0); 508 509 /* 510 * Tell the debugger ... 511 */ 512 KSI_INIT_TRAP(ksi); 513 ksi->ksi_signo = SIGTRAP; 514 ksi->ksi_trap = EXC_TRC; 515 ksi->ksi_addr = (void *)tf->tf_srr0; 516 ksi->ksi_code = TRAP_TRACE; 517 return rv; 518 } 519 520 static int 521 ali_exception(struct trapframe *tf, ksiginfo_t *ksi) 522 { 523 struct cpu_info * const ci = curcpu(); 524 int rv = EFAULT; 525 526 ci->ci_ev_ali.ev_count++; 527 528 if (rv != 0 && usertrap_p(tf)) { 529 ci->ci_ev_ali_fatal.ev_count++; 530 KSI_INIT_TRAP(ksi); 531 ksi->ksi_signo = SIGILL; 532 ksi->ksi_trap = EXC_PGM; 533 if (tf->tf_esr & ESR_PIL) 534 ksi->ksi_code = ILL_ILLOPC; 535 else if (tf->tf_esr & ESR_PPR) 536 ksi->ksi_code = ILL_PRVOPC; 537 else if (tf->tf_esr & ESR_PTR) 538 ksi->ksi_code = ILL_ILLTRP; 539 else 540 ksi->ksi_code = 0; 541 ksi->ksi_addr = (void *)tf->tf_srr0; 542 } 543 return rv; 544 } 545 546 static int 547 embedded_fp_data_exception(struct trapframe *tf, ksiginfo_t *ksi) 548 { 549 struct cpu_info * const ci = curcpu(); 550 int rv = EFAULT; 551 552 ci->ci_ev_fpu.ev_count++; 553 554 if (rv != 0 && usertrap_p(tf)) { 555 KSI_INIT_TRAP(ksi); 556 #ifdef PPC_HAVE_SPE 557 ksi->ksi_signo = SIGFPE; 558 ksi->ksi_trap = tf->tf_exc; 559 ksi->ksi_code = vec_siginfo_code(tf); 560 #else 561 ksi->ksi_signo = SIGILL; 562 ksi->ksi_trap = EXC_PGM; 563 ksi->ksi_code = ILL_ILLOPC; 564 #endif 565 ksi->ksi_addr = (void *)tf->tf_srr0; 566 } 567 return rv; 568 } 569 570 static int 571 embedded_fp_round_exception(struct trapframe *tf, ksiginfo_t *ksi) 572 { 573 struct cpu_info * const ci = curcpu(); 574 int rv = EDOM; 575 576 ci->ci_ev_fpu.ev_count++; 577 578 if (rv != 0 && usertrap_p(tf)) { 579 KSI_INIT_TRAP(ksi); 580 #ifdef PPC_HAVE_SPE 581 ksi->ksi_signo = SIGFPE; 582 ksi->ksi_trap = tf->tf_exc; 583 ksi->ksi_code = vec_siginfo_code(tf); 584 #else 585 ksi->ksi_signo = SIGILL; 586 ksi->ksi_trap = EXC_PGM; 587 ksi->ksi_code = ILL_ILLOPC; 588 #endif 589 ksi->ksi_addr = (void *)tf->tf_srr0; 590 } 591 return rv; 592 } 593 594 static void 595 dump_trapframe(const struct trapframe *tf) 596 { 597 printf("trapframe %p (exc=%x srr0/1=%#lx/%#lx esr/dear=%#x/%#lx)\n", 598 tf, tf->tf_exc, tf->tf_srr0, tf->tf_srr1, tf->tf_esr, tf->tf_dear); 599 printf("lr =%08lx ctr=%08lx cr =%08x xer=%08x\n", 600 tf->tf_lr, tf->tf_ctr, tf->tf_cr, tf->tf_xer); 601 for (u_int r = 0; r < 32; r += 4) { 602 printf("r%02u=%08lx r%02u=%08lx r%02u=%08lx r%02u=%08lx\n", 603 r+0, tf->tf_fixreg[r+0], r+1, tf->tf_fixreg[r+1], 604 r+2, tf->tf_fixreg[r+2], r+3, tf->tf_fixreg[r+3]); 605 } 606 } 607 static bool 608 ddb_exception(struct trapframe *tf) 609 { 610 #if 0 611 const register_t ddb_trapfunc = (uintptr_t) cpu_Debugger; 612 if ((tf->tf_esr & ESR_PTR) == 0) 613 return false; 614 if (ddb_trapfunc <= tf->tf_srr0 && tf->tf_srr0 <= ddb_trapfunc+16) { 615 register_t srr0 = tf->tf_srr0; 616 if (kdb_trap(tf->tf_exc, tf)) { 617 if (srr0 == tf->tf_srr0) 618 tf->tf_srr0 += 4; 619 return true; 620 } 621 } 622 return false; 623 #else 624 #if 0 625 struct cpu_info * const ci = curcpu(); 626 struct cpu_softc * const cpu = ci->ci_softc; 627 printf("CPL stack:"); 628 if (ci->ci_idepth >= 0) { 629 for (u_int i = 0; i <= ci->ci_idepth; i++) { 630 printf(" [%u]=%u", i, cpu->cpu_pcpls[i]); 631 } 632 } 633 printf(" %u\n", ci->ci_cpl); 634 dump_trapframe(tf); 635 #endif 636 if (kdb_trap(tf->tf_exc, tf)) { 637 tf->tf_srr0 += 4; 638 return true; 639 } 640 return false; 641 #endif 642 } 643 644 static bool 645 onfaulted(struct trapframe *tf, register_t rv) 646 { 647 struct lwp * const l = curlwp; 648 struct pcb * const pcb = lwp_getpcb(l); 649 struct faultbuf * const fb = pcb->pcb_onfault; 650 if (fb == NULL) 651 return false; 652 tf->tf_srr0 = fb->fb_pc; 653 tf->tf_srr1 = fb->fb_msr; 654 tf->tf_cr = fb->fb_cr; 655 tf->tf_fixreg[1] = fb->fb_sp; 656 tf->tf_fixreg[2] = fb->fb_r2; 657 tf->tf_fixreg[3] = rv; 658 pcb->pcb_onfault = NULL; 659 return true; 660 } 661 662 void 663 trap(enum ppc_booke_exceptions trap_code, struct trapframe *tf) 664 { 665 const bool usertrap = usertrap_p(tf); 666 struct cpu_info * const ci = curcpu(); 667 struct lwp * const l = curlwp; 668 struct proc * const p = l->l_proc; 669 ksiginfo_t ksi; 670 int rv = EACCES; 671 672 ci->ci_ev_traps.ev_count++; 673 ci->ci_data.cpu_ntrap++; 674 675 KASSERTMSG(!usertrap || tf == trapframe(l), 676 "trap: tf=%p is invalid: trapframe(%p)=%p", tf, l, trapframe(l)); 677 678 #if 0 679 if (trap_code != T_PROGRAM || usertrap) 680 printf("trap(enter): %s (tf=%p, esr/dear=%#x/%#lx, srr0/1=%#lx/%#lx, lr=%#lx)\n", 681 trap_names[trap_code], tf, tf->tf_esr, tf->tf_dear, 682 tf->tf_srr0, tf->tf_srr1, tf->tf_lr); 683 #endif 684 #if 0 685 if ((register_t)tf >= (register_t)l->l_addr + USPACE 686 || (register_t)tf < (register_t)l->l_addr + PAGE_SIZE) { 687 printf("%s(entry): pid %d.%d (%s): invalid tf addr %p\n", 688 __func__, p->p_pid, l->l_lid, p->p_comm, tf); 689 dump_trapframe(tf); 690 Debugger(); 691 } 692 #endif 693 #if 0 694 if ((mfmsr() & PSL_CE) == 0) { 695 printf("%s(entry): pid %d.%d (%s): %s: PSL_CE (%#lx) not set\n", 696 __func__, p->p_pid, l->l_lid, p->p_comm, 697 trap_names[trap_code], mfmsr()); 698 dump_trapframe(tf); 699 } 700 #endif 701 702 if (usertrap && (tf->tf_fixreg[1] & 0x80000000)) { 703 printf("%s(entry): pid %d.%d (%s): %s invalid sp %#lx (sprg1=%#lx)\n", 704 __func__, p->p_pid, l->l_lid, p->p_comm, 705 trap_names[trap_code], tf->tf_fixreg[1], mfspr(SPR_SPRG1)); 706 dump_trapframe(tf); 707 Debugger(); 708 } 709 710 if (usertrap && (tf->tf_srr1 & (PSL_DS|PSL_IS)) != (PSL_DS|PSL_IS)) { 711 printf("%s(entry): pid %d.%d (%s): %s invalid PSL %#lx\n", 712 __func__, p->p_pid, l->l_lid, p->p_comm, 713 trap_names[trap_code], tf->tf_srr1); 714 dump_trapframe(tf); 715 Debugger(); 716 } 717 718 switch (trap_code) { 719 case T_CRITIAL_INPUT: 720 case T_EXTERNAL_INPUT: 721 case T_DECREMENTER: 722 case T_FIXED_INTERVAL: 723 case T_WATCHDOG: 724 case T_SYSTEM_CALL: 725 default: 726 panic("trap: unexcepted trap code %d! (tf=%p, srr0/1=%#lx/%#lx)", 727 trap_code, tf, tf->tf_srr0, tf->tf_srr1); 728 case T_MACHINE_CHECK: 729 rv = mchk_exception(tf, &ksi); 730 break; 731 case T_DSI: 732 rv = dsi_exception(tf, &ksi); 733 break; 734 case T_ISI: 735 rv = isi_exception(tf, &ksi); 736 break; 737 case T_ALIGNMENT: 738 rv = ali_exception(tf, &ksi); 739 break; 740 case T_SPE_UNAVAILABLE: 741 rv = spe_exception(tf, &ksi); 742 break; 743 case T_PROGRAM: 744 #ifdef DDB 745 if (!usertrap && ddb_exception(tf)) 746 return; 747 #endif 748 rv = pgm_exception(tf, &ksi); 749 break; 750 case T_FP_UNAVAILABLE: 751 case T_AP_UNAVAILABLE: 752 panic("trap: unexcepted trap code %d! (tf=%p, srr0/1=%#lx/%#lx)", 753 trap_code, tf, tf->tf_srr0, tf->tf_srr1); 754 case T_DATA_TLB_ERROR: 755 rv = dtlb_exception(tf, &ksi); 756 break; 757 case T_INSTRUCTION_TLB_ERROR: 758 rv = itlb_exception(tf, &ksi); 759 break; 760 case T_DEBUG: 761 #ifdef DDB 762 if (!usertrap && ddb_exception(tf)) 763 return; 764 #endif 765 rv = debug_exception(tf, &ksi); 766 break; 767 case T_EMBEDDED_FP_DATA: 768 rv = embedded_fp_data_exception(tf, &ksi); 769 break; 770 case T_EMBEDDED_FP_ROUND: 771 rv = embedded_fp_round_exception(tf, &ksi); 772 break; 773 case T_EMBEDDED_PERF_MONITOR: 774 //db_stack_trace_print(tf->tf_fixreg[1], true, 40, "", printf); 775 dump_trapframe(tf); 776 rv = EPERM; 777 break; 778 case T_AST: 779 KASSERT(usertrap); 780 cpu_ast(l, ci); 781 if (tf->tf_fixreg[1] & 0x80000000) { 782 printf("%s(ast-exit): pid %d.%d (%s): invalid sp %#lx\n", 783 __func__, p->p_pid, l->l_lid, p->p_comm, 784 tf->tf_fixreg[1]); 785 dump_trapframe(tf); 786 Debugger(); 787 } 788 if ((tf->tf_srr1 & (PSL_DS|PSL_IS)) != (PSL_DS|PSL_IS)) { 789 printf("%s(entry): pid %d.%d (%s): %s invalid PSL %#lx\n", 790 __func__, p->p_pid, l->l_lid, p->p_comm, 791 trap_names[trap_code], tf->tf_srr1); 792 dump_trapframe(tf); 793 Debugger(); 794 } 795 #if 0 796 if ((mfmsr() & PSL_CE) == 0) { 797 printf("%s(exit): pid %d.%d (%s): %s: PSL_CE (%#lx) not set\n", 798 __func__, p->p_pid, l->l_lid, p->p_comm, 799 trap_names[trap_code], mfmsr()); 800 dump_trapframe(tf); 801 } 802 #endif 803 userret(l, tf); 804 return; 805 } 806 if (!usertrap) { 807 if (rv != 0) { 808 if (!onfaulted(tf, rv)) { 809 db_stack_trace_print(tf->tf_fixreg[1], true, 40, "", printf); 810 dump_trapframe(tf); 811 panic("%s: pid %d.%d (%s): %s exception in kernel mode" 812 " (tf=%p, dear=%#lx, esr=%#x," 813 " srr0/1=%#lx/%#lx)", 814 __func__, p->p_pid, l->l_lid, p->p_comm, 815 trap_names[trap_code], tf, tf->tf_dear, 816 tf->tf_esr, tf->tf_srr0, tf->tf_srr1); 817 } 818 } 819 #if 0 820 if (tf->tf_fixreg[1] >= (register_t)l->l_addr + USPACE 821 || tf->tf_fixreg[1] < (register_t)l->l_addr + PAGE_SIZE) { 822 printf("%s(exit): pid %d.%d (%s): invalid kern sp %#lx\n", 823 __func__, p->p_pid, l->l_lid, p->p_comm, 824 tf->tf_fixreg[1]); 825 dump_trapframe(tf); 826 Debugger(); 827 } 828 #endif 829 #if 0 830 if ((mfmsr() & PSL_CE) == 0) { 831 printf("%s(exit): pid %d.%d (%s): %s: PSL_CE (%#lx) not set\n", 832 __func__, p->p_pid, l->l_lid, p->p_comm, 833 trap_names[trap_code], mfmsr()); 834 mtmsr(mfmsr()|PSL_CE); 835 dump_trapframe(tf); 836 } 837 #endif 838 } else { 839 if (rv == ENOMEM) { 840 printf("UVM: pid %d.%d (%s), uid %d killed: " 841 "out of swap\n", 842 p->p_pid, l->l_lid, p->p_comm, 843 l->l_cred ? kauth_cred_geteuid(l->l_cred) : -1); 844 ksi.ksi_signo = SIGKILL; 845 } 846 if (rv != 0) { 847 if (cpu_printfataltraps) { 848 printf("%s: pid %d.%d (%s):" 849 " %s exception in user mode\n", 850 __func__, p->p_pid, l->l_lid, p->p_comm, 851 trap_names[trap_code]); 852 if (cpu_printfataltraps > 1) 853 dump_trapframe(tf); 854 } 855 (*p->p_emul->e_trapsignal)(l, &ksi); 856 } 857 #ifdef DEBUG 858 if ((tf->tf_srr1 & (PSL_DS|PSL_IS)) != (PSL_DS|PSL_IS)) { 859 printf("%s(exit): pid %d.%d (%s): %s invalid PSL %#lx\n", 860 __func__, p->p_pid, l->l_lid, p->p_comm, 861 trap_names[trap_code], tf->tf_srr1); 862 dump_trapframe(tf); 863 Debugger(); 864 } 865 #endif 866 #if 0 867 if ((mfmsr() & PSL_CE) == 0) { 868 printf("%s(exit): pid %d.%d (%s): %s: PSL_CE (%#lx) not set\n", 869 __func__, p->p_pid, l->l_lid, p->p_comm, 870 trap_names[trap_code], mfmsr()); 871 dump_trapframe(tf); 872 } 873 #endif 874 userret(l, tf); 875 } 876 } 877