1/* $NetBSD: trap.c,v 1.265 2023/10/24 18:08:16 andvar 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. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * from: Utah Hdr: trap.c 1.32 91/04/06 37 * 38 * @(#)trap.c 8.5 (Berkeley) 1/11/94 39 */ 40 41#include <sys/cdefs.h> 42__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.265 2023/10/24 18:08:16 andvar Exp $"); 43 44#include "opt_cputype.h" /* which mips CPU levels do we support? */ 45#include "opt_ddb.h" 46#include "opt_dtrace.h" 47#include "opt_kgdb.h" 48#include "opt_multiprocessor.h" 49 50#include <sys/param.h> 51#include <sys/systm.h> 52#include <sys/kernel.h> 53#include <sys/cpu.h> 54#include <sys/proc.h> 55#include <sys/ras.h> 56#include <sys/signalvar.h> 57#include <sys/syscall.h> 58#include <sys/buf.h> 59#include <sys/ktrace.h> 60#include <sys/kauth.h> 61#include <sys/atomic.h> 62 63#include <mips/cache.h> 64#include <mips/locore.h> 65#include <mips/mips_opcode.h> 66 67#include <uvm/uvm.h> 68 69#include <mips/trap.h> 70#include <mips/reg.h> 71#include <mips/regnum.h> /* symbolic register indices */ 72#include <mips/pcb.h> 73#include <mips/pte.h> 74#include <mips/psl.h> 75#include <mips/userret.h> 76 77#ifdef DDB 78#include <machine/db_machdep.h> 79#include <ddb/db_sym.h> 80#endif 81 82#ifdef KGDB 83#include <sys/kgdb.h> 84#endif 85 86#ifdef KDTRACE_HOOKS 87#include <sys/dtrace_bsd.h> 88 89/* Not used for now, but needed for dtrace/fbt modules */ 90dtrace_doubletrap_func_t dtrace_doubletrap_func = NULL; 91dtrace_trap_func_t dtrace_trap_func = NULL; 92 93int (* dtrace_invop_jump_addr)(struct trapframe *); 94#endif /* KDTRACE_HOOKS */ 95 96const char * const trap_names[] = { 97 "external interrupt", 98 "TLB modification", 99 "TLB miss (load or instr. fetch)", 100 "TLB miss (store)", 101 "address error (load or I-fetch)", 102 "address error (store)", 103 "bus error (I-fetch)", 104 "bus error (load or store)", 105 "system call", 106 "breakpoint", 107 "reserved instruction", 108 "coprocessor unusable", 109 "arithmetic overflow", 110 "r4k trap/r3k reserved 13", 111 "r4k virtual coherency instruction/r3k reserved 14", 112 "r4k floating point/ r3k reserved 15", 113 "mips NMI", 114 "reserved 17", 115 "mipsNN cp2 exception", 116 "mipsNN TLBRI", 117 "mipsNN TLBXI", 118 "reserved 21", 119 "mips64 MDMX", 120 "r4k watch", 121 "mipsNN machine check", 122 "mipsNN thread", 123 "DSP exception", 124 "reserved 27", 125 "reserved 28", 126 "reserved 29", 127 "mipsNN cache error", 128 "r4000 virtual coherency data", 129}; 130 131void trap(uint32_t, uint32_t, vaddr_t, vaddr_t, struct trapframe *); 132void ast(void); 133 134#ifdef TRAP_SIGDEBUG 135static void sigdebug(const struct trapframe *, const ksiginfo_t *, int, 136 vaddr_t); 137#define SIGDEBUG(a, b, c, d) sigdebug(a, b, c, d) 138#else 139#define SIGDEBUG(a, b, c, d) 140#endif 141 142/* 143 * fork syscall returns directly to user process via lwp_trampoline(), 144 * which will be called the very first time when child gets running. 145 */ 146void 147md_child_return(struct lwp *l) 148{ 149 struct trapframe *utf = l->l_md.md_utf; 150 151 utf->tf_regs[_R_V0] = 0; 152 utf->tf_regs[_R_V1] = 1; 153 utf->tf_regs[_R_A3] = 0; 154 userret(l); 155} 156 157#ifdef MIPS3_PLUS 158#define TRAPTYPE(x) (((x) & MIPS3_CR_EXC_CODE) >> MIPS_CR_EXC_CODE_SHIFT) 159#else 160#define TRAPTYPE(x) (((x) & MIPS1_CR_EXC_CODE) >> MIPS_CR_EXC_CODE_SHIFT) 161#endif 162#define KERNLAND_P(x) ((intptr_t)(x) < 0) 163 164/* 165 * Trap is called from locore to handle most types of processor traps. 166 * System calls are broken out for efficiency. MIPS can handle software 167 * interrupts as a part of real interrupt processing. 168 */ 169void 170trap(uint32_t status, uint32_t cause, vaddr_t vaddr, vaddr_t pc, 171 struct trapframe *tf) 172{ 173 struct lwp * const l = curlwp; 174 struct proc * const p = curproc; 175 struct trapframe * const utf = l->l_md.md_utf; 176 struct pcb * const pcb = lwp_getpcb(l); 177 vm_prot_t ftype; 178 ksiginfo_t ksi; 179 extern void fswintrberr(void); 180 void *onfault; 181 InstFmt insn; 182 uint32_t instr; 183 int type; 184 int rv = 0; 185 186 KSI_INIT_TRAP(&ksi); 187 188 curcpu()->ci_data.cpu_ntrap++; 189 if (CPUISMIPS3 && (status & MIPS3_SR_NMI)) { 190 type = T_NMI; 191 } else { 192 type = TRAPTYPE(cause); 193 } 194 if (USERMODE(status)) { 195 tf = utf; 196 type |= T_USER; 197 } 198 199#ifdef KDTRACE_HOOKS 200 /* 201 * A trap can occur while DTrace executes a probe. Before 202 * executing the probe, DTrace blocks re-scheduling and sets 203 * a flag in its per-cpu flags to indicate that it doesn't 204 * want to fault. On returning from the probe, the no-fault 205 * flag is cleared and finally re-scheduling is enabled. 206 * 207 * If the DTrace kernel module has registered a trap handler, 208 * call it and if it returns non-zero, assume that it has 209 * handled the trap and modified the trap frame so that this 210 * function can return normally. 211 */ 212 /* 213 * XXXDTRACE: add pid probe handler here (if ever) 214 */ 215 if (!USERMODE(status)) { 216 if ((dtrace_trap_func != NULL) && 217 ((*dtrace_trap_func)(tf, type) != 0)) { 218 return; 219 } 220 } 221#endif /* KDTRACE_HOOKS */ 222 223 switch (type) { 224 default: 225 dopanic: 226 (void)splhigh(); 227 228 /* 229 * use snprintf to allow a single, idempotent, readable printf 230 */ 231 char strbuf[256], *str = strbuf; 232 int n, sz = sizeof(strbuf); 233 234 n = snprintf(str, sz, "pid %d(%s): ", p->p_pid, p->p_comm); 235 sz -= n; 236 str += n; 237 n = snprintf(str, sz, "trap: cpu%d, %s in %s mode\n", 238 cpu_number(), trap_names[TRAPTYPE(cause)], 239 USERMODE(status) ? "user" : "kernel"); 240 sz -= n; 241 str += n; 242 n = snprintf(str, sz, "status=%#x, cause=%#x, epc=%#" 243 PRIxVADDR ", vaddr=%#" PRIxVADDR "\n", 244 status, cause, pc, vaddr); 245 sz -= n; 246 str += n; 247 if (USERMODE(status)) { 248 KASSERT(tf == utf); 249 n = snprintf(str, sz, "frame=%p usp=%#" PRIxREGISTER 250 " ra=%#" PRIxREGISTER "\n", 251 tf, tf->tf_regs[_R_SP], tf->tf_regs[_R_RA]); 252 sz -= n; 253 str += n; 254 } else { 255 n = snprintf(str, sz, "tf=%p ksp=%p ra=%#" 256 PRIxREGISTER " ppl=%#x\n", tf, 257 type == T_NMI 258 ? (void*)(uintptr_t)tf->tf_regs[_R_SP] 259 : tf+1, 260 tf->tf_regs[_R_RA], tf->tf_ppl); 261 sz -= n; 262 str += n; 263 } 264 printf("%s", strbuf); 265 266 if (type == T_BUS_ERR_IFETCH || type == T_BUS_ERR_LD_ST) 267 (void)(*mips_locoresw.lsw_bus_error)(cause); 268 269#if defined(DDB) 270 kdb_trap(type, &tf->tf_registers); 271 /* XXX force halt XXX */ 272#elif defined(KGDB) 273 { 274 extern mips_reg_t kgdb_cause, kgdb_vaddr; 275 struct reg *regs = &ddb_regs; 276 kgdb_cause = cause; 277 kgdb_vaddr = vaddr; 278 279 /* 280 * init global ddb_regs, used in db_interface.c routines 281 * shared between ddb and gdb. Send ddb_regs to gdb so 282 * that db_machdep.h macros will work with it, and 283 * allow gdb to alter the PC. 284 */ 285 db_set_ddb_regs(type, &tf->tf_registers); 286 PC_BREAK_ADVANCE(regs); 287 if (kgdb_trap(type, regs)) { 288 tf->tf_regs[_R_PC] = regs->r_regs[_R_PC]; 289 return; 290 } 291 } 292#else 293 panic("trap"); 294#endif 295 /*NOTREACHED*/ 296 case T_TLB_MOD: 297 case T_TLB_MOD+T_USER: { 298 const bool user_p = (type & T_USER) || !KERNLAND_P(vaddr); 299 pmap_t pmap = user_p 300 ? p->p_vmspace->vm_map.pmap 301 : pmap_kernel(); 302 303 kpreempt_disable(); 304 305 pt_entry_t * const ptep = pmap_pte_lookup(pmap, vaddr); 306 if (!ptep) 307 panic("%ctlbmod: %#"PRIxVADDR": no pte", 308 user_p ? 'u' : 'k', vaddr); 309 pt_entry_t pte = *ptep; 310 if (!pte_valid_p(pte)) { 311 panic("%ctlbmod: %#"PRIxVADDR": invalid pte %#"PRIx32 312 " @ ptep %p", user_p ? 'u' : 'k', vaddr, 313 pte_value(pte), ptep); 314 } 315 if (pte_readonly_p(pte)) { 316 /* write to read only page */ 317 ftype = VM_PROT_WRITE; 318 kpreempt_enable(); 319 if (user_p) { 320 goto pagefault; 321 } else { 322 goto kernelfault; 323 } 324 } 325 UVMHIST_FUNC(__func__); UVMHIST_CALLED(maphist); 326 UVMHIST_LOG(maphist, "%ctlbmod(va=%#lx, pc=%#lx, tf=%#jx)", 327 user_p ? 'u' : 'k', vaddr, pc, (uintptr_t)tf); 328 if (!pte_modified_p(pte)) { 329 pte |= mips_pg_m_bit(); 330#ifdef MULTIPROCESSOR 331 atomic_or_32(ptep, mips_pg_m_bit()); 332#else 333 *ptep = pte; 334#endif 335 } 336 // We got a TLB MOD exception so we must have a valid ASID 337 // and there must be a matching entry in the TLB. So when 338 // we try to update it, we better have done it. 339 KASSERTMSG(pte_valid_p(pte), "%#"PRIx32, pte_value(pte)); 340 vaddr = trunc_page(vaddr); 341 int ok = pmap_tlb_update_addr(pmap, vaddr, pte, 0); 342 kpreempt_enable(); 343 if (ok != 1) { 344#if 0 /* PMAP_FAULTINFO? */ 345 /* 346 * Since we don't block interrupts here, 347 * this can legitimately happen if we get 348 * a TLB miss that's serviced in an interrupt 349 * handler that happens to randomly evict the 350 * TLB entry we're concerned about. 351 */ 352 printf("pmap_tlb_update_addr(%p,%#" 353 PRIxVADDR",%#"PRIxPTE", 0) returned %d\n", 354 pmap, vaddr, pte_value(pte), ok); 355#endif 356 } 357 paddr_t pa = pte_to_paddr(pte); 358 KASSERTMSG(uvm_pageismanaged(pa), 359 "%#"PRIxVADDR" pa %#"PRIxPADDR, vaddr, pa); 360 pmap_set_modified(pa); 361 if (type & T_USER) 362 userret(l); 363 UVMHIST_LOG(maphist, " <-- done", 0, 0, 0, 0); 364 return; /* GEN */ 365 } 366 case T_TLB_LD_MISS: 367 case T_TLB_ST_MISS: 368 ftype = (type == T_TLB_LD_MISS) ? VM_PROT_READ : VM_PROT_WRITE; 369 if (KERNLAND_P(vaddr)) 370 goto kernelfault; 371 /* 372 * It is an error for the kernel to access user space except 373 * through the copyin/copyout routines. 374 */ 375 if (pcb->pcb_onfault == NULL) { 376 goto dopanic; 377 } 378 goto pagefault; 379 case T_TLB_LD_MISS+T_USER: 380 ftype = VM_PROT_READ; 381 goto pagefault; 382 case T_TLB_ST_MISS+T_USER: 383 ftype = VM_PROT_WRITE; 384 pagefault: { 385 const vaddr_t va = trunc_page(vaddr); 386 struct vmspace * const vm = p->p_vmspace; 387 struct vm_map * const map = &vm->vm_map; 388#ifdef PMAP_FAULTINFO 389 struct pcb_faultinfo * const pfi = &pcb->pcb_faultinfo; 390#endif 391 392 kpreempt_disable(); 393#ifdef _LP64 394 /* 395 * If the pmap has been activated and we allocated the segtab 396 * for the low 4GB, seg0tab may still be NULL. We can't 397 * really fix this in pmap_enter (we can only update the local 398 * cpu's cpu_info but not other cpu's) so we need to detect 399 * and fix this here. 400 */ 401 struct cpu_info * const ci = curcpu(); 402 if ((va >> XSEGSHIFT) == 0 && 403 __predict_false(ci->ci_pmap_user_seg0tab == NULL 404 && ci->ci_pmap_user_segtab->seg_seg[0] != NULL)) { 405 ci->ci_pmap_user_seg0tab = 406 ci->ci_pmap_user_segtab->seg_seg[0]; 407 kpreempt_enable(); 408 if (type & T_USER) { 409 userret(l); 410 } 411 return; /* GEN */ 412 } 413#endif 414 KASSERT(KERNLAND_P(va) || curcpu()->ci_pmap_asid_cur != 0); 415 pmap_tlb_asid_check(); 416 kpreempt_enable(); 417 418#ifdef PMAP_FAULTINFO 419 if (p->p_pid == pfi->pfi_lastpid && va == pfi->pfi_faultaddr) { 420 if (++pfi->pfi_repeats > 4) { 421 tlb_asid_t asid = tlb_get_asid(); 422 pt_entry_t *ptep = pfi->pfi_faultptep; 423 printf("trap: fault #%u (%s/%s) for %#" 424 PRIxVADDR" (%#"PRIxVADDR") at pc %#" 425 PRIxVADDR" curpid=%u/%u ptep@%p=%#" 426 PRIxPTE")\n", pfi->pfi_repeats, 427 trap_names[TRAPTYPE(cause)], 428 trap_names[pfi->pfi_faulttype], va, 429 vaddr, pc, map->pmap->pm_pai[0].pai_asid, 430 asid, ptep, ptep ? pte_value(*ptep) : 0); 431 if (pfi->pfi_repeats >= 4) { 432 cpu_Debugger(); 433 } else { 434 pfi->pfi_faulttype = TRAPTYPE(cause); 435 } 436 } 437 } else { 438 pfi->pfi_lastpid = p->p_pid; 439 pfi->pfi_faultaddr = va; 440 pfi->pfi_repeats = 0; 441 pfi->pfi_faultptep = NULL; 442 pfi->pfi_faulttype = TRAPTYPE(cause); 443 } 444#endif /* PMAP_FAULTINFO */ 445 446 onfault = pcb->pcb_onfault; 447 pcb->pcb_onfault = NULL; 448 rv = uvm_fault(map, va, ftype); 449 pcb->pcb_onfault = onfault; 450 451#if defined(VMFAULT_TRACE) 452 if (!KERNLAND_P(va)) 453 printf( 454 "uvm_fault(%p (pmap %p), %#"PRIxVADDR 455 " (%"PRIxVADDR"), %d) -> %d at pc %#"PRIxVADDR"\n", 456 map, vm->vm_map.pmap, va, vaddr, ftype, rv, pc); 457#endif 458 /* 459 * If this was a stack access we keep track of the maximum 460 * accessed stack size. Also, if vm_fault gets a protection 461 * failure it is due to accessing the stack region outside 462 * the current limit and we need to reflect that as an access 463 * error. 464 */ 465 if ((void *)va >= vm->vm_maxsaddr) { 466 if (rv == 0) 467 uvm_grow(p, va); 468 else if (rv == EACCES) 469 rv = EFAULT; 470 } 471 if (rv == 0) { 472#ifdef PMAP_FAULTINFO 473 if (pfi->pfi_repeats == 0) { 474 pfi->pfi_faultptep = 475 pmap_pte_lookup(map->pmap, va); 476 } 477 KASSERT(*(pt_entry_t *)pfi->pfi_faultptep); 478#endif 479 if (type & T_USER) { 480 userret(l); 481 } 482 return; /* GEN */ 483 } 484 if ((type & T_USER) == 0) 485 goto copyfault; 486 487 KSI_INIT_TRAP(&ksi); 488 switch (rv) { 489 case EINVAL: 490 ksi.ksi_signo = SIGBUS; 491 ksi.ksi_code = BUS_ADRERR; 492 break; 493 case EACCES: 494 ksi.ksi_signo = SIGSEGV; 495 ksi.ksi_code = SEGV_ACCERR; 496 break; 497 case ENOMEM: 498 ksi.ksi_signo = SIGKILL; 499 printf("UVM: pid %d.%d (%s), uid %d killed: " 500 "out of swap\n", p->p_pid, l->l_lid, p->p_comm, 501 l->l_cred ? kauth_cred_geteuid(l->l_cred) : -1); 502 break; 503 default: 504 ksi.ksi_signo = SIGSEGV; 505 ksi.ksi_code = SEGV_MAPERR; 506 break; 507 } 508 ksi.ksi_trap = type & ~T_USER; 509 ksi.ksi_addr = (void *)vaddr; 510 break; /* SIGNAL */ 511 } 512 kernelfault: { 513 onfault = pcb->pcb_onfault; 514 515 pcb->pcb_onfault = NULL; 516 rv = uvm_fault(kernel_map, trunc_page(vaddr), ftype); 517 pcb->pcb_onfault = onfault; 518 if (rv == 0) 519 return; /* KERN */ 520 goto copyfault; 521 } 522 case T_ADDR_ERR_LD: /* misaligned access */ 523 case T_ADDR_ERR_ST: /* misaligned access */ 524 case T_BUS_ERR_LD_ST: /* BERR asserted to CPU */ 525 onfault = pcb->pcb_onfault; 526 rv = EFAULT; 527 copyfault: 528 if (onfault == NULL) { 529 goto dopanic; 530 } 531 tf->tf_regs[_R_PC] = (intptr_t)onfault; 532 tf->tf_regs[_R_V0] = rv; 533 return; /* KERN */ 534 535 case T_ADDR_ERR_LD+T_USER: /* misaligned or kseg access */ 536 case T_ADDR_ERR_ST+T_USER: /* misaligned or kseg access */ 537 case T_BUS_ERR_IFETCH+T_USER: /* BERR asserted to CPU */ 538 case T_BUS_ERR_LD_ST+T_USER: /* BERR asserted to CPU */ 539 ksi.ksi_trap = type & ~T_USER; 540 ksi.ksi_addr = (void *)vaddr; 541 if (KERNLAND_P(vaddr)) { 542 ksi.ksi_signo = SIGSEGV; 543 ksi.ksi_code = SEGV_MAPERR; 544 } else { 545 ksi.ksi_signo = SIGBUS; 546 if (type == T_BUS_ERR_IFETCH+T_USER 547 || type == T_BUS_ERR_LD_ST+T_USER) 548 ksi.ksi_code = BUS_OBJERR; 549 else 550 ksi.ksi_code = BUS_ADRALN; 551 } 552 break; /* SIGNAL */ 553 554 case T_BREAK: 555#ifdef KDTRACE_HOOKS 556 if ((dtrace_invop_jump_addr != NULL) && 557 (dtrace_invop_jump_addr(tf) == 0)) { 558 return; 559 } 560#endif /* KDTRACE_HOOKS */ 561 /* FALLTHROUGH */ 562 case T_WATCH: 563#if defined(DDB) 564 kdb_trap(type, &tf->tf_registers); 565 return; /* KERN */ 566#elif defined(KGDB) 567 { 568 extern mips_reg_t kgdb_cause, kgdb_vaddr; 569 struct reg *regs = &ddb_regs; 570 kgdb_cause = cause; 571 kgdb_vaddr = vaddr; 572 573 /* 574 * init global ddb_regs, used in db_interface.c routines 575 * shared between ddb and gdb. Send ddb_regs to gdb so 576 * that db_machdep.h macros will work with it, and 577 * allow gdb to alter the PC. 578 */ 579 db_set_ddb_regs(type, &tf->tf_registers); 580 PC_BREAK_ADVANCE(regs); 581 if (!kgdb_trap(type, regs)) 582 printf("kgdb: ignored %s\n", 583 trap_names[TRAPTYPE(cause)]); 584 else 585 tf->tf_regs[_R_PC] = regs->r_regs[_R_PC]; 586 587 return; 588 } 589#else 590 goto dopanic; 591#endif 592 case T_BREAK+T_USER: { 593 /* compute address of break instruction */ 594 vaddr_t va = pc + (cause & MIPS_CR_BR_DELAY ? sizeof(int) : 0); 595 596 /* read break instruction */ 597 instr = mips_ufetch32((void *)va); 598 insn.word = instr; 599 600 if (l->l_md.md_ss_addr != va || instr != MIPS_BREAK_SSTEP) { 601 bool advance_pc = false; 602 603 ksi.ksi_trap = type & ~T_USER; 604 ksi.ksi_signo = SIGTRAP; 605 ksi.ksi_addr = (void *)va; 606 ksi.ksi_code = TRAP_BRKPT; 607 608 if ((insn.JType.op == OP_SPECIAL) && 609 (insn.RType.func == OP_BREAK)) { 610 int code = (insn.RType.rs << 5) | insn.RType.rt; 611 switch (code) { 612 case 0: 613 /* we broke, skip it to avoid infinite loop */ 614 advance_pc = true; 615 break; 616 case MIPS_BREAK_INTOVERFLOW: 617 ksi.ksi_signo = SIGFPE; 618 ksi.ksi_code = FPE_INTOVF; 619 advance_pc = true; 620 break; 621 case MIPS_BREAK_INTDIVZERO: 622 ksi.ksi_signo = SIGFPE; 623 ksi.ksi_code = FPE_INTDIV; 624 advance_pc = true; 625 break; 626 default: 627 /* do nothing */ 628 break; 629 } 630 } 631 632 if (advance_pc) 633 tf->tf_regs[_R_PC] += 4; 634 break; 635 } 636 /* 637 * Restore original instruction and clear BP 638 */ 639 rv = mips_ustore32_isync((void *)va, l->l_md.md_ss_instr); 640 if (rv != 0) { 641 vaddr_t sa, ea; 642 sa = trunc_page(va); 643 ea = round_page(va + sizeof(int) - 1); 644 rv = uvm_map_protect(&p->p_vmspace->vm_map, 645 sa, ea, VM_PROT_ALL, false); 646 if (rv == 0) { 647 rv = mips_ustore32_isync((void *)va, 648 l->l_md.md_ss_instr); 649 (void)uvm_map_protect(&p->p_vmspace->vm_map, 650 sa, ea, VM_PROT_READ|VM_PROT_EXECUTE, false); 651 } 652 } 653 mips_icache_sync_all(); /* XXXJRT -- necessary? */ 654 mips_dcache_wbinv_all(); /* XXXJRT -- necessary? */ 655 656 if (rv != 0) 657 printf("Warning: can't restore instruction" 658 " at %#"PRIxVADDR": 0x%x\n", 659 l->l_md.md_ss_addr, l->l_md.md_ss_instr); 660 l->l_md.md_ss_addr = 0; 661 ksi.ksi_trap = type & ~T_USER; 662 ksi.ksi_signo = SIGTRAP; 663 ksi.ksi_addr = (void *)va; 664 ksi.ksi_code = TRAP_TRACE; 665 break; /* SIGNAL */ 666 } 667 case T_DSP+T_USER: 668#if (MIPS32R2 + MIPS64R2) > 0 669 if (MIPS_HAS_DSP) { 670 dsp_load(); 671 userret(l); 672 return; /* GEN */ 673 } 674#endif /* (MIPS32R3 + MIPS64R2) > 0 */ 675 /* FALLTHROUGH */ 676 case T_RES_INST+T_USER: 677 case T_COP_UNUSABLE+T_USER: 678#if !defined(FPEMUL) && !defined(NOFPU) 679 if (__SHIFTOUT(cause, MIPS_CR_COP_ERR) == MIPS_CR_COP_ERR_CU1) { 680 fpu_load(); /* load FPA */ 681 } else 682#endif 683 { 684 mips_emul_inst(status, cause, pc, utf); 685 } 686 userret(l); 687 return; /* GEN */ 688 case T_FPE+T_USER: 689#if defined(FPEMUL) 690 mips_emul_inst(status, cause, pc, utf); 691#elif !defined(NOFPU) 692 utf->tf_regs[_R_CAUSE] = cause; 693 mips_fpu_trap(pc, utf); 694#endif 695 userret(l); 696 return; /* GEN */ 697 case T_OVFLOW+T_USER: 698 case T_TRAP+T_USER: { 699 /* compute address of trap/faulting instruction */ 700 vaddr_t va = pc + (cause & MIPS_CR_BR_DELAY ? sizeof(int) : 0); 701 bool advance_pc = false; 702 703 /* read break instruction */ 704 instr = mips_ufetch32((void *)va); 705 insn.word = instr; 706 707 ksi.ksi_trap = type & ~T_USER; 708 ksi.ksi_signo = SIGFPE; 709 ksi.ksi_addr = (void *)(intptr_t)pc /*utf->tf_regs[_R_PC]*/; 710 ksi.ksi_code = FPE_FLTOVF; /* XXX */ 711 712 if ((insn.JType.op == OP_SPECIAL) && 713 (insn.RType.func == OP_TEQ)) { 714 int code = (insn.RType.rd << 5) | insn.RType.shamt; 715 switch (code) { 716 case MIPS_BREAK_INTOVERFLOW: 717 ksi.ksi_code = FPE_INTOVF; 718 advance_pc = true; 719 break; 720 case MIPS_BREAK_INTDIVZERO: 721 ksi.ksi_code = FPE_INTDIV; 722 advance_pc = true; 723 break; 724 } 725 } 726 727 /* XXX when else do we advance the PC? */ 728 if (advance_pc) 729 tf->tf_regs[_R_PC] += 4; 730 break; /* SIGNAL */ 731 } 732 } 733 utf->tf_regs[_R_CAUSE] = cause; 734 utf->tf_regs[_R_BADVADDR] = vaddr; 735 SIGDEBUG(utf, &ksi, rv, pc); 736 (*p->p_emul->e_trapsignal)(l, &ksi); 737 if ((type & T_USER) == 0) { 738#ifdef DDB 739 Debugger(); 740#endif 741 panic("trapsignal"); 742 } 743 userret(l); 744 return; 745} 746 747/* 748 * Handle asynchronous software traps. 749 * This is called from MachUserIntr() either to deliver signals or 750 * to make involuntary context switch (preemption). 751 */ 752void 753ast(void) 754{ 755 struct lwp * const l = curlwp; 756 u_int astpending; 757 758 while ((astpending = l->l_md.md_astpending) != 0) { 759 //curcpu()->ci_data.cpu_nast++; 760 l->l_md.md_astpending = 0; 761 762#ifdef MULTIPROCESSOR 763 { 764 kpreempt_disable(); 765 struct cpu_info * const ci = l->l_cpu; 766 if (ci->ci_tlb_info->ti_synci_page_bitmap != 0) 767 pmap_tlb_syncicache_ast(ci); 768 kpreempt_enable(); 769 } 770#endif 771 772 if (l->l_pflag & LP_OWEUPC) { 773 l->l_pflag &= ~LP_OWEUPC; 774 ADDUPROF(l); 775 } 776 777 userret(l); 778 779 if (l->l_cpu->ci_want_resched) { 780 /* 781 * We are being preempted. 782 */ 783 preempt(); 784 } 785 } 786} 787 788 789/* XXX need to rewrite ancient comment XXX 790 * This routine is called by procxmt() to single step one instruction. 791 * We do this by storing a break instruction after the current instruction, 792 * resuming execution, and then restoring the old instruction. 793 */ 794int 795mips_singlestep(struct lwp *l) 796{ 797 struct trapframe * const tf = l->l_md.md_utf; 798 struct proc * const p = l->l_proc; 799 vaddr_t pc, va; 800 int rv; 801 802 if (l->l_md.md_ss_addr) { 803 printf("SS %s (%d): breakpoint already set at %#"PRIxVADDR"\n", 804 p->p_comm, p->p_pid, l->l_md.md_ss_addr); 805 return EFAULT; 806 } 807 pc = (vaddr_t)tf->tf_regs[_R_PC]; 808 if (mips_ufetch32((void *)pc) != 0) { /* not a NOP instruction */ 809 struct pcb * const pcb = lwp_getpcb(l); 810 va = mips_emul_branch(tf, pc, PCB_FSR(pcb), true); 811 } else { 812 va = pc + sizeof(int); 813 } 814 815 /* 816 * We can't single-step into a RAS. Check if we're in 817 * a RAS, and set the breakpoint just past it. 818 */ 819 if (p->p_raslist != NULL) { 820 while (ras_lookup(p, (void *)va) != (void *)-1) 821 va += sizeof(int); 822 } 823 824 l->l_md.md_ss_addr = va; 825 l->l_md.md_ss_instr = mips_ufetch32((void *)va); 826 rv = mips_ustore32_isync((void *)va, MIPS_BREAK_SSTEP); 827 if (rv != 0) { 828 vaddr_t sa, ea; 829 sa = trunc_page(va); 830 ea = round_page(va + sizeof(int) - 1); 831 rv = uvm_map_protect(&p->p_vmspace->vm_map, 832 sa, ea, VM_PROT_ALL, false); 833 if (rv == 0) { 834 rv = mips_ustore32_isync((void *)va, 835 MIPS_BREAK_SSTEP); 836 (void)uvm_map_protect(&p->p_vmspace->vm_map, 837 sa, ea, VM_PROT_READ|VM_PROT_EXECUTE, false); 838 } 839 } 840#if 0 841 printf("SS %s (%d): breakpoint set at %x: %x (pc %x) br %x\n", 842 p->p_comm, p->p_pid, p->p_md.md_ss_addr, 843 p->p_md.md_ss_instr, pc, mips_ufetch32((void *)va)); /* XXX */ 844#endif 845 return 0; 846} 847 848#ifdef TRAP_SIGDEBUG 849static void 850frame_dump(const struct trapframe *tf, struct pcb *pcb) 851{ 852 853 printf("trapframe %p\n", tf); 854 printf("ast %#018lx v0 %#018lx v1 %#018lx\n", 855 tf->tf_regs[_R_AST], tf->tf_regs[_R_V0], tf->tf_regs[_R_V1]); 856 printf(" a0 %#018lx a1 %#018lx a2 %#018lx\n", 857 tf->tf_regs[_R_A0], tf->tf_regs[_R_A1], tf->tf_regs[_R_A2]); 858#if defined(__mips_n32) || defined(__mips_n64) 859 printf(" a3 %#018lx a4 %#018lx a5 %#018lx\n", 860 tf->tf_regs[_R_A3], tf->tf_regs[_R_A4], tf->tf_regs[_R_A5]); 861 printf(" a6 %#018lx a7 %#018lx t0 %#018lx\n", 862 tf->tf_regs[_R_A6], tf->tf_regs[_R_A7], tf->tf_regs[_R_T0]); 863 printf(" t1 %#018lx t2 %#018lx t3 %#018lx\n", 864 tf->tf_regs[_R_T1], tf->tf_regs[_R_T2], tf->tf_regs[_R_T3]); 865#else 866 printf(" a3 %#018lx t0 %#018lx t1 %#018lx\n", 867 tf->tf_regs[_R_A3], tf->tf_regs[_R_T0], tf->tf_regs[_R_T1]); 868 printf(" t2 %#018lx t3 %#018lx t4 %#018lx\n", 869 tf->tf_regs[_R_T2], tf->tf_regs[_R_T3], tf->tf_regs[_R_T4]); 870 printf(" t5 %#018lx t6 %#018lx t7 %#018lx\n", 871 tf->tf_regs[_R_T5], tf->tf_regs[_R_T6], tf->tf_regs[_R_T7]); 872#endif 873 printf(" s0 %#018lx s1 %#018lx s2 %#018lx\n", 874 tf->tf_regs[_R_S0], tf->tf_regs[_R_S1], tf->tf_regs[_R_S2]); 875 printf(" s3 %#018lx s4 %#018lx s5 %#018lx\n", 876 tf->tf_regs[_R_S3], tf->tf_regs[_R_S4], tf->tf_regs[_R_S5]); 877 printf(" s6 %#018lx s7 %#018lx t8 %#018lx\n", 878 tf->tf_regs[_R_S6], tf->tf_regs[_R_S7], tf->tf_regs[_R_T8]); 879 printf(" t9 %#018lx k0 %#018lx k1 %#018lx\n", 880 tf->tf_regs[_R_T9], tf->tf_regs[_R_K0], tf->tf_regs[_R_K1]); 881 printf(" gp %#018lx sp %#018lx s8 %#018lx\n", 882 tf->tf_regs[_R_GP], tf->tf_regs[_R_SP], tf->tf_regs[_R_S8]); 883 printf(" ra %#018lx sr %#018lx pc %#018lx\n", 884 tf->tf_regs[_R_RA], tf->tf_regs[_R_SR], tf->tf_regs[_R_PC]); 885 printf(" mullo %#018lx mulhi %#018lx\n", 886 tf->tf_regs[_R_MULLO], tf->tf_regs[_R_MULHI]); 887 printf(" badvaddr %#018lx cause %#018lx\n", 888 tf->tf_regs[_R_BADVADDR], tf->tf_regs[_R_CAUSE]); 889 printf("\n"); 890 hexdump(printf, "Stack dump", tf, 256); 891} 892 893static void 894sigdebug(const struct trapframe *tf, const ksiginfo_t *ksi, int e, 895 vaddr_t pc) 896{ 897 struct lwp *l = curlwp; 898 struct proc *p = l->l_proc; 899 900 printf("pid %d.%d (%s): signal %d code=%d (trap %#lx) " 901 "@pc %#lx addr %#lx error=%d\n", 902 p->p_pid, l->l_lid, p->p_comm, ksi->ksi_signo, ksi->ksi_code, 903 tf->tf_regs[_R_CAUSE], (unsigned long)pc, tf->tf_regs[_R_BADVADDR], 904 e); 905 frame_dump(tf, lwp_getpcb(l)); 906} 907#endif /* TRAP_SIGDEBUG */ 908