1 /* $NetBSD: m68k_trap.c,v 1.11 2026/04/26 12:49:38 thorpej Exp $ */ 2 3 /* 4 * Copyright (c) 1988 University of Utah. 5 * Copyright (c) 1982, 1986, 1990 The Regents of the University of California. 6 * 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.32 91/04/06$ 37 * 38 * @(#)trap.c 7.15 (Berkeley) 8/2/91 39 */ 40 41 #include <sys/cdefs.h> 42 __KERNEL_RCSID(0, "$NetBSD: m68k_trap.c,v 1.11 2026/04/26 12:49:38 thorpej Exp $"); 43 44 #include "opt_ddb.h" 45 #include "opt_kgdb.h" 46 #include "opt_m68k_arch.h" 47 #include "opt_fpu_emulate.h" 48 #include "opt_compat_sunos.h" 49 50 #include <sys/param.h> 51 #include <sys/systm.h> 52 #include <sys/proc.h> 53 #include <sys/userret.h> 54 #include <sys/kauth.h> 55 #include <sys/ras.h> 56 #ifdef KGDB 57 #include <sys/kgdb.h> 58 #endif 59 60 #ifdef DEBUG 61 #include <dev/cons.h> 62 #endif 63 64 #include <uvm/uvm_extern.h> 65 66 #include <m68k/cpu.h> 67 #include <m68k/cacheops.h> 68 69 #include <machine/trap.h> 70 #include <machine/cpu.h> 71 #include <machine/pcb.h> 72 73 #ifdef FPU_EMULATE 74 #include <m68k/fpe/fpu_emulate.h> 75 #endif 76 77 #ifdef DDB 78 #include <machine/db_machdep.h> 79 #include <ddb/db_extern.h> 80 #endif 81 82 #ifdef COMPAT_SUNOS 83 #include <compat/sunos/sunos_syscall.h> 84 #include <compat/sunos/sunos_exec.h> 85 #endif 86 87 void trap(struct frame *, int, u_int, u_int); 88 89 volatile int astpending; 90 91 static const char * const trap_descriptions[] = { 92 [T_BUSERR] = "Bus error", 93 [T_ADDRERR] = "Address error", 94 [T_ILLINST] = "Illegal instruction", 95 [T_ZERODIV] = "Zero divide", 96 [T_CHKINST] = "CHK instruction", 97 [T_TRAPVINST] = "TRAPV instruction", 98 [T_PRIVINST] = "Privilege violation", 99 [T_TRACE] = "Trace trap", 100 [T_MMUFLT] = "MMU fault", 101 [T_FMTERR] = "Format error", 102 [T_FPERR] = "Floating Point exception", 103 [T_COPERR] = "Coprocessor violation", 104 [T_ASTFLT] = "Async system trap", 105 [T_BREAKPOINT] = "Breakpoint trap", 106 [T_FPEMULI] = "FPU instruction", 107 [T_FPEMULD] = "FPU data format", 108 }; 109 static const unsigned int trap_description_count = 110 __arraycount(trap_descriptions); 111 112 const char * 113 trap_desc(int type) 114 { 115 static char typestr[sizeof("trap type XXXXXXXX")]; 116 117 if (type < 0) { 118 return "stray trap"; 119 } else if (type >= trap_description_count || 120 trap_descriptions[type] == NULL) { 121 snprintf(typestr, sizeof(typestr), "trap type %d", type); 122 return typestr; 123 } 124 return trap_descriptions[type]; 125 } 126 127 /* 128 * Size of various exception stack frames (minus the standard 8 bytes) 129 */ 130 const short exframesize[] = { 131 FMT0SIZE, /* type 0 - normal (68020/030/040/060) */ 132 FMT1SIZE, /* type 1 - throwaway (68020/030/040) */ 133 FMT2SIZE, /* type 2 - normal 6-word (68020/030/040/060) */ 134 FMT3SIZE, /* type 3 - FP post-instruction (68040/060) */ 135 FMT4SIZE, /* type 4 - access error/fp disabled (68060) */ 136 -1, -1, /* type 5-6 - undefined */ 137 FMT7SIZE, /* type 7 - access error (68040) */ 138 FMT8SIZE, /* type 8 - bus fault (68010) */ 139 FMT9SIZE, /* type 9 - coprocessor mid-instruction (68020/030) */ 140 FMTASIZE, /* type A - short bus fault (68020/030) */ 141 FMTBSIZE, /* type B - long bus fault (68020/030) */ 142 -1, -1, -1, -1 /* type C-F - undefined */ 143 }; 144 145 #if defined(M68010) 146 #if defined(M68020) || defined(M68030) || defined(M68040) || defined(M68060) 147 /* 148 * We actually could make this "work" by forcing the cputype check 149 * in the 68020/68030 case to be unsigned, but there are other very 150 * practical reasons why we can't mix them anyway, so why bother? 151 */ 152 #error Cannnot mix 68010 with 68020+ 153 #endif 154 155 #define KDFAULT(c) (((c) & (SSW1_IF|SSW1_FCMASK)) == (FC_SUPERD)) 156 #define WRFAULT(c) (((c) & (SSW1_IF|SSW1_DF|SSW1_RW)) == (0)) 157 158 #else /* ! M68010 */ 159 160 #ifdef M68060 161 #if defined(M68020) || defined(M68030) || defined(M68040) 162 #define CPU_IS_60 (cputype == CPU_68060) 163 #else 164 #define CPU_IS_60 1 165 #endif 166 #else 167 #define CPU_IS_60 0 168 #endif 169 170 #ifdef M68040 171 #if defined(M68020) || defined(M68030) || defined(M68060) 172 #define CPU_IS_40 (cputype == CPU_68040) 173 #else 174 #define CPU_IS_40 1 175 #endif 176 #else 177 #define CPU_IS_40 0 178 #endif 179 180 #if defined(M68020) || defined(M68030) 181 #if defined(M68040) || defined(M68060) 182 #define CPU_IS_2030 (cputype <= CPU_68030) 183 #else 184 #define CPU_IS_2030 1 185 #endif 186 #else 187 #define CPU_IS_2030 0 188 #endif 189 190 #define KDFAULT_60(c) (CPU_IS_60 && ((c) & FSLW_TM_SV)) 191 #define WRFAULT_60(c) (CPU_IS_60 && ((c) & FSLW_RW_W)) 192 193 #define KDFAULT_40(c) (CPU_IS_40 && \ 194 ((c) & SSW4_TMMASK) == SSW4_TMKD) 195 #define WRFAULT_40(c) (CPU_IS_40 && \ 196 ((c) & (SSW4_LK|SSW4_RW)) != SSW4_RW) 197 198 #define KDFAULT_2030(c) (CPU_IS_2030 && \ 199 ((c) & (SSW_DF|SSW_FCMASK)) == (SSW_DF|FC_SUPERD)) 200 #define WRFAULT_2030(c) (CPU_IS_2030 && \ 201 (((c) & SSW_DF) != 0 && \ 202 ((((c) & SSW_RW) == 0) || (((c) & SSW_RM) != 0)))) 203 204 #define KDFAULT(c) (KDFAULT_60(c) || KDFAULT_40(c) || KDFAULT_2030(c)) 205 #define WRFAULT(c) (WRFAULT_60(c) || WRFAULT_40(c) || WRFAULT_2030(c)) 206 207 #endif /* M68010 */ 208 209 #ifdef DEBUG 210 int mmudebug = 0; 211 int mmupid = -1; 212 #define MDB_ISPID(pid) ((pid) == mmupid) 213 #define MDB_FOLLOW 1 214 #define MDB_WBFOLLOW 2 215 #define MDB_WBFAILED 4 216 #define MDB_CPFAULT 8 217 #endif 218 219 #ifdef M68040 220 #ifdef DEBUG 221 struct writebackstats { 222 int calls; 223 int cpushes; 224 int move16s; 225 int wb1s, wb2s, wb3s; 226 int wbsize[4]; 227 } wbstats; 228 229 static const char *f7sz[] = { "longword", "byte", "word", "line" }; 230 static const char *f7tt[] = { "normal", "MOVE16", "AFC", "ACK" }; 231 static const char *f7tm[] = { "d-push", "u-data", "u-code", "M-data", 232 "M-code", "k-data", "k-code", "RES" }; 233 static const char wberrstr[] = 234 "WARNING: pid %d(%s) writeback [%s] failed, pc=%x fa=%x wba=%x wbd=%x\n"; 235 236 static void 237 dumpssw(u_short ssw) 238 { 239 printf(" SSW: %x: ", ssw); 240 if (ssw & SSW4_CP) 241 printf("CP,"); 242 if (ssw & SSW4_CU) 243 printf("CU,"); 244 if (ssw & SSW4_CT) 245 printf("CT,"); 246 if (ssw & SSW4_CM) 247 printf("CM,"); 248 if (ssw & SSW4_MA) 249 printf("MA,"); 250 if (ssw & SSW4_ATC) 251 printf("ATC,"); 252 if (ssw & SSW4_LK) 253 printf("LK,"); 254 if (ssw & SSW4_RW) 255 printf("RW,"); 256 printf(" SZ=%s, TT=%s, TM=%s\n", 257 f7sz[(ssw & SSW4_SZMASK) >> 5], 258 f7tt[(ssw & SSW4_TTMASK) >> 3], 259 f7tm[ssw & SSW4_TMMASK]); 260 } 261 262 static void 263 dumpwb(int num, u_short s, u_int a, u_int d) 264 { 265 struct proc *p = curproc; 266 paddr_t pa; 267 268 printf(" writeback #%d: VA %x, data %x, SZ=%s, TT=%s, TM=%s\n", 269 num, a, d, f7sz[(s & SSW4_SZMASK) >> 5], 270 f7tt[(s & SSW4_TTMASK) >> 3], f7tm[s & SSW4_TMMASK]); 271 printf(" PA "); 272 if (pmap_extract(p->p_vmspace->vm_map.pmap, (vaddr_t)a, &pa) == false) 273 printf("<invalid address>"); 274 else { 275 u_long val; 276 if (ufetch_long((void *)a, &val) != 0) 277 val = (u_long)-1; 278 printf("%lx, current value %lx", pa, val); 279 } 280 printf("\n"); 281 } 282 #endif /* DEBUG */ 283 284 /* Because calling memcpy() for 16 bytes is *way* too much overhead ... */ 285 static inline void 286 fastcopy16(u_int *dst, const u_int *src) 287 { 288 *dst++ = *src++; 289 *dst++ = *src++; 290 *dst++ = *src++; 291 *dst = *src; 292 } 293 294 extern int suline(void *, void *); 295 296 int 297 m68040_writeback(struct frame *fp, int docachepush) 298 { 299 struct fmt7 *f = &fp->f_fmt7; 300 struct lwp *l = curlwp; 301 struct proc *p = l->l_proc; 302 struct pcb *pcb = lwp_getpcb(l); 303 int err = 0; 304 u_int fa = 0; 305 void *oonfault = pcb->pcb_onfault; 306 paddr_t pa; 307 308 #ifdef DEBUG 309 if ((mmudebug & MDB_WBFOLLOW) || MDB_ISPID(p->p_pid)) { 310 printf(" pid=%d, fa=%x,", p->p_pid, f->f_fa); 311 dumpssw(f->f_ssw); 312 } 313 wbstats.calls++; 314 #endif 315 /* 316 * Deal with special cases first. 317 */ 318 if ((f->f_ssw & SSW4_TMMASK) == SSW4_TMDCP) { 319 /* 320 * Dcache push fault. 321 * Line-align the address and write out the push data to 322 * the indicated physical address. 323 */ 324 #ifdef DEBUG 325 if ((mmudebug & MDB_WBFOLLOW) || MDB_ISPID(p->p_pid)) { 326 printf(" pushing %s to PA %x, data %x", 327 f7sz[(f->f_ssw & SSW4_SZMASK) >> 5], 328 f->f_fa, f->f_pd0); 329 if ((f->f_ssw & SSW4_SZMASK) == SSW4_SZLN) 330 printf("/%x/%x/%x", 331 f->f_pd1, f->f_pd2, f->f_pd3); 332 printf("\n"); 333 } 334 if (f->f_wb1s & SSW4_WBSV) 335 panic("writeback: cache push with WB1S valid"); 336 wbstats.cpushes++; 337 #endif 338 /* 339 * XXX there are security problems if we attempt to do a 340 * cache push after a signal handler has been called. 341 */ 342 if (docachepush) { 343 pmap_enter(pmap_kernel(), (vaddr_t)vmmap, 344 trunc_page(f->f_fa), VM_PROT_WRITE, 345 VM_PROT_WRITE|PMAP_WIRED); 346 pmap_update(pmap_kernel()); 347 fa = (u_int)&vmmap[m68k_page_offset(f->f_fa) & ~0xF]; 348 fastcopy16((void *)fa, (void *)&f->f_pd0); 349 (void) pmap_extract(pmap_kernel(), (vaddr_t)fa, &pa); 350 DCFL(pa); 351 pmap_remove(pmap_kernel(), (vaddr_t)vmmap, 352 (vaddr_t)&vmmap[PAGE_SIZE]); 353 pmap_update(pmap_kernel()); 354 } else 355 printf("WARNING: pid %d(%s) uid %d: CPUSH not done\n", 356 p->p_pid, p->p_comm, kauth_cred_geteuid(l->l_cred)); 357 } else if ((f->f_ssw & (SSW4_RW|SSW4_TTMASK)) == SSW4_TTM16) { 358 /* 359 * MOVE16 fault. 360 * Line-align the address and write out the push data to 361 * the indicated virtual address. 362 */ 363 #ifdef DEBUG 364 if ((mmudebug & MDB_WBFOLLOW) || MDB_ISPID(p->p_pid)) 365 printf(" MOVE16 to VA %x(%x), data %x/%x/%x/%x\n", 366 f->f_fa, f->f_fa & ~0xF, f->f_pd0, f->f_pd1, 367 f->f_pd2, f->f_pd3); 368 if (f->f_wb1s & SSW4_WBSV) 369 panic("writeback: MOVE16 with WB1S valid"); 370 wbstats.move16s++; 371 #endif 372 if (KDFAULT(f->f_wb1s)) 373 fastcopy16((void *)(f->f_fa & ~0xF), (void *)&f->f_pd0); 374 else 375 err = suline((void *)(f->f_fa & ~0xF), (void *)&f->f_pd0); 376 if (err) { 377 fa = f->f_fa & ~0xF; 378 #ifdef DEBUG 379 if (mmudebug & MDB_WBFAILED) 380 printf(wberrstr, p->p_pid, p->p_comm, 381 "MOVE16", fp->f_pc, f->f_fa, 382 f->f_fa & ~0xF, f->f_pd0); 383 #endif 384 } 385 } else if (f->f_wb1s & SSW4_WBSV) { 386 /* 387 * Writeback #1. 388 * Position the "memory-aligned" data and write it out. 389 */ 390 u_int wb1d = f->f_wb1d; 391 int off; 392 393 #ifdef DEBUG 394 if ((mmudebug & MDB_WBFOLLOW) || MDB_ISPID(p->p_pid)) 395 dumpwb(1, f->f_wb1s, f->f_wb1a, f->f_wb1d); 396 wbstats.wb1s++; 397 wbstats.wbsize[(f->f_wb2s&SSW4_SZMASK)>>5]++; 398 #endif 399 off = (f->f_wb1a & 3) * 8; 400 switch (f->f_wb1s & SSW4_SZMASK) { 401 case SSW4_SZLW: 402 if (off) 403 wb1d = (wb1d >> (32 - off)) | (wb1d << off); 404 if (KDFAULT(f->f_wb1s)) 405 *(long *)f->f_wb1a = wb1d; 406 else 407 err = ustore_long((void *)f->f_wb1a, wb1d); 408 break; 409 case SSW4_SZB: 410 off = 24 - off; 411 if (off) 412 wb1d >>= off; 413 if (KDFAULT(f->f_wb1s)) 414 *(char *)f->f_wb1a = wb1d; 415 else 416 err = ustore_char((void *)f->f_wb1a, wb1d); 417 break; 418 case SSW4_SZW: 419 off = (off + 16) % 32; 420 if (off) 421 wb1d = (wb1d >> (32 - off)) | (wb1d << off); 422 if (KDFAULT(f->f_wb1s)) 423 *(short *)f->f_wb1a = wb1d; 424 else 425 err = ustore_short((void *)f->f_wb1a, wb1d); 426 break; 427 } 428 if (err) { 429 fa = f->f_wb1a; 430 #ifdef DEBUG 431 if (mmudebug & MDB_WBFAILED) 432 printf(wberrstr, p->p_pid, p->p_comm, 433 "#1", fp->f_pc, f->f_fa, 434 f->f_wb1a, f->f_wb1d); 435 #endif 436 } 437 } 438 /* 439 * Deal with the "normal" writebacks. 440 * 441 * XXX writeback2 is known to reflect a LINE size writeback after 442 * a MOVE16 was already dealt with above. Ignore it. 443 */ 444 if (err == 0 && (f->f_wb2s & SSW4_WBSV) && 445 (f->f_wb2s & SSW4_SZMASK) != SSW4_SZLN) { 446 #ifdef DEBUG 447 if ((mmudebug & MDB_WBFOLLOW) || MDB_ISPID(p->p_pid)) 448 dumpwb(2, f->f_wb2s, f->f_wb2a, f->f_wb2d); 449 wbstats.wb2s++; 450 wbstats.wbsize[(f->f_wb2s&SSW4_SZMASK)>>5]++; 451 #endif 452 switch (f->f_wb2s & SSW4_SZMASK) { 453 case SSW4_SZLW: 454 if (KDFAULT(f->f_wb2s)) 455 *(long *)f->f_wb2a = f->f_wb2d; 456 else 457 err = ustore_long((void *)f->f_wb2a, f->f_wb2d); 458 break; 459 case SSW4_SZB: 460 if (KDFAULT(f->f_wb2s)) 461 *(char *)f->f_wb2a = f->f_wb2d; 462 else 463 err = ustore_char((void *)f->f_wb2a, f->f_wb2d); 464 break; 465 case SSW4_SZW: 466 if (KDFAULT(f->f_wb2s)) 467 *(short *)f->f_wb2a = f->f_wb2d; 468 else 469 err = ustore_short((void *)f->f_wb2a, f->f_wb2d); 470 break; 471 } 472 if (err) { 473 fa = f->f_wb2a; 474 #ifdef DEBUG 475 if (mmudebug & MDB_WBFAILED) { 476 printf(wberrstr, p->p_pid, p->p_comm, 477 "#2", fp->f_pc, f->f_fa, 478 f->f_wb2a, f->f_wb2d); 479 dumpssw(f->f_ssw); 480 dumpwb(2, f->f_wb2s, f->f_wb2a, f->f_wb2d); 481 } 482 #endif 483 } 484 } 485 if (err == 0 && (f->f_wb3s & SSW4_WBSV)) { 486 #ifdef DEBUG 487 if ((mmudebug & MDB_WBFOLLOW) || MDB_ISPID(p->p_pid)) 488 dumpwb(3, f->f_wb3s, f->f_wb3a, f->f_wb3d); 489 wbstats.wb3s++; 490 wbstats.wbsize[(f->f_wb3s&SSW4_SZMASK)>>5]++; 491 #endif 492 switch (f->f_wb3s & SSW4_SZMASK) { 493 case SSW4_SZLW: 494 if (KDFAULT(f->f_wb3s)) 495 *(long *)f->f_wb3a = f->f_wb3d; 496 else 497 err = ustore_long((void *)f->f_wb3a, f->f_wb3d); 498 break; 499 case SSW4_SZB: 500 if (KDFAULT(f->f_wb3s)) 501 *(char *)f->f_wb3a = f->f_wb3d; 502 else 503 err = ustore_char((void *)f->f_wb3a, f->f_wb3d); 504 break; 505 case SSW4_SZW: 506 if (KDFAULT(f->f_wb3s)) 507 *(short *)f->f_wb3a = f->f_wb3d; 508 else 509 err = ustore_short((void *)f->f_wb3a, f->f_wb3d); 510 break; 511 #ifdef DEBUG 512 case SSW4_SZLN: 513 panic("writeback: wb3s indicates LINE write"); 514 #endif 515 } 516 if (err) { 517 fa = f->f_wb3a; 518 #ifdef DEBUG 519 if (mmudebug & MDB_WBFAILED) 520 printf(wberrstr, p->p_pid, p->p_comm, 521 "#3", fp->f_pc, f->f_fa, 522 f->f_wb3a, f->f_wb3d); 523 #endif 524 } 525 } 526 pcb->pcb_onfault = oonfault; 527 if (err) 528 err = SIGSEGV; 529 return err; 530 } 531 #endif /* M68040 */ 532 533 /* 534 * This is called by the trap15 and trace trap handlers for 535 * supervisor-mode trace and breakpoint traps. This is separate 536 * from trap() so that breakpoints in trap() will work. 537 * 538 * If we have both DDB and KGDB, let KGDB see it first, because 539 * KGDB will just return 0 if not connected. 540 * 541 * A fallback hook for machine-specific handling is also provided. 542 */ 543 void 544 trap_kdebug(int type, struct trapframe *tf) 545 { 546 #ifdef KGDB 547 /* Let KGDB handle it (if connected) */ 548 if (kgdb_trap(type, tf)) { 549 return; 550 } 551 #endif 552 #ifdef DDB 553 /* Let DDB handle it. */ 554 if (kdb_trap(type, tf)) { 555 return; 556 } 557 #endif 558 #ifdef MACHINE_KDEBUG_TRAP_FALLBACK 559 MACHINE_KDEBUG_TRAP_FALLBACK(type, tf); 560 #else 561 panic("%s trap", type == -1 ? "stray" : "unexpected BPT"); 562 #endif 563 } 564 565 void straytrap(struct trapframe); /* called from badtrap[] */ 566 567 void 568 straytrap(struct trapframe tf) 569 { 570 printf("unexpected trap format=%d vector=0x%x pc=0x%x\n", 571 tf.tf_format, tf.tf_vector, tf.tf_pc); 572 573 trap_kdebug(-1, &tf); 574 } 575 576 /* 577 * trap and syscall both need the following work done before returning 578 * to user mode. 579 * 580 * The 68040 thing here is ugly, but it's intended to optimize it away 581 * on platforms that wouldn't otherwise need to pay the penalty. 582 */ 583 #ifdef M68040 584 #define USERRET(l, fp, ot, fa, ft) userret0((l), (fp), (ot), (fa), (ft)) 585 #else 586 #define USERRET(l, fp, ot, fa, ft) userret0((l), (fp), (ot)) 587 #endif 588 589 static void 590 userret0(struct lwp *l, struct frame *fp, u_quad_t oticks 591 #ifdef M68040 592 , u_int faultaddr, int fromtrap 593 #endif 594 ) 595 { 596 struct proc *p = l->l_proc; 597 #ifdef M68040 598 int sig; 599 int beenhere = 0; 600 601 again: 602 #endif 603 604 /* Invoke MI userret code */ 605 mi_userret(l); 606 607 /* 608 * If profiling, charge system time to the trapped pc. 609 */ 610 if (p->p_stflag & PST_PROFIL) { 611 extern int psratio; 612 613 addupc_task(l, fp->f_pc, 614 (int)(p->p_sticks - oticks) * psratio); 615 } 616 617 #ifdef M68040 618 /* 619 * Deal with user mode writebacks (from trap, or from sigreturn). 620 * If any writeback fails, go back and attempt signal delivery. 621 * unless we have already been here and attempted the writeback 622 * (e.g. bad address with user ignoring SIGSEGV). In that case 623 * we just return to the user without successfully completing 624 * the writebacks. Maybe we should just drop the sucker? 625 */ 626 if (CPU_IS_40 && fp->f_format == FMT7) { 627 if (beenhere) { 628 #ifdef DEBUG 629 if (mmudebug & MDB_WBFAILED) { 630 printf(fromtrap ? 631 "pid %d(%s): writeback aborted, pc=%x, fa=%x\n" : 632 "pid %d(%s): writeback aborted in sigreturn, pc=%x\n", 633 p->p_pid, p->p_comm, fp->f_pc, faultaddr); 634 } 635 #endif 636 } else if ((sig = m68040_writeback(fp, fromtrap))) { 637 ksiginfo_t ksi; 638 beenhere = 1; 639 oticks = p->p_sticks; 640 KSI_INIT_TRAP(&ksi); 641 ksi.ksi_signo = sig; 642 ksi.ksi_addr = (void *)faultaddr; 643 ksi.ksi_code = BUS_OBJERR; 644 trapsignal(l, &ksi); 645 goto again; 646 } 647 } 648 #endif /* M68040 */ 649 } 650 651 void 652 userret(struct lwp *l, struct frame *f, u_quad_t t) 653 { 654 USERRET(l, f, t, 0, 0); 655 } 656 657 label_t *nofault; 658 659 /* 660 * trap() is called by way of the trap stubs (fault[] and faultstkadj[]) 661 * to handle most types of processor traps, including events such as 662 * ASTs. 663 * 664 * System calls have their own fast path. 665 */ 666 void 667 trap(struct frame *fp, int type, unsigned int code, unsigned int v) 668 { 669 struct lwp *l; 670 struct proc *p; 671 struct pcb *pcb; 672 void *onfault; 673 ksiginfo_t ksi; 674 int s; 675 int rv; 676 u_quad_t sticks; 677 static int panicking __diagused; 678 679 curcpu()->ci_data.cpu_ntrap++; 680 l = curlwp; 681 p = l->l_proc; 682 pcb = lwp_getpcb(l); 683 onfault = pcb->pcb_onfault; 684 685 KSI_INIT_TRAP(&ksi); 686 ksi.ksi_trap = type & ~T_USER; 687 688 if (USERMODE(fp->f_sr)) { 689 type |= T_USER; 690 sticks = p->p_sticks; 691 l->l_md.md_regs = fp->f_regs; 692 } else { 693 sticks = 0; 694 /* XXX Detect trap recursion? */ 695 } 696 697 switch (type) { 698 default: 699 dopanic: 700 /* 701 * Let the kernel debugger see the trap frame that 702 * caused us to panic. This is a convenience so 703 * one can see registers at the point of failure. 704 */ 705 s = splhigh(); 706 panicking = 1; 707 printf("trap type=0x%x, code=0x%x, v=0x%x\n", type, code, v); 708 printf("%s pc=0x%x\n", 709 (type & T_USER) ? "user" : "kernel", fp->f_pc); 710 rv = 0; 711 #ifdef KGDB 712 /* If connected, step or cont returns 1 */ 713 rv = kgdb_trap(type, (db_regs_t *)fp)); 714 #endif 715 #ifdef DDB 716 if (rv == 0) { 717 (void)kdb_trap(type, (db_regs_t *)fp); 718 } 719 #endif 720 splx(s); 721 if (panicstr) { 722 printf("trap during panic!\n"); 723 #ifdef DEBUG 724 /* XXX should be a machine-dependent hook */ 725 printf("(press a key)\n"); 726 cnpollc(true); 727 (void)cngetc(); 728 cnpollc(false); 729 #endif 730 } 731 regdump((struct trapframe *)fp, 128); 732 type &= ~T_USER; 733 panic("%s", trap_desc(type)); 734 /* NOTREACHED */ 735 break; 736 737 case T_BUSERR: /* kernel bus error */ 738 if (onfault == NULL) { 739 goto dopanic; 740 } 741 rv = EFAULT; 742 /* FALLTHROUGH */ 743 744 copyfault: 745 /* 746 * If we have arranged to catch this fault in any of the 747 * copy to/from user space routines, set PC to return to 748 * indicated location and set flag informing buserror code 749 * that it may need to clean up stack frame. 750 */ 751 fp->f_stackadj = exframesize[fp->f_format]; 752 fp->f_format = fp->f_vector = 0; 753 fp->f_pc = (int)onfault; 754 fp->f_regs[D0] = rv; 755 goto done; 756 757 case T_BUSERR|T_USER: /* bus error */ 758 case T_ADDRERR|T_USER: /* address error */ 759 ksi.ksi_addr = (void *)v; 760 ksi.ksi_signo = SIGBUS; 761 ksi.ksi_code = (type == (T_BUSERR|T_USER)) ? 762 BUS_OBJERR : BUS_ADRERR; 763 break; 764 765 case T_COPERR: /* kernel coprocessor violation */ 766 case T_FMTERR|T_USER: /* do all RTE errors come in as T_USER? */ 767 case T_FMTERR: /* ...just in case... */ 768 /* 769 * The user has most likely trashed the RTE or FP state info 770 * in the stack frame of a signal handler. 771 */ 772 printf("pid %d: kernel %s exception\n", p->p_pid, 773 type==T_COPERR ? "coprocessor" : "format"); 774 type |= T_USER; 775 776 mutex_enter(p->p_lock); 777 SIGACTION(p, SIGILL).sa_handler = SIG_DFL; 778 sigdelset(&p->p_sigctx.ps_sigignore, SIGILL); 779 sigdelset(&p->p_sigctx.ps_sigcatch, SIGILL); 780 sigdelset(&l->l_sigmask, SIGILL); 781 mutex_exit(p->p_lock); 782 783 ksi.ksi_signo = SIGILL; 784 ksi.ksi_addr = (void *)(int)fp->f_format; 785 /* XXX was ILL_RESAD_FAULT */ 786 ksi.ksi_code = (type == T_COPERR) ? 787 ILL_COPROC : ILL_ILLOPC; 788 break; 789 790 case T_COPERR|T_USER: /* user coprocessor violation */ 791 /* What is a proper response here? */ 792 ksi.ksi_signo = SIGFPE; 793 ksi.ksi_code = FPE_FLTINV; 794 break; 795 796 case T_FPERR|T_USER: /* 68881 exceptions */ 797 /* 798 * We pass along the 68881 status register which the trap stub 799 * helpfully stashed in the code argument slot for us. 800 */ 801 ksi.ksi_signo = SIGFPE; 802 ksi.ksi_code = fpsr2siginfocode(code); 803 break; 804 805 /* 806 * FPU faults in supervisor mode. 807 */ 808 case T_ILLINST: /* fnop generates this, apparently. */ 809 case T_FPEMULI: 810 case T_FPEMULD: 811 /* Check to see if we're probing for the FPU. */ 812 if (nofault) { 813 longjmp(nofault); 814 } 815 if (type == T_ILLINST) { 816 printf("Kernel Illegal Instruction trap.\n"); 817 } else { 818 printf("Kernel FPU trap.\n"); 819 } 820 goto dopanic; 821 822 case T_FPEMULI|T_USER: /* unimplemented FP instruction */ 823 case T_FPEMULD|T_USER: /* unimplemented FP data type */ 824 switch (fputype) { 825 case FPU_NONE: 826 #ifdef FPU_EMULATE 827 if (fpu_emulate(fp, &pcb->pcb_fpregs, &ksi) == 0) { 828 /* XXX Deal with tracing? (f_sr & PSL_T) */; 829 } 830 #else 831 uprintf("pid %d killed: no floating point support\n", 832 p->p_pid); 833 goto illegal_instruction; 834 #endif 835 break; 836 #if defined(M68040) || defined(M68060) 837 case FPU_68040: 838 case FPU_68060: 839 /* XXX need to FSAVE */ 840 printf("pid %d(%s): " 841 "unimplemented FP %s at 0x%x (EA 0x%x)\n", 842 p->p_pid, p->p_comm, 843 fp->f_format == 2 ? "instruction" : "data type", 844 fp->f_pc, fp->f_fmt2.f_iaddr); 845 /* XXX need to FRESTORE */ 846 ksi.ksi_addr = (void *)(int)fp->f_format; 847 ksi.ksi_signo = SIGFPE; 848 ksi.ksi_code = FPE_FLTINV; 849 break; 850 #endif 851 default: 852 goto illegal_instruction; 853 } 854 break; 855 856 case T_ILLINST|T_USER: /* illegal instruction fault */ 857 case T_PRIVINST|T_USER: /* privileged instruction fault */ 858 illegal_instruction: 859 ksi.ksi_addr = (void *)(int)fp->f_format; 860 /* XXX was ILL_PRIVIN_FAULT */ 861 ksi.ksi_signo = SIGILL; 862 ksi.ksi_code = (type == (T_PRIVINST|T_USER)) ? 863 ILL_PRVOPC : ILL_ILLOPC; 864 break; 865 866 case T_ZERODIV|T_USER: /* Integer divide by zero */ 867 ksi.ksi_addr = (void *)(int)fp->f_format; 868 ksi.ksi_signo = SIGFPE; 869 ksi.ksi_code = FPE_INTDIV; 870 break; 871 872 case T_CHKINST|T_USER: /* CHK instruction trap */ 873 ksi.ksi_addr = (void *)(int)fp->f_format; 874 /* XXX was FPE_SUBRNG_TRAP */ 875 ksi.ksi_signo = SIGFPE; 876 break; 877 878 case T_TRAPVINST|T_USER: /* TRAPV instruction trap */ 879 ksi.ksi_addr = (void *)(int)fp->f_format; 880 /* XXX was FPE_INTOVF_TRAP */ 881 ksi.ksi_signo = SIGFPE; 882 break; 883 884 /* 885 * XXX Trace traps are a nightmare. 886 * 887 * HP-UX uses trap #1 for breakpoints, 888 * NetBSD/m68k uses trap #2, 889 * SUN 3.x uses trap #15, 890 * DDB and KGDB uses trap #15 (for kernel breakpoints; 891 * handled elsewhere). 892 * 893 * NetBSD and HP-UX traps both get mapped by the trap stubs into 894 * T_TRACE. SUN 3.x traps get passed through as T_TRAP15 and are 895 * not really supported yet. 896 * 897 * XXX We should never get kernel-mode T_TRAP15 because the 898 * XXX trap stubs now give them special treatment. 899 */ 900 case T_TRAP15: /* kernel breakpoint */ 901 #ifdef DEBUG 902 printf("unexpected kernel trace trap, type = %d\n", type); 903 printf("program counter = 0x%x\n", fp->f_pc); 904 #endif 905 fp->f_sr &= ~PSL_T; 906 goto done; 907 908 case T_TRACE|T_USER: /* user trace trap */ 909 #ifdef COMPAT_SUNOS 910 /* 911 * SunOS uses Trap #2 for a "CPU cache flush". 912 * Just flush the on-chip caches and return. 913 */ 914 if (p->p_emul == &emul_sunos) { 915 #ifndef __mc68010__ 916 ICIA(); 917 DCIU(); 918 #endif /* ! __mc68010__ */ 919 /* get out fast */ 920 goto done; 921 } 922 #endif 923 /* FALLTHROUGH */ 924 case T_TRACE: /* tracing a trap instruction */ 925 case T_TRAP15|T_USER: /* SUN user trace trap */ 926 /* 927 * Don't go stepping into a RAS. 928 */ 929 if (p->p_raslist != NULL && 930 (ras_lookup(p, (void *)fp->f_pc) != (void *)-1)) { 931 goto out; 932 } 933 fp->f_sr &= ~PSL_T; 934 ksi.ksi_addr = (void *)fp->f_pc; 935 ksi.ksi_signo = SIGTRAP; 936 if (type == (T_TRAP15|T_USER)) { 937 ksi.ksi_code = TRAP_BRKPT; 938 } else { 939 ksi.ksi_code = TRAP_TRACE; 940 } 941 break; 942 943 case T_ASTFLT: /* system async trap, cannot happen */ 944 goto dopanic; 945 946 case T_ASTFLT|T_USER: /* user async trap */ 947 astpending = 0; 948 if (l->l_pflag & LP_OWEUPC) { 949 l->l_pflag &= ~LP_OWEUPC; 950 ADDUPROF(l); 951 } 952 goto out; 953 954 case T_MMUFLT: /* kernel mode page fault */ 955 /* Hacks to avoid calling VM code from debugger. */ 956 #ifdef DDB 957 if (db_recover != 0) { 958 goto dopanic; 959 } 960 #endif 961 #ifdef KGDB 962 if (kgdb_recover != 0) { 963 goto dopanic; 964 } 965 #endif 966 /* FALLTHROUGH */ 967 968 case T_MMUFLT|T_USER: /* page fault */ 969 { 970 vaddr_t va; 971 struct vmspace *vm = p->p_vmspace; 972 struct vm_map *map; 973 vm_prot_t ftype; 974 extern struct vm_map *kernel_map; 975 976 onfault = pcb->pcb_onfault; 977 #ifdef DEBUG 978 if ((mmudebug & MDB_WBFOLLOW) || MDB_ISPID(p->p_pid)) { 979 printf("trap: T_MMUFLT " 980 "pid=%d, code=0x%x, v=0x%x, pc=0x%x, sr=0x%x\n", 981 p->p_pid, code, v, fp->f_pc, fp->f_sr); 982 } 983 #endif 984 /* 985 * It is only a kernel address space fault iff: 986 * 1. (type & T_USER) == 0 and 987 * 2. pcb_onfault not set or 988 * 3. pcb_onfault set but supervisor space data fault 989 * The last can occur during an exec() copyin where the 990 * argument space is lazy-allocated. 991 */ 992 if ((type & T_USER) == 0 && 993 (onfault == NULL || KDFAULT(code))) { 994 map = kernel_map; 995 } else { 996 /* XXX KASSERT(vm != NULL)? */ 997 map = vm ? &vm->vm_map : kernel_map; 998 } 999 1000 if (WRFAULT(code)) { 1001 ftype = VM_PROT_WRITE; 1002 } else { 1003 ftype = VM_PROT_READ; 1004 } 1005 1006 va = trunc_page((vaddr_t)v); 1007 1008 #if 0 /* XXX keep this around? */ 1009 /* NULL pointer check. */ 1010 if (map == kernel_map && va == 0 && onfault == 0) { 1011 printf("trap: bad kernel %s access at 0x%x\n", 1012 (ftype & VM_PROT_WRITE) ? "read/write" : 1013 "read", v); 1014 goto dopanic; 1015 } 1016 #endif 1017 1018 #ifdef DIAGNOSTIC 1019 if (intr_depth && !panicking) { 1020 printf("trap: calling pmap_fault() from interrupt!\n"); 1021 goto dopanic; 1022 } 1023 #endif 1024 1025 pcb->pcb_onfault = NULL; 1026 rv = pmap_fault(map, va, ftype); 1027 pcb->pcb_onfault = onfault; 1028 #ifdef DEBUG 1029 if (rv && MDB_ISPID(p->p_pid)) { 1030 printf("pmap_fault(%p, 0x%lx, 0x%x) -> 0x%x\n", 1031 map, va, ftype, rv); 1032 } 1033 #endif 1034 /* 1035 * If this was a stack access we keep track of the maximum 1036 * accessed stack size. Also, if vm_fault gets a protection 1037 * failure it is due to accessing the stack region outside 1038 * the current limit and we need to reflect that as an access 1039 * error. 1040 */ 1041 if (rv == 0) { 1042 if (map != kernel_map && 1043 (void *)va >= vm->vm_maxsaddr) { 1044 uvm_grow(p, va); 1045 } 1046 if (type == T_MMUFLT) { 1047 #ifdef M68040 1048 if (CPU_IS_40) { 1049 (void)m68040_writeback(fp, 1); 1050 } 1051 #endif 1052 goto done; 1053 } 1054 goto out; 1055 } 1056 /* vvv redundant with the switch() below? vvv */ 1057 if (rv == EACCES) { 1058 ksi.ksi_code = SEGV_ACCERR; 1059 rv = EFAULT; 1060 } else { 1061 ksi.ksi_code = SEGV_MAPERR; 1062 } 1063 /* ^^^ ^^^ */ 1064 if (type == T_MMUFLT) { 1065 if (onfault) { 1066 #ifdef DEBUG 1067 if (mmudebug & MDB_CPFAULT) { 1068 printf("trap: copyfault pcb_onfault\n"); 1069 Debugger(); 1070 } 1071 #endif 1072 goto copyfault; 1073 } 1074 printf("pmap_fault(%p, 0x%lx, 0x%x) -> 0x%x\n", 1075 map, va, ftype, rv); 1076 printf(" type 0x%x, code [mmu,,ssw]: 0x%x\n", 1077 type, code); 1078 goto dopanic; 1079 } 1080 ksi.ksi_addr = (void *)v; 1081 switch (rv) { 1082 case ENOMEM: 1083 printf("UVM: pid %d (%s), uid %d killed: out of swap\n", 1084 p->p_pid, p->p_comm, 1085 l->l_cred ? 1086 kauth_cred_geteuid(l->l_cred) : -1); 1087 ksi.ksi_signo = SIGKILL; 1088 break; 1089 case EINVAL: 1090 ksi.ksi_signo = SIGBUS; 1091 ksi.ksi_code = BUS_ADRERR; 1092 break; 1093 case EACCES: 1094 ksi.ksi_signo = SIGSEGV; 1095 ksi.ksi_code = SEGV_ACCERR; 1096 break; 1097 default: 1098 ksi.ksi_signo = SIGSEGV; 1099 ksi.ksi_code = SEGV_MAPERR; 1100 break; 1101 } 1102 break; 1103 } 1104 } 1105 if (ksi.ksi_signo) { 1106 trapsignal(l, &ksi); 1107 } 1108 if (type & T_USER) { 1109 out: USERRET(l, fp, sticks, v, 1); 1110 } 1111 1112 done: 1113 /* XXX Detect trap recursion? */; 1114 } 1115 1116 #define DO_PEEK(a, r, t) *(t *)(r) = *(volatile t *)(a) 1117 1118 bool 1119 badaddr_read(volatile void *addr, size_t size, void *result) 1120 { 1121 label_t faultbuf; 1122 uint64_t junk; 1123 1124 if (result == NULL) { 1125 result = &junk; 1126 } 1127 1128 nofault = &faultbuf; 1129 if (setjmp(nofault)) { 1130 nofault = NULL; 1131 return true; 1132 } 1133 switch (size) { 1134 case 1: 1135 DO_PEEK(addr, result, uint8_t); 1136 break; 1137 case 2: 1138 DO_PEEK(addr, result, uint16_t); 1139 break; 1140 case 4: 1141 DO_PEEK(addr, result, uint32_t); 1142 break; 1143 case 8: 1144 DO_PEEK(addr, result, uint64_t); 1145 break; 1146 default: 1147 panic("%s", __func__); 1148 } 1149 nofault = NULL; 1150 1151 return false; 1152 } 1153 1154 #undef DO_PEEK 1155 1156 #define DO_POKE(a, v, t) *(volatile t *)(a) = (t)(v) 1157 1158 bool 1159 badaddr_write(volatile void *addr, size_t size, uintmax_t val) 1160 { 1161 label_t faultbuf; 1162 1163 nofault = &faultbuf; 1164 if (setjmp(nofault)) { 1165 nofault = NULL; 1166 return true; 1167 } 1168 switch (size) { 1169 case 1: 1170 DO_POKE(addr, val, uint8_t); 1171 break; 1172 case 2: 1173 DO_POKE(addr, val, uint16_t); 1174 break; 1175 case 4: 1176 DO_POKE(addr, val, uint32_t); 1177 break; 1178 case 8: 1179 DO_POKE(addr, val, uint64_t); 1180 break; 1181 default: 1182 panic("%s", __func__); 1183 } 1184 nofault = NULL; 1185 1186 return false; 1187 } 1188 1189 #undef DO_POKE 1190