1 /* $NetBSD: trap.c,v 1.175 2002/11/09 20:06:07 thorpej Exp $ */ 2 3 /* 4 * Copyright (c) 1988 University of Utah. 5 * Copyright (c) 1992, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * This code is derived from software contributed to Berkeley by 9 * the Systems Programming Group of the University of Utah Computer 10 * Science Department and Ralph Campbell. 11 * 12 * Redistribution and use in source and binary forms, with or without 13 * modification, are permitted provided that the following conditions 14 * are met: 15 * 1. Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 2. Redistributions in binary form must reproduce the above copyright 18 * notice, this list of conditions and the following disclaimer in the 19 * documentation and/or other materials provided with the distribution. 20 * 3. All advertising materials mentioning features or use of this software 21 * must display the following acknowledgement: 22 * This product includes software developed by the University of 23 * California, Berkeley and its contributors. 24 * 4. Neither the name of the University nor the names of its contributors 25 * may be used to endorse or promote products derived from this software 26 * without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 38 * SUCH DAMAGE. 39 * 40 * from: Utah Hdr: trap.c 1.32 91/04/06 41 * 42 * @(#)trap.c 8.5 (Berkeley) 1/11/94 43 */ 44 45 #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */ 46 47 __KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.175 2002/11/09 20:06:07 thorpej Exp $"); 48 49 #include "opt_cputype.h" /* which mips CPU levels do we support? */ 50 #include "opt_ktrace.h" 51 #include "opt_ddb.h" 52 #include "opt_kgdb.h" 53 54 #include <sys/param.h> 55 #include <sys/systm.h> 56 #include <sys/kernel.h> 57 #include <sys/proc.h> 58 #include <sys/ras.h> 59 #include <sys/signalvar.h> 60 #include <sys/syscall.h> 61 #include <sys/user.h> 62 #include <sys/buf.h> 63 #ifdef KTRACE 64 #include <sys/ktrace.h> 65 #endif 66 67 #include <mips/cache.h> 68 #include <mips/locore.h> 69 #include <mips/mips_opcode.h> 70 71 #include <uvm/uvm_extern.h> 72 73 #include <machine/cpu.h> 74 #include <mips/trap.h> 75 #include <mips/reg.h> 76 #include <mips/regnum.h> /* symbolic register indices */ 77 #include <mips/pte.h> 78 #include <mips/psl.h> 79 #include <mips/userret.h> 80 81 #include <net/netisr.h> 82 83 #ifdef DDB 84 #include <machine/db_machdep.h> 85 #include <ddb/db_sym.h> 86 #endif 87 88 #ifdef KGDB 89 #include <sys/kgdb.h> 90 #endif 91 92 int want_resched; 93 94 const char *trap_type[] = { 95 "external interrupt", 96 "TLB modification", 97 "TLB miss (load or instr. fetch)", 98 "TLB miss (store)", 99 "address error (load or I-fetch)", 100 "address error (store)", 101 "bus error (I-fetch)", 102 "bus error (load or store)", 103 "system call", 104 "breakpoint", 105 "reserved instruction", 106 "coprocessor unusable", 107 "arithmetic overflow", 108 "r4k trap/r3k reserved 13", 109 "r4k virtual coherency instruction/r3k reserved 14", 110 "r4k floating point/ r3k reserved 15", 111 "reserved 16", 112 "reserved 17", 113 "mipsNN cp2 exception", 114 "reserved 19", 115 "reserved 20", 116 "reserved 21", 117 "mips64 MDMX", 118 "r4k watch", 119 "mipsNN machine check", 120 "reserved 25", 121 "reserved 26", 122 "reserved 27", 123 "reserved 28", 124 "reserved 29", 125 "mipsNN cache error", 126 "r4000 virtual coherency data", 127 }; 128 129 void trap(unsigned, unsigned, unsigned, unsigned, struct trapframe *); 130 void ast(unsigned); 131 132 extern vaddr_t MachEmulateBranch(struct frame *, vaddr_t, unsigned, int); 133 extern void MachEmulateInst(u_int32_t, u_int32_t, u_int32_t, struct frame *); 134 extern void MachFPTrap(u_int32_t, u_int32_t, u_int32_t, struct frame *); 135 136 #define DELAYBRANCH(x) ((int)(x)<0) 137 138 /* 139 * fork syscall returns directly to user process via proc_trampoline, 140 * which will be called the very first time when child gets running. 141 */ 142 void 143 child_return(arg) 144 void *arg; 145 { 146 struct proc *p = arg; 147 struct frame *frame = (struct frame *)p->p_md.md_regs; 148 149 frame->f_regs[V0] = 0; 150 frame->f_regs[V1] = 1; 151 frame->f_regs[A3] = 0; 152 userret(p); 153 #ifdef KTRACE 154 if (KTRPOINT(p, KTR_SYSRET)) 155 ktrsysret(p, SYS_fork, 0, 0); 156 #endif 157 } 158 159 #ifdef MIPS3_PLUS 160 #define TRAPTYPE(x) (((x) & MIPS3_CR_EXC_CODE) >> MIPS_CR_EXC_CODE_SHIFT) 161 #else 162 #define TRAPTYPE(x) (((x) & MIPS1_CR_EXC_CODE) >> MIPS_CR_EXC_CODE_SHIFT) 163 #endif 164 #define KERNLAND(x) ((int)(x) < 0) 165 166 /* 167 * Trap is called from locore to handle most types of processor traps. 168 * System calls are broken out for efficiency. MIPS can handle software 169 * interrupts as a part of real interrupt processing. 170 */ 171 void 172 trap(status, cause, vaddr, opc, frame) 173 unsigned status; 174 unsigned cause; 175 unsigned vaddr; 176 unsigned opc; 177 struct trapframe *frame; 178 { 179 int type, sig; 180 int ucode = 0; 181 struct proc *p = curproc; 182 vm_prot_t ftype; 183 extern void fswintrberr(void); 184 185 uvmexp.traps++; 186 type = TRAPTYPE(cause); 187 if (USERMODE(status)) 188 type |= T_USER; 189 190 if (status & ((CPUISMIPS3) ? MIPS_SR_INT_IE : MIPS1_SR_INT_ENA_PREV)) { 191 if (type != T_BREAK) { 192 #ifdef IPL_ICU_MASK 193 spllowersofthigh(); 194 #else 195 _splset((status & MIPS_HARD_INT_MASK) | MIPS_SR_INT_IE); 196 #endif 197 } 198 } 199 200 switch (type) { 201 default: 202 dopanic: 203 (void)splhigh(); 204 printf("trap: %s in %s mode\n", 205 trap_type[TRAPTYPE(cause)], 206 USERMODE(status) ? "user" : "kernel"); 207 printf("status=0x%x, cause=0x%x, epc=0x%x, vaddr=0x%x\n", 208 status, cause, opc, vaddr); 209 if (curproc != NULL) 210 printf("pid=%d cmd=%s usp=0x%x ", 211 p->p_pid, p->p_comm, 212 (int)((struct frame *)p->p_md.md_regs)->f_regs[SP]); 213 else 214 printf("curproc == NULL "); 215 printf("ksp=0x%x\n", (int)&status); 216 #if defined(DDB) 217 kdb_trap(type, (mips_reg_t *) frame); 218 /* XXX force halt XXX */ 219 #elif defined(KGDB) 220 { 221 struct frame *f = (struct frame *)&ddb_regs; 222 extern mips_reg_t kgdb_cause, kgdb_vaddr; 223 kgdb_cause = cause; 224 kgdb_vaddr = vaddr; 225 226 /* 227 * init global ddb_regs, used in db_interface.c routines 228 * shared between ddb and gdb. Send ddb_regs to gdb so 229 * that db_machdep.h macros will work with it, and 230 * allow gdb to alter the PC. 231 */ 232 db_set_ddb_regs(type, (mips_reg_t *) frame); 233 PC_BREAK_ADVANCE(f); 234 if (kgdb_trap(type, &ddb_regs)) { 235 ((mips_reg_t *)frame)[21] = f->f_regs[PC]; 236 return; 237 } 238 } 239 #else 240 panic("trap"); 241 #endif 242 /*NOTREACHED*/ 243 case T_TLB_MOD: 244 if (KERNLAND(vaddr)) { 245 pt_entry_t *pte; 246 unsigned entry; 247 paddr_t pa; 248 249 pte = kvtopte(vaddr); 250 entry = pte->pt_entry; 251 if (!mips_pg_v(entry) || (entry & mips_pg_m_bit())) { 252 panic("ktlbmod: invalid pte"); 253 } 254 if (entry & mips_pg_ro_bit()) { 255 /* write to read only page in the kernel */ 256 ftype = VM_PROT_WRITE; 257 goto kernelfault; 258 } 259 entry |= mips_pg_m_bit(); 260 pte->pt_entry = entry; 261 vaddr &= ~PGOFSET; 262 MachTLBUpdate(vaddr, entry); 263 pa = mips_tlbpfn_to_paddr(entry); 264 if (!IS_VM_PHYSADDR(pa)) { 265 printf("ktlbmod: va %x pa %llx\n", 266 vaddr, (long long)pa); 267 panic("ktlbmod: unmanaged page"); 268 } 269 pmap_set_modified(pa); 270 return; /* KERN */ 271 } 272 /*FALLTHROUGH*/ 273 case T_TLB_MOD+T_USER: 274 { 275 pt_entry_t *pte; 276 unsigned entry; 277 paddr_t pa; 278 pmap_t pmap; 279 280 pmap = p->p_vmspace->vm_map.pmap; 281 if (!(pte = pmap_segmap(pmap, vaddr))) 282 panic("utlbmod: invalid segmap"); 283 pte += (vaddr >> PGSHIFT) & (NPTEPG - 1); 284 entry = pte->pt_entry; 285 if (!mips_pg_v(entry) || (entry & mips_pg_m_bit())) 286 panic("utlbmod: invalid pte"); 287 288 if (entry & mips_pg_ro_bit()) { 289 /* write to read only page */ 290 ftype = VM_PROT_WRITE; 291 goto pagefault; 292 } 293 entry |= mips_pg_m_bit(); 294 pte->pt_entry = entry; 295 vaddr = (vaddr & ~PGOFSET) | 296 (pmap->pm_asid << MIPS_TLB_PID_SHIFT); 297 MachTLBUpdate(vaddr, entry); 298 pa = mips_tlbpfn_to_paddr(entry); 299 if (!IS_VM_PHYSADDR(pa)) { 300 printf("utlbmod: va %x pa %llx\n", 301 vaddr, (long long)pa); 302 panic("utlbmod: unmanaged page"); 303 } 304 pmap_set_modified(pa); 305 if (type & T_USER) 306 userret(p); 307 return; /* GEN */ 308 } 309 case T_TLB_LD_MISS: 310 case T_TLB_ST_MISS: 311 ftype = (type == T_TLB_LD_MISS) ? VM_PROT_READ : VM_PROT_WRITE; 312 if (KERNLAND(vaddr)) 313 goto kernelfault; 314 /* 315 * It is an error for the kernel to access user space except 316 * through the copyin/copyout routines. 317 */ 318 if (p == NULL || p->p_addr->u_pcb.pcb_onfault == NULL) 319 goto dopanic; 320 /* check for fuswintr() or suswintr() getting a page fault */ 321 if (p->p_addr->u_pcb.pcb_onfault == (caddr_t)fswintrberr) { 322 frame->tf_regs[TF_EPC] = (int)fswintrberr; 323 return; /* KERN */ 324 } 325 goto pagefault; 326 case T_TLB_LD_MISS+T_USER: 327 ftype = VM_PROT_READ; 328 goto pagefault; 329 case T_TLB_ST_MISS+T_USER: 330 ftype = VM_PROT_WRITE; 331 pagefault: ; 332 { 333 vaddr_t va; 334 struct vmspace *vm; 335 struct vm_map *map; 336 int rv; 337 338 vm = p->p_vmspace; 339 map = &vm->vm_map; 340 va = trunc_page(vaddr); 341 342 if (p->p_emul->e_fault) 343 rv = (*p->p_emul->e_fault)(p, va, 0, ftype); 344 else 345 rv = uvm_fault(map, va, 0, ftype); 346 #ifdef VMFAULT_TRACE 347 printf( 348 "uvm_fault(%p (pmap %p), %lx (0x%x), 0, %d) -> %d at pc %p\n", 349 map, vm->vm_map.pmap, va, vaddr, ftype, rv, (void*)opc); 350 #endif 351 /* 352 * If this was a stack access we keep track of the maximum 353 * accessed stack size. Also, if vm_fault gets a protection 354 * failure it is due to accessing the stack region outside 355 * the current limit and we need to reflect that as an access 356 * error. 357 */ 358 if ((caddr_t)va >= vm->vm_maxsaddr) { 359 if (rv == 0) { 360 segsz_t nss; 361 362 nss = btoc(USRSTACK - va); 363 if (nss > vm->vm_ssize) 364 vm->vm_ssize = nss; 365 } 366 else if (rv == EACCES) 367 rv = EFAULT; 368 } 369 if (rv == 0) { 370 if (type & T_USER) { 371 userret(p); 372 } 373 return; /* GEN */ 374 } 375 if ((type & T_USER) == 0) 376 goto copyfault; 377 if (rv == ENOMEM) { 378 printf("UVM: pid %d (%s), uid %d killed: out of swap\n", 379 p->p_pid, p->p_comm, 380 p->p_cred && p->p_ucred ? 381 p->p_ucred->cr_uid : (uid_t) -1); 382 sig = SIGKILL; 383 } else { 384 sig = (rv == EACCES) ? SIGBUS : SIGSEGV; 385 } 386 ucode = vaddr; 387 break; /* SIGNAL */ 388 } 389 kernelfault: ; 390 { 391 vaddr_t va; 392 int rv; 393 394 va = trunc_page(vaddr); 395 rv = uvm_fault(kernel_map, va, 0, ftype); 396 if (rv == 0) 397 return; /* KERN */ 398 /*FALLTHROUGH*/ 399 } 400 case T_ADDR_ERR_LD: /* misaligned access */ 401 case T_ADDR_ERR_ST: /* misaligned access */ 402 case T_BUS_ERR_LD_ST: /* BERR asserted to cpu */ 403 copyfault: 404 if (p == NULL || p->p_addr->u_pcb.pcb_onfault == NULL) 405 goto dopanic; 406 frame->tf_regs[TF_EPC] = (int)p->p_addr->u_pcb.pcb_onfault; 407 return; /* KERN */ 408 409 case T_ADDR_ERR_LD+T_USER: /* misaligned or kseg access */ 410 case T_ADDR_ERR_ST+T_USER: /* misaligned or kseg access */ 411 case T_BUS_ERR_IFETCH+T_USER: /* BERR asserted to cpu */ 412 case T_BUS_ERR_LD_ST+T_USER: /* BERR asserted to cpu */ 413 sig = SIGSEGV; 414 ucode = vaddr; 415 break; /* SIGNAL */ 416 417 case T_BREAK: 418 #if defined(DDB) 419 kdb_trap(type, (mips_reg_t *) frame); 420 return; /* KERN */ 421 #elif defined(KGDB) 422 { 423 struct frame *f = (struct frame *)&ddb_regs; 424 extern mips_reg_t kgdb_cause, kgdb_vaddr; 425 kgdb_cause = cause; 426 kgdb_vaddr = vaddr; 427 428 /* 429 * init global ddb_regs, used in db_interface.c routines 430 * shared between ddb and gdb. Send ddb_regs to gdb so 431 * that db_machdep.h macros will work with it, and 432 * allow gdb to alter the PC. 433 */ 434 db_set_ddb_regs(type, (mips_reg_t *) frame); 435 PC_BREAK_ADVANCE(f); 436 if (!kgdb_trap(type, &ddb_regs)) 437 printf("kgdb: ignored %s\n", 438 trap_type[TRAPTYPE(cause)]); 439 else 440 ((mips_reg_t *)frame)[21] = f->f_regs[PC]; 441 442 return; 443 } 444 #else 445 goto dopanic; 446 #endif 447 case T_BREAK+T_USER: 448 { 449 unsigned va, instr; 450 int rv; 451 452 /* compute address of break instruction */ 453 va = (DELAYBRANCH(cause)) ? opc + sizeof(int) : opc; 454 455 /* read break instruction */ 456 instr = fuiword((void *)va); 457 458 if (p->p_md.md_ss_addr != va || instr != MIPS_BREAK_SSTEP) { 459 sig = SIGTRAP; 460 break; 461 } 462 /* 463 * Restore original instruction and clear BP 464 */ 465 rv = suiword((void *)va, p->p_md.md_ss_instr); 466 if (rv < 0) { 467 vaddr_t sa, ea; 468 sa = trunc_page(va); 469 ea = round_page(va + sizeof(int) - 1); 470 rv = uvm_map_protect(&p->p_vmspace->vm_map, 471 sa, ea, VM_PROT_DEFAULT, FALSE); 472 if (rv == 0) { 473 rv = suiword((void *)va, MIPS_BREAK_SSTEP); 474 (void)uvm_map_protect(&p->p_vmspace->vm_map, 475 sa, ea, VM_PROT_READ|VM_PROT_EXECUTE, FALSE); 476 } 477 } 478 mips_icache_sync_all(); /* XXXJRT -- necessary? */ 479 mips_dcache_wbinv_all(); /* XXXJRT -- necessary? */ 480 481 if (rv < 0) 482 printf("Warning: can't restore instruction at 0x%lx: 0x%x\n", 483 p->p_md.md_ss_addr, p->p_md.md_ss_instr); 484 p->p_md.md_ss_addr = 0; 485 sig = SIGTRAP; 486 break; /* SIGNAL */ 487 } 488 case T_RES_INST+T_USER: 489 case T_COP_UNUSABLE+T_USER: 490 #if !defined(SOFTFLOAT) && !defined(NOFPU) 491 if ((cause & MIPS_CR_COP_ERR) == 0x10000000) { 492 struct frame *f; 493 494 f = (struct frame *)p->p_md.md_regs; 495 savefpregs(fpcurproc); /* yield FPA */ 496 loadfpregs(p); /* load FPA */ 497 fpcurproc = p; 498 p->p_md.md_flags |= MDP_FPUSED; 499 f->f_regs[SR] |= MIPS_SR_COP_1_BIT; 500 } else 501 #endif 502 { 503 MachEmulateInst(status, cause, opc, p->p_md.md_regs); 504 } 505 userret(p); 506 return; /* GEN */ 507 case T_FPE+T_USER: 508 #if defined(SOFTFLOAT) 509 MachEmulateInst(status, cause, opc, p->p_md.md_regs); 510 #elif !defined(NOFPU) 511 MachFPTrap(status, cause, opc, p->p_md.md_regs); 512 #endif 513 userret(p); 514 return; /* GEN */ 515 case T_OVFLOW+T_USER: 516 case T_TRAP+T_USER: 517 sig = SIGFPE; 518 break; /* SIGNAL */ 519 } 520 ((struct frame *)p->p_md.md_regs)->f_regs[CAUSE] = cause; 521 ((struct frame *)p->p_md.md_regs)->f_regs[BADVADDR] = vaddr; 522 trapsignal(p, sig, ucode); 523 if ((type & T_USER) == 0) 524 panic("trapsignal"); 525 userret(p); 526 return; 527 } 528 529 /* 530 * Software (low priority) network interrupt. i.e. softnet(). 531 */ 532 void 533 netintr() 534 { 535 #define DONETISR(bit, fn) \ 536 do { \ 537 if (n & (1 << bit)) \ 538 fn(); \ 539 } while (0) 540 541 int n; 542 n = netisr; netisr = 0; 543 544 #ifdef SOFTNET_INTR /* XXX TEMPORARY XXX */ 545 intrcnt[SOFTNET_INTR]++; 546 #endif 547 548 #include <net/netisr_dispatch.h> 549 550 #undef DONETISR 551 } 552 553 /* 554 * Handle asynchronous software traps. 555 * This is called from MachUserIntr() either to deliver signals or 556 * to make involuntary context switch (preemption). 557 */ 558 void 559 ast(pc) 560 unsigned pc; /* program counter where to continue */ 561 { 562 struct proc *p = curproc; 563 int sig; 564 565 while (p->p_md.md_astpending) { 566 uvmexp.softs++; 567 p->p_md.md_astpending = 0; 568 569 if (p->p_flag & P_OWEUPC) { 570 p->p_flag &= ~P_OWEUPC; 571 ADDUPROF(p); 572 } 573 574 /* Take pending signals. */ 575 while ((sig = CURSIG(p)) != 0) 576 postsig(sig); 577 578 if (want_resched) { 579 /* 580 * We are being preempted. 581 */ 582 preempt(NULL); 583 } 584 585 userret(p); 586 } 587 } 588 589 590 /* XXX need to rewrite acient comment XXX 591 * This routine is called by procxmt() to single step one instruction. 592 * We do this by storing a break instruction after the current instruction, 593 * resuming execution, and then restoring the old instruction. 594 */ 595 int 596 mips_singlestep(p) 597 struct proc *p; 598 { 599 struct frame *f = (struct frame *)p->p_md.md_regs; 600 vaddr_t pc, va; 601 int rv; 602 603 if (p->p_md.md_ss_addr) { 604 printf("SS %s (%d): breakpoint already set at %lx\n", 605 p->p_comm, p->p_pid, p->p_md.md_ss_addr); 606 return EFAULT; 607 } 608 pc = (vaddr_t)f->f_regs[PC]; 609 if (fuiword((void *)pc) != 0) /* not a NOP instruction */ 610 va = MachEmulateBranch(f, pc, 611 PCB_FSR(&p->p_addr->u_pcb), 1); 612 else 613 va = pc + sizeof(int); 614 615 /* 616 * We can't single-step into a RAS. Check if we're in 617 * a RAS, and set the breakpoint just past it. 618 */ 619 if (p->p_nras != 0) { 620 while (ras_lookup(p, (caddr_t)va) != (caddr_t)-1) 621 va += sizeof(int); 622 } 623 624 p->p_md.md_ss_addr = va; 625 p->p_md.md_ss_instr = fuiword((void *)va); 626 rv = suiword((void *)va, MIPS_BREAK_SSTEP); 627 if (rv < 0) { 628 vaddr_t sa, ea; 629 sa = trunc_page(va); 630 ea = round_page(va + sizeof(int) - 1); 631 rv = uvm_map_protect(&p->p_vmspace->vm_map, 632 sa, ea, VM_PROT_DEFAULT, FALSE); 633 if (rv == 0) { 634 rv = suiword((void *)va, MIPS_BREAK_SSTEP); 635 (void)uvm_map_protect(&p->p_vmspace->vm_map, 636 sa, ea, VM_PROT_READ|VM_PROT_EXECUTE, FALSE); 637 } 638 } 639 #if 0 640 printf("SS %s (%d): breakpoint set at %x: %x (pc %x) br %x\n", 641 p->p_comm, p->p_pid, p->p_md.md_ss_addr, 642 p->p_md.md_ss_instr, pc, fuword((void *)va)); /* XXX */ 643 #endif 644 return 0; 645 } 646 647 648 #ifndef DDB_TRACE 649 650 #if defined(DEBUG) || defined(DDB) || defined(KGDB) || defined(geo) 651 mips_reg_t kdbrpeek(vaddr_t); 652 653 int 654 kdbpeek(addr) 655 vaddr_t addr; 656 { 657 int rc; 658 if (addr & 3) { 659 printf("kdbpeek: unaligned address %lx\n", addr); 660 /* We might have been called from DDB, so do not go there. */ 661 stacktrace(); 662 rc = -1 ; 663 } else if (addr == NULL) { 664 printf("kdbpeek: NULL\n"); 665 rc = 0xdeadfeed; 666 } else { 667 rc = *(int *)addr; 668 } 669 return rc; 670 } 671 672 mips_reg_t 673 kdbrpeek(addr) 674 vaddr_t addr; 675 { 676 mips_reg_t rc; 677 if (addr & (sizeof(mips_reg_t) - 1)) { 678 printf("kdbrpeek: unaligned address %lx\n", addr); 679 /* We might have been called from DDB, so do not go there. */ 680 stacktrace(); 681 rc = -1 ; 682 } else if (addr == NULL) { 683 printf("kdbrpeek: NULL\n"); 684 rc = 0xdeadfeed; 685 } else { 686 rc = *(mips_reg_t *)addr; 687 } 688 return rc; 689 } 690 691 extern char start[], edata[], verylocore[]; 692 extern char mips1_KernGenException[]; 693 extern char mips1_UserGenException[]; 694 extern char mips1_KernIntr[]; 695 extern char mips1_UserIntr[]; 696 extern char mips1_SystemCall[]; 697 extern char mips3_KernGenException[]; 698 extern char mips3_UserGenException[]; 699 extern char mips3_KernIntr[]; 700 extern char mips3_UserIntr[]; 701 extern char mips3_SystemCall[]; 702 extern int main(void *); 703 extern void mips_idle(void); 704 extern void cpu_switch(struct proc *, struct proc *); 705 706 /* 707 * stack trace code, also useful to DDB one day 708 */ 709 710 /* forward */ 711 char *fn_name(unsigned addr); 712 void stacktrace_subr(int, int, int, int, u_int, u_int, u_int, u_int, 713 void (*)(const char*, ...)); 714 715 #define MIPS_JR_RA 0x03e00008 /* instruction code for jr ra */ 716 #define MIPS_JR_K0 0x03400008 /* instruction code for jr k0 */ 717 #define MIPS_ERET 0x42000018 /* instruction code for eret */ 718 719 /* 720 * Do a stack backtrace. 721 * (*printfn)() prints the output to either the system log, 722 * the console, or both. 723 */ 724 void 725 stacktrace_subr(a0, a1, a2, a3, pc, sp, fp, ra, printfn) 726 int a0, a1, a2, a3; 727 u_int pc, sp, fp, ra; 728 void (*printfn)(const char*, ...); 729 { 730 unsigned va, subr; 731 unsigned instr, mask; 732 InstFmt i; 733 int more, stksize; 734 unsigned int frames = 0; 735 int foundframesize = 0; 736 737 /* Jump here when done with a frame, to start a new one */ 738 loop: 739 stksize = 0; 740 subr = 0; 741 if (frames++ > 100) { 742 (*printfn)("\nstackframe count exceeded\n"); 743 /* return breaks stackframe-size heuristics with gcc -O2 */ 744 goto finish; /*XXX*/ 745 } 746 747 /* check for bad SP: could foul up next frame */ 748 if (sp & 3 || sp < 0x80000000) { 749 (*printfn)("SP 0x%x: not in kernel\n", sp); 750 ra = 0; 751 subr = 0; 752 goto done; 753 } 754 755 /* Check for bad PC */ 756 if (pc & 3 || pc < 0x80000000 || pc >= (unsigned)edata) { 757 (*printfn)("PC 0x%x: not in kernel space\n", pc); 758 ra = 0; 759 goto done; 760 } 761 762 /* 763 * Find the beginning of the current subroutine by scanning backwards 764 * from the current PC for the end of the previous subroutine. 765 */ 766 va = pc; 767 do { 768 va -= sizeof(int); 769 if (va <= (unsigned)verylocore) 770 goto finish; 771 instr = kdbpeek(va); 772 if (instr == MIPS_ERET) 773 goto mips3_eret; 774 } while (instr != MIPS_JR_RA && instr != MIPS_JR_K0); 775 /* skip back over branch & delay slot */ 776 va += sizeof(int); 777 mips3_eret: 778 va += sizeof(int); 779 /* skip over nulls which might separate .o files */ 780 while ((instr = kdbpeek(va)) == 0) 781 va += sizeof(int); 782 subr = va; 783 784 /* scan forwards to find stack size and any saved registers */ 785 stksize = 0; 786 more = 3; 787 mask = 0; 788 foundframesize = 0; 789 for (va = subr; more; va += sizeof(int), 790 more = (more == 3) ? 3 : more - 1) { 791 /* stop if hit our current position */ 792 if (va >= pc) 793 break; 794 instr = kdbpeek(va); 795 i.word = instr; 796 switch (i.JType.op) { 797 case OP_SPECIAL: 798 switch (i.RType.func) { 799 case OP_JR: 800 case OP_JALR: 801 more = 2; /* stop after next instruction */ 802 break; 803 804 case OP_SYSCALL: 805 case OP_BREAK: 806 more = 1; /* stop now */ 807 }; 808 break; 809 810 case OP_BCOND: 811 case OP_J: 812 case OP_JAL: 813 case OP_BEQ: 814 case OP_BNE: 815 case OP_BLEZ: 816 case OP_BGTZ: 817 more = 2; /* stop after next instruction */ 818 break; 819 820 case OP_COP0: 821 case OP_COP1: 822 case OP_COP2: 823 case OP_COP3: 824 switch (i.RType.rs) { 825 case OP_BCx: 826 case OP_BCy: 827 more = 2; /* stop after next instruction */ 828 }; 829 break; 830 831 case OP_SW: 832 /* look for saved registers on the stack */ 833 if (i.IType.rs != 29) 834 break; 835 /* only restore the first one */ 836 if (mask & (1 << i.IType.rt)) 837 break; 838 mask |= (1 << i.IType.rt); 839 switch (i.IType.rt) { 840 case 4: /* a0 */ 841 a0 = kdbpeek(sp + (short)i.IType.imm); 842 break; 843 844 case 5: /* a1 */ 845 a1 = kdbpeek(sp + (short)i.IType.imm); 846 break; 847 848 case 6: /* a2 */ 849 a2 = kdbpeek(sp + (short)i.IType.imm); 850 break; 851 852 case 7: /* a3 */ 853 a3 = kdbpeek(sp + (short)i.IType.imm); 854 break; 855 856 case 30: /* fp */ 857 fp = kdbpeek(sp + (short)i.IType.imm); 858 break; 859 860 case 31: /* ra */ 861 ra = kdbpeek(sp + (short)i.IType.imm); 862 } 863 break; 864 865 case OP_ADDI: 866 case OP_ADDIU: 867 /* look for stack pointer adjustment */ 868 if (i.IType.rs != 29 || i.IType.rt != 29) 869 break; 870 /* don't count pops for mcount */ 871 if (!foundframesize) { 872 stksize = - ((short)i.IType.imm); 873 foundframesize = 1; 874 } 875 } 876 } 877 done: 878 (*printfn)("%s+%x (%x,%x,%x,%x) ra %x sz %d\n", 879 fn_name(subr), pc - subr, a0, a1, a2, a3, ra, stksize); 880 881 if (ra) { 882 if (pc == ra && stksize == 0) 883 (*printfn)("stacktrace: loop!\n"); 884 else { 885 pc = ra; 886 sp += stksize; 887 ra = 0; 888 goto loop; 889 } 890 } else { 891 finish: 892 if (curproc) 893 (*printfn)("User-level: pid %d\n", curproc->p_pid); 894 else 895 (*printfn)("User-level: curproc NULL\n"); 896 } 897 } 898 899 /* 900 * Functions ``special'' enough to print by name 901 */ 902 #ifdef __STDC__ 903 #define Name(_fn) { (void*)_fn, # _fn } 904 #else 905 #define Name(_fn) { _fn, "_fn"} 906 #endif 907 static struct { void *addr; char *name;} names[] = { 908 Name(stacktrace), 909 Name(stacktrace_subr), 910 Name(main), 911 Name(trap), 912 913 #ifdef MIPS1 /* r2000 family (mips-I cpu) */ 914 Name(mips1_KernGenException), 915 Name(mips1_UserGenException), 916 Name(mips1_SystemCall), 917 Name(mips1_KernIntr), 918 Name(mips1_UserIntr), 919 #endif /* MIPS1 */ 920 921 /* XXX simonb: need mips32 and mips64 checks here too */ 922 #if defined(MIPS3) && !defined(MIPS3_5900) /* r4000 family (mips-III cpu) */ 923 Name(mips3_KernGenException), 924 Name(mips3_UserGenException), 925 Name(mips3_SystemCall), 926 Name(mips3_KernIntr), 927 Name(mips3_UserIntr), 928 #endif /* MIPS3 && !MIPS3_5900 */ 929 930 Name(mips_idle), 931 Name(cpu_switch), 932 {0, 0} 933 }; 934 935 /* 936 * Map a function address to a string name, if known; or a hex string. 937 */ 938 char * 939 fn_name(unsigned addr) 940 { 941 static char buf[17]; 942 int i = 0; 943 #ifdef DDB 944 db_expr_t diff; 945 db_sym_t sym; 946 char *symname; 947 #endif 948 949 #ifdef DDB 950 diff = 0; 951 symname = NULL; 952 sym = db_search_symbol(addr, DB_STGY_ANY, &diff); 953 db_symbol_values(sym, &symname, 0); 954 if (symname && diff == 0) 955 return (symname); 956 #endif 957 for (i = 0; names[i].name; i++) 958 if (names[i].addr == (void*)addr) 959 return (names[i].name); 960 sprintf(buf, "%x", addr); 961 return (buf); 962 } 963 964 #endif /* DEBUG */ 965 966 #endif /* DDB_TRACE */ 967