1 /* $NetBSD: trap.c,v 1.73 2021/09/25 19:16:31 tsutsui Exp $ */ 2 3 /* 4 * Copyright (c) 1988 University of Utah. 5 * Copyright (c) 1982, 1986, 1990, 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. 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.37 92/12/20$ 37 * 38 * @(#)trap.c 8.5 (Berkeley) 1/4/94 39 */ 40 41 #include <sys/cdefs.h> 42 __KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.73 2021/09/25 19:16:31 tsutsui Exp $"); 43 44 #include "opt_ddb.h" 45 #include "opt_execfmt.h" 46 #include "opt_kgdb.h" 47 #include "opt_compat_sunos.h" 48 #include "opt_m68k_arch.h" 49 50 #include <sys/param.h> 51 #include <sys/systm.h> 52 #include <sys/proc.h> 53 #include <sys/acct.h> 54 #include <sys/syscall.h> 55 #include <sys/userret.h> 56 #include <sys/kauth.h> 57 58 #include <m68k/frame.h> 59 #include <m68k/cacheops.h> 60 61 #include <machine/cpu.h> 62 #include <machine/db_machdep.h> 63 #include <machine/pcb.h> 64 #include <machine/reg.h> 65 #include <machine/trap.h> 66 67 #include <uvm/uvm_extern.h> 68 69 #include <dev/cons.h> 70 71 #ifdef COMPAT_SUNOS 72 #include <compat/sunos/sunos_exec.h> 73 #include <compat/sunos/sunos_syscall.h> 74 #endif 75 76 void trap(struct frame *fp, int type, u_int code, u_int v); 77 78 #ifdef DEBUG 79 void dumpssw(u_short); 80 void dumpwb(int, u_short, u_int, u_int); 81 #endif 82 83 static inline void userret(struct lwp *l, struct frame *fp, 84 u_quad_t oticks, u_int faultaddr, int fromtrap); 85 86 int astpending; 87 88 const char *trap_type[] = { 89 "Bus error", 90 "Address error", 91 "Illegal instruction", 92 "Zero divide", 93 "CHK instruction", 94 "TRAPV instruction", 95 "Privilege violation", 96 "Trace trap", 97 "MMU fault", 98 "SSIR trap", 99 "Format error", 100 "68881 exception", 101 "Coprocessor violation", 102 "Async system trap" 103 }; 104 const int trap_types = sizeof trap_type / sizeof trap_type[0]; 105 106 /* 107 * Size of various exception stack frames (minus the standard 8 bytes) 108 */ 109 short exframesize[] = { 110 FMT0SIZE, /* type 0 - normal (68020/030/040/060) */ 111 FMT1SIZE, /* type 1 - throwaway (68020/030/040) */ 112 FMT2SIZE, /* type 2 - normal 6-word (68020/030/040/060) */ 113 FMT3SIZE, /* type 3 - FP post-instruction (68040/060) */ 114 FMT4SIZE, /* type 4 - access error/fp disabled (68060) */ 115 -1, -1, /* type 5-6 - undefined */ 116 FMT7SIZE, /* type 7 - access error (68040) */ 117 58, /* type 8 - bus fault (68010) */ 118 FMT9SIZE, /* type 9 - coprocessor mid-instruction (68020/030) */ 119 FMTASIZE, /* type A - short bus fault (68020/030) */ 120 FMTBSIZE, /* type B - long bus fault (68020/030) */ 121 -1, -1, -1, -1 /* type C-F - undefined */ 122 }; 123 124 #ifdef M68060 125 #define KDFAULT_060(c) (cputype == CPU_68060 && ((c) & FSLW_TM_SV)) 126 #define WRFAULT_060(c) (cputype == CPU_68060 && ((c) & FSLW_RW_W)) 127 #else 128 #define KDFAULT_060(c) 0 129 #define WRFAULT_060(c) 0 130 #endif 131 132 #ifdef M68040 133 #define KDFAULT_040(c) (cputype == CPU_68040 && \ 134 ((c) & SSW4_TMMASK) == SSW4_TMKD) 135 #define WRFAULT_040(c) (cputype == CPU_68040 && \ 136 ((c) & (SSW4_LK|SSW4_RW)) != SSW4_RW) 137 #else 138 #define KDFAULT_040(c) 0 139 #define WRFAULT_040(c) 0 140 #endif 141 142 #if defined(M68030) || defined(M68020) 143 #define KDFAULT_OTH(c) (cputype <= CPU_68030 && \ 144 ((c) & (SSW_DF|SSW_FCMASK)) == (SSW_DF|FC_SUPERD)) 145 #define WRFAULT_OTH(c) (cputype <= CPU_68030 && \ 146 (((c) & SSW_DF) != 0 && \ 147 ((((c) & SSW_RW) == 0) || (((c) & SSW_RM) != 0)))) 148 #else 149 #define KDFAULT_OTH(c) 0 150 #define WRFAULT_OTH(c) 0 151 #endif 152 153 #define KDFAULT(c) (KDFAULT_060(c) || KDFAULT_040(c) || KDFAULT_OTH(c)) 154 #define WRFAULT(c) (WRFAULT_060(c) || WRFAULT_040(c) || WRFAULT_OTH(c)) 155 156 #ifdef DEBUG 157 int mmudebug = 0; 158 int mmupid = -1; 159 #define MDB_FOLLOW 1 160 #define MDB_WBFOLLOW 2 161 #define MDB_WBFAILED 4 162 #define MDB_ISPID(p) ((p) == mmupid) 163 #endif 164 165 /* 166 * trap and syscall both need the following work done before returning 167 * to user mode. 168 */ 169 static inline void 170 userret(struct lwp *l, struct frame *fp, u_quad_t oticks, 171 u_int faultaddr, int fromtrap) 172 { 173 struct proc *p = l->l_proc; 174 #ifdef M68040 175 int sig; 176 int beenhere = 0; 177 178 again: 179 #endif 180 /* Invoke MI userret code */ 181 mi_userret(l); 182 183 /* 184 * If profiling, charge system time to the trapped pc. 185 */ 186 if (p->p_stflag & PST_PROFIL) { 187 extern int psratio; 188 189 addupc_task(l, fp->f_pc, 190 (int)(p->p_sticks - oticks) * psratio); 191 } 192 #ifdef M68040 193 /* 194 * Deal with user mode writebacks (from trap, or from sigreturn). 195 * If any writeback fails, go back and attempt signal delivery. 196 * unless we have already been here and attempted the writeback 197 * (e.g. bad address with user ignoring SIGSEGV). In that case 198 * we just return to the user without successfully completing 199 * the writebacks. Maybe we should just drop the sucker? 200 */ 201 if (cputype == CPU_68040 && fp->f_format == FMT7) { 202 if (beenhere) { 203 #ifdef DEBUG 204 if (mmudebug & MDB_WBFAILED) 205 printf(fromtrap ? 206 "pid %d(%s): writeback aborted, pc=%x, fa=%x\n" : 207 "pid %d(%s): writeback aborted in sigreturn, pc=%x\n", 208 p->p_pid, p->p_comm, fp->f_pc, faultaddr); 209 #endif 210 } else if ((sig = m68040_writeback(fp, fromtrap))) { 211 ksiginfo_t ksi; 212 beenhere = 1; 213 oticks = p->p_sticks; 214 (void)memset(&ksi, 0, sizeof(ksi)); 215 ksi.ksi_signo = sig; 216 ksi.ksi_addr = (void *)faultaddr; 217 ksi.ksi_code = BUS_OBJERR; 218 trapsignal(l, &ksi); 219 goto again; 220 } 221 } 222 #endif 223 } 224 225 /* 226 * Used by the common m68k syscall() and child_return() functions. 227 * XXX: Temporary until all m68k ports share common trap()/userret() code. 228 */ 229 void machine_userret(struct lwp *, struct frame *, u_quad_t); 230 231 void 232 machine_userret(struct lwp *l, struct frame *f, u_quad_t t) 233 { 234 235 userret(l, f, t, 0, 0); 236 } 237 238 /* 239 * Trap is called from locore to handle most types of processor traps, 240 * including events such as simulated software interrupts/AST's. 241 * System calls are broken out for efficiency. 242 */ 243 /*ARGSUSED*/ 244 void 245 trap(struct frame *fp, int type, u_int code, u_int v) 246 { 247 struct lwp *l; 248 struct proc *p; 249 struct pcb *pcb; 250 void *onfault; 251 ksiginfo_t ksi; 252 int s; 253 int rv; 254 u_quad_t sticks = 0 /* XXX initializer works around compiler bug */; 255 256 curcpu()->ci_data.cpu_ntrap++; 257 l = curlwp; 258 p = l->l_proc; 259 pcb = lwp_getpcb(l); 260 261 KSI_INIT_TRAP(&ksi); 262 ksi.ksi_trap = type & ~T_USER; 263 264 if (USERMODE(fp->f_sr)) { 265 type |= T_USER; 266 sticks = p->p_sticks; 267 l->l_md.md_regs = fp->f_regs; 268 LWP_CACHE_CREDS(l, p); 269 } 270 switch (type) { 271 272 default: 273 dopanic: 274 printf("trap type %d, code = 0x%x, v = 0x%x\n", type, code, v); 275 printf("%s program counter = 0x%x\n", 276 (type & T_USER) ? "user" : "kernel", fp->f_pc); 277 /* 278 * Let the kernel debugger see the trap frame that 279 * caused us to panic. This is a convenience so 280 * one can see registers at the point of failure. 281 */ 282 s = splhigh(); 283 #ifdef KGDB 284 /* If connected, step or cont returns 1 */ 285 if (kgdb_trap(type, fp)) 286 goto kgdb_cont; 287 #endif 288 #ifdef DDB 289 (void)kdb_trap(type, (db_regs_t *)fp); 290 #endif 291 #ifdef KGDB 292 kgdb_cont: 293 #endif 294 splx(s); 295 if (panicstr) { 296 printf("trap during panic!\n"); 297 #ifdef DEBUG 298 /* XXX should be a machine-dependent hook */ 299 printf("(press a key)\n"); 300 cnpollc(1); 301 (void)cngetc(); 302 cnpollc(0); 303 #endif 304 } 305 regdump((struct trapframe *)fp, 128); 306 type &= ~T_USER; 307 if ((u_int)type < trap_types) 308 panic(trap_type[type]); 309 panic("trap"); 310 311 case T_BUSERR: /* kernel bus error */ 312 onfault = pcb->pcb_onfault; 313 if (onfault == NULL) 314 goto dopanic; 315 rv = EFAULT; 316 /* FALLTHROUGH */ 317 318 copyfault: 319 /* 320 * If we have arranged to catch this fault in any of the 321 * copy to/from user space routines, set PC to return to 322 * indicated location and set flag informing buserror code 323 * that it may need to clean up stack frame. 324 */ 325 fp->f_stackadj = exframesize[fp->f_format]; 326 fp->f_format = fp->f_vector = 0; 327 fp->f_pc = (int)onfault; 328 fp->f_regs[D0] = rv; 329 return; 330 331 case T_BUSERR|T_USER: /* bus error */ 332 case T_ADDRERR|T_USER: /* address error */ 333 ksi.ksi_addr = (void *)v; 334 ksi.ksi_signo = SIGBUS; 335 ksi.ksi_code = (type == (T_BUSERR|T_USER)) ? 336 BUS_OBJERR : BUS_ADRERR; 337 break; 338 339 case T_COPERR: /* kernel coprocessor violation */ 340 case T_FMTERR|T_USER: /* do all RTE errors come in as T_USER? */ 341 case T_FMTERR: /* ...just in case... */ 342 /* 343 * The user has most likely trashed the RTE or FP state info 344 * in the stack frame of a signal handler. 345 */ 346 printf("pid %d: kernel %s exception\n", p->p_pid, 347 type==T_COPERR ? "coprocessor" : "format"); 348 type |= T_USER; 349 350 mutex_enter(p->p_lock); 351 SIGACTION(p, SIGILL).sa_handler = SIG_DFL; 352 sigdelset(&p->p_sigctx.ps_sigignore, SIGILL); 353 sigdelset(&p->p_sigctx.ps_sigcatch, SIGILL); 354 sigdelset(&l->l_sigmask, SIGILL); 355 mutex_exit(p->p_lock); 356 357 ksi.ksi_signo = SIGILL; 358 ksi.ksi_addr = (void *)(int)fp->f_format; 359 /* XXX was ILL_RESAD_FAULT */ 360 ksi.ksi_code = (type == T_COPERR) ? 361 ILL_COPROC : ILL_ILLOPC; 362 break; 363 364 case T_COPERR|T_USER: /* user coprocessor violation */ 365 /* What is a proper response here? */ 366 ksi.ksi_signo = SIGFPE; 367 ksi.ksi_code = FPE_FLTINV; 368 break; 369 370 case T_FPERR|T_USER: /* 68881 exceptions */ 371 /* 372 * We pass along the 68881 status register which locore stashed 373 * in code for us. 374 */ 375 ksi.ksi_signo = SIGFPE; 376 ksi.ksi_code = fpsr2siginfocode(code); 377 break; 378 379 #ifdef M68040 380 case T_FPEMULI|T_USER: /* unimplemented FP instruction */ 381 case T_FPEMULD|T_USER: /* unimplemented FP data type */ 382 /* XXX need to FSAVE */ 383 printf("pid %d(%s): unimplemented FP %s at %x (EA %x)\n", 384 p->p_pid, p->p_comm, 385 fp->f_format == 2 ? "instruction" : "data type", 386 fp->f_pc, fp->f_fmt2.f_iaddr); 387 /* XXX need to FRESTORE */ 388 ksi.ksi_signo = SIGFPE; 389 ksi.ksi_code = FPE_FLTINV; 390 break; 391 #endif 392 393 case T_ILLINST|T_USER: /* illegal instruction fault */ 394 case T_PRIVINST|T_USER: /* privileged instruction fault */ 395 ksi.ksi_addr = (void *)(int)fp->f_format; 396 /* XXX was ILL_PRIVIN_FAULT */ 397 ksi.ksi_signo = SIGILL; 398 ksi.ksi_code = (type == (T_PRIVINST|T_USER)) ? 399 ILL_PRVOPC : ILL_ILLOPC; 400 break; 401 402 case T_ZERODIV|T_USER: /* Divide by zero */ 403 ksi.ksi_addr = (void *)(int)fp->f_format; 404 /* XXX was FPE_INTDIV_TRAP */ 405 ksi.ksi_signo = SIGFPE; 406 ksi.ksi_code = FPE_FLTDIV; 407 break; 408 409 case T_CHKINST|T_USER: /* CHK instruction trap */ 410 ksi.ksi_addr = (void *)(int)fp->f_format; 411 /* XXX was FPE_SUBRNG_TRAP */ 412 ksi.ksi_signo = SIGFPE; 413 break; 414 415 case T_TRAPVINST|T_USER: /* TRAPV instruction trap */ 416 ksi.ksi_addr = (void *)(int)fp->f_format; 417 /* XXX was FPE_INTOVF_TRAP */ 418 ksi.ksi_signo = SIGFPE; 419 break; 420 421 /* 422 * XXX: Trace traps are a nightmare. 423 * 424 * HP-UX uses trap #1 for breakpoints, 425 * NetBSD/m68k uses trap #2, 426 * SUN 3.x uses trap #15, 427 * DDB and KGDB uses trap #15 (for kernel breakpoints; 428 * handled elsewhere). 429 * 430 * NetBSD and HP-UX traps both get mapped by locore.s into T_TRACE. 431 * SUN 3.x traps get passed through as T_TRAP15 and are not really 432 * supported yet. 433 * 434 * XXX: We should never get kernel-mode T_TRAP15 435 * XXX: because locore.s now gives them special treatment. 436 */ 437 case T_TRAP15: /* kernel breakpoint */ 438 #ifdef DEBUG 439 printf("unexpected kernel trace trap, type = %d\n", type); 440 printf("program counter = 0x%x\n", fp->f_pc); 441 #endif 442 fp->f_sr &= ~PSL_T; 443 return; 444 445 case T_TRACE|T_USER: /* user trace trap */ 446 #ifdef COMPAT_SUNOS 447 /* 448 * SunOS uses Trap #2 for a "CPU cache flush". 449 * Just flush the on-chip caches and return. 450 */ 451 if (p->p_emul == &emul_sunos) { 452 ICIA(); 453 DCIU(); 454 return; 455 } 456 #endif 457 /* FALLTHROUGH */ 458 case T_TRACE: /* tracing a trap instruction */ 459 case T_TRAP15|T_USER: /* SUN user trace trap */ 460 fp->f_sr &= ~PSL_T; 461 ksi.ksi_signo = SIGTRAP; 462 break; 463 464 case T_ASTFLT: /* system async trap, cannot happen */ 465 goto dopanic; 466 467 case T_ASTFLT|T_USER: /* user async trap */ 468 astpending = 0; 469 /* T_SSIR is not used on news68k */ 470 if (l->l_pflag & LP_OWEUPC) { 471 l->l_pflag &= ~LP_OWEUPC; 472 ADDUPROF(l); 473 } 474 goto out; 475 476 case T_MMUFLT: /* kernel mode page fault */ 477 case T_MMUFLT|T_USER: /* page fault */ 478 { 479 vaddr_t va; 480 struct vmspace *vm = p->p_vmspace; 481 struct vm_map *map; 482 vm_prot_t ftype; 483 extern struct vm_map *kernel_map; 484 485 onfault = pcb->pcb_onfault; 486 487 #ifdef DEBUG 488 if ((mmudebug & MDB_WBFOLLOW) || MDB_ISPID(p->p_pid)) 489 printf("trap: T_MMUFLT pid=%d, code=%x, v=%x, pc=%x, sr=%x\n", 490 p->p_pid, code, v, fp->f_pc, fp->f_sr); 491 #endif 492 /* 493 * It is only a kernel address space fault iff: 494 * 1. (type & T_USER) == 0 and 495 * 2. pcb_onfault not set or 496 * 3. pcb_onfault set but supervisor space data fault 497 * The last can occur during an exec() copyin where the 498 * argument space is lazy-allocated. 499 */ 500 if ((type & T_USER) == 0 && (onfault == NULL || KDFAULT(code))) 501 map = kernel_map; 502 else { 503 map = vm ? &vm->vm_map : kernel_map; 504 } 505 506 if (WRFAULT(code)) 507 ftype = VM_PROT_WRITE; 508 else 509 ftype = VM_PROT_READ; 510 511 va = trunc_page((vaddr_t)v); 512 513 if (map == kernel_map && va == 0) { 514 printf("trap: bad kernel %s access at 0x%x\n", 515 (ftype & VM_PROT_WRITE) ? "read/write" : 516 "read", v); 517 goto dopanic; 518 } 519 520 pcb->pcb_onfault = NULL; 521 rv = uvm_fault(map, va, ftype); 522 pcb->pcb_onfault = onfault; 523 #ifdef DEBUG 524 if (rv && MDB_ISPID(p->p_pid)) 525 printf("uvm_fault(%p, 0x%lx, 0x%x) -> 0x%x\n", 526 map, va, ftype, rv); 527 #endif 528 /* 529 * If this was a stack access we keep track of the maximum 530 * accessed stack size. Also, if vm_fault gets a protection 531 * failure it is due to accessing the stack region outside 532 * the current limit and we need to reflect that as an access 533 * error. 534 */ 535 if (rv == 0) { 536 if (map != kernel_map && (void *)va >= vm->vm_maxsaddr) 537 uvm_grow(p, va); 538 539 if (type == T_MMUFLT) { 540 #ifdef M68040 541 if (cputype == CPU_68040) 542 (void) m68040_writeback(fp, 1); 543 #endif 544 return; 545 } 546 goto out; 547 } 548 if (rv == EACCES) { 549 ksi.ksi_code = SEGV_ACCERR; 550 rv = EFAULT; 551 } else 552 ksi.ksi_code = SEGV_MAPERR; 553 if (type == T_MMUFLT) { 554 if (onfault) 555 goto copyfault; 556 printf("uvm_fault(%p, 0x%lx, 0x%x) -> 0x%x\n", 557 map, va, ftype, rv); 558 printf(" type %x, code [mmu,,ssw]: %x\n", 559 type, code); 560 goto dopanic; 561 } 562 ksi.ksi_addr = (void *)v; 563 switch (rv) { 564 case ENOMEM: 565 printf("UVM: pid %d (%s), uid %d killed: out of swap\n", 566 p->p_pid, p->p_comm, 567 l->l_cred ? 568 kauth_cred_geteuid(l->l_cred) : -1); 569 ksi.ksi_signo = SIGKILL; 570 break; 571 case EINVAL: 572 ksi.ksi_signo = SIGBUS; 573 ksi.ksi_code = BUS_ADRERR; 574 break; 575 case EACCES: 576 ksi.ksi_signo = SIGSEGV; 577 ksi.ksi_code = SEGV_ACCERR; 578 break; 579 default: 580 ksi.ksi_signo = SIGSEGV; 581 ksi.ksi_code = SEGV_MAPERR; 582 break; 583 } 584 break; 585 } 586 } 587 trapsignal(l, &ksi); 588 if ((type & T_USER) == 0) 589 return; 590 out: 591 userret(l, fp, sticks, v, 1); 592 } 593