1 /* $NetBSD: trap.c,v 1.143 2024/05/04 13:45:10 mlelstv 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 "opt_ddb.h" 42 #include "opt_execfmt.h" 43 #include "opt_compat_sunos.h" 44 #include "opt_fpu_emulate.h" 45 #include "opt_m68k_arch.h" 46 47 #include <sys/cdefs.h> 48 __KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.143 2024/05/04 13:45:10 mlelstv Exp $"); 49 50 #include <sys/param.h> 51 #include <sys/systm.h> 52 #include <sys/proc.h> 53 #include <sys/acct.h> 54 #include <sys/kernel.h> 55 #include <sys/signalvar.h> 56 #include <sys/resourcevar.h> 57 #include <sys/syslog.h> 58 #include <sys/syscall.h> 59 #include <sys/userret.h> 60 #include <sys/kauth.h> 61 62 #include <uvm/uvm_extern.h> 63 64 #include <machine/psl.h> 65 #include <machine/trap.h> 66 #include <machine/cpu.h> 67 #include <machine/fcode.h> 68 #include <machine/pcb.h> 69 #include <machine/pte.h> 70 71 #include <m68k/fpe/fpu_emulate.h> 72 #include <m68k/cacheops.h> 73 74 #ifdef COMPAT_SUNOS 75 #include <compat/sunos/sunos_syscall.h> 76 extern struct emul emul_sunos; 77 #endif 78 79 /* 80 * XXX Hack until I can figure out what to do about this code's removal 81 * from m68k/include/frame.h 82 */ 83 84 /* 68040 fault frame */ 85 #define SSW_CP 0x8000 /* Continuation - Floating-Point Post*/ 86 #define SSW_CU 0x4000 /* Continuation - Unimpl. FP */ 87 #define SSW_CT 0x2000 /* Continuation - Trace */ 88 #define SSW_CM 0x1000 /* Continuation - MOVEM */ 89 #define SSW_MA 0x0800 /* Misaligned access */ 90 #define SSW_ATC 0x0400 /* ATC fault */ 91 #define SSW_LK 0x0200 /* Locked transfer */ 92 #define SSW_RW040 0x0100 /* Read/Write */ 93 #define SSW_SZMASK 0x0060 /* Transfer size */ 94 #define SSW_TTMASK 0x0018 /* Transfer type */ 95 #define SSW_TMMASK 0x0007 /* Transfer modifier */ 96 97 #define WBS_TMMASK 0x0007 98 #define WBS_TTMASK 0x0018 99 #define WBS_SZMASK 0x0060 100 #define WBS_VALID 0x0080 101 102 #define WBS_SIZE_BYTE 0x0020 103 #define WBS_SIZE_WORD 0x0040 104 #define WBS_SIZE_LONG 0x0000 105 #define WBS_SIZE_LINE 0x0060 106 107 #define WBS_TT_NORMAL 0x0000 108 #define WBS_TT_MOVE16 0x0008 109 #define WBS_TT_ALTFC 0x0010 110 #define WBS_TT_ACK 0x0018 111 112 #define WBS_TM_PUSH 0x0000 113 #define WBS_TM_UDATA 0x0001 114 #define WBS_TM_UCODE 0x0002 115 #define WBS_TM_MMUTD 0x0003 116 #define WBS_TM_MMUTC 0x0004 117 #define WBS_TM_SDATA 0x0005 118 #define WBS_TM_SCODE 0x0006 119 #define WBS_TM_RESV 0x0007 120 121 #define MMUSR_PA_MASK 0xfffff000 122 #define MMUSR_B 0x00000800 123 #define MMUSR_G 0x00000400 124 #define MMUSR_U1 0x00000200 125 #define MMUSR_U0 0x00000100 126 #define MMUSR_S 0x00000080 127 #define MMUSR_CM 0x00000060 128 #define MMUSR_M 0x00000010 129 #define MMUSR_0 0x00000008 130 #define MMUSR_W 0x00000004 131 #define MMUSR_T 0x00000002 132 #define MMUSR_R 0x00000001 133 134 #define FSLW_STRING "\020\1SEE\3BPE\4TTR\5WE\6RE\7TWE\010WP\011SP" \ 135 "\012PF\013IL\014PTB\015PTA\016SBE\017PBE" 136 /* 137 * XXX End hack 138 */ 139 140 volatile int astpending; 141 142 const char *trap_type[] = { 143 "Bus error", 144 "Address error", 145 "Illegal instruction", 146 "Zero divide", 147 "CHK instruction", 148 "TRAPV instruction", 149 "Privilege violation", 150 "Trace trap", 151 "MMU fault", 152 "SSIR trap", 153 "Format error", 154 "68881 exception", 155 "Coprocessor violation", 156 "Async system trap" 157 }; 158 int trap_types = sizeof trap_type / sizeof trap_type[0]; 159 160 /* 161 * Size of various exception stack frames (minus the standard 8 bytes) 162 */ 163 short exframesize[] = { 164 FMT0SIZE, /* type 0 - normal (68020/030/040/060) */ 165 FMT1SIZE, /* type 1 - throwaway (68020/030/040) */ 166 FMT2SIZE, /* type 2 - normal 6-word (68020/030/040/060) */ 167 FMT3SIZE, /* type 3 - FP post-instruction (68040/060) */ 168 FMT4SIZE, /* type 4 - access error/fp disabled (68060) */ 169 -1, -1, /* type 5-6 - undefined */ 170 FMT7SIZE, /* type 7 - access error (68040) */ 171 58, /* type 8 - bus fault (68010) */ 172 FMT9SIZE, /* type 9 - coprocessor mid-instruction (68020/030) */ 173 FMTASIZE, /* type A - short bus fault (68020/030) */ 174 FMTBSIZE, /* type B - long bus fault (68020/030) */ 175 -1, -1, -1, -1 /* type C-F - undefined */ 176 }; 177 178 #ifdef DEBUG 179 int mmudebug = 0; 180 #endif 181 182 extern struct pcb *curpcb; 183 int _write_back(u_int, u_int, u_int, u_int, struct vm_map *); 184 static void userret(struct lwp *, int, u_quad_t); 185 void panictrap(int, u_int, u_int, struct frame *); 186 void trapcpfault(struct lwp *, struct frame *, int); 187 void trapmmufault(int, u_int, u_int, struct frame *, struct lwp *, 188 u_quad_t); 189 void trap(struct frame *, int, u_int, u_int); 190 #ifdef DDB 191 #include <m68k/db_machdep.h> 192 int kdb_trap(int, db_regs_t *); 193 #endif 194 void _wb_fault(void); 195 196 197 static void 198 userret(struct lwp *l, int pc, u_quad_t oticks) 199 { 200 struct proc *p = l->l_proc; 201 202 /* Invoke MI userret code */ 203 mi_userret(l); 204 205 /* 206 * If profiling, charge recent system time. 207 */ 208 if (p->p_stflag & PST_PROFIL) { 209 extern int psratio; 210 211 addupc_task(l, pc, (int)(p->p_sticks - oticks) * psratio); 212 } 213 } 214 215 /* 216 * Used by the common m68k syscall() and child_return() functions. 217 * XXX: Temporary until all m68k ports share common trap()/userret() code. 218 */ 219 void machine_userret(struct lwp *, struct frame *, u_quad_t); 220 221 void 222 machine_userret(struct lwp *l, struct frame *f, u_quad_t t) 223 { 224 225 userret(l, f->f_pc, t); 226 } 227 228 void 229 panictrap(int type, u_int code, u_int v, struct frame *fp) 230 { 231 static int panicking = 0; 232 if (panicking++ == 0) { 233 printf("trap type %d, code = %x, v = %x\n", type, code, v); 234 regdump((struct trapframe *)fp, 128); 235 } 236 type &= ~T_USER; 237 #ifdef DEBUG 238 DCIS(); /* XXX? push cache */ 239 #endif 240 if ((u_int)type < trap_types) 241 panic(trap_type[type]); 242 panic("trap"); 243 /*NOTREACHED*/ 244 } 245 246 /* 247 * return to fault handler 248 */ 249 void 250 trapcpfault(struct lwp *l, struct frame *fp, int error) 251 { 252 struct pcb *pcb = lwp_getpcb(l); 253 254 /* 255 * We have arranged to catch this fault in one of the 256 * copy to/from user space routines, set PC to return to 257 * indicated location and set flag informing buserror code 258 * that it may need to clean up stack frame. 259 */ 260 fp->f_stackadj = exframesize[fp->f_format]; 261 fp->f_format = fp->f_vector = 0; 262 fp->f_pc = (int)pcb->pcb_onfault; 263 fp->f_regs[D0] = error; 264 } 265 266 int donomore = 0; 267 268 void 269 trapmmufault(int type, u_int code, u_int v, struct frame *fp, struct lwp *l, u_quad_t sticks) 270 { 271 #if defined(DEBUG) && defined(M68060) 272 static u_int oldcode=0, oldv=0; 273 static struct proc *oldp=0; 274 #endif 275 extern struct vm_map *kernel_map; 276 struct proc *p = l->l_proc; 277 struct vmspace *vm = NULL; 278 struct vm_map *map; 279 struct pcb *pcb; 280 void *onfault; 281 vm_prot_t ftype; 282 vaddr_t va; 283 ksiginfo_t ksi; 284 int rv; 285 286 pcb = lwp_getpcb(l); 287 onfault = pcb->pcb_onfault; 288 289 KSI_INIT_TRAP(&ksi); 290 ksi.ksi_trap = type & ~T_USER; 291 292 /* 293 * It is only a kernel address space fault iff: 294 * 1. (type & T_USER) == 0 and 295 * 2. pcb_onfault not set or 296 * 3. pcb_onfault set but supervisor space data fault 297 * The last can occur during an exec() copyin where the 298 * argument space is lazy-allocated. 299 */ 300 #ifdef DEBUG 301 /* 302 * Print out some data about the fault 303 */ 304 #ifdef DEBUG_PAGE0 305 if (v < PAGE_SIZE) /* XXX PAGE0 */ 306 mmudebug |= 0x100; /* XXX PAGE0 */ 307 #endif 308 if (mmudebug && mmutype == MMU_68040) { 309 #ifdef M68060 310 if (machineid & AMIGA_68060) { 311 if (--donomore == 0 || mmudebug & 1) { 312 char bits[64]; 313 snprintb(bits, sizeof(bits), FSLW_STRING, code); 314 printf ("68060 access error: pc %x, code %s," 315 " ea %x\n", fp->f_pc, bits, v); 316 } 317 if (p == oldp && v == oldv && code == oldcode) 318 panic("Identical fault backtoback!"); 319 if (donomore == 0) 320 panic("Tired of faulting."); 321 oldp = p; 322 oldv = v; 323 oldcode = code; 324 } else 325 #endif 326 printf("68040 access error: pc %x, code %x," 327 " ea %x, fa %x\n", fp->f_pc, code, fp->f_fmt7.f_ea, v); 328 if (curpcb) 329 printf(" curpcb %p\n", curpcb); 330 331 332 #ifdef DDB /* XXX PAGE0 */ 333 if (v < PAGE_SIZE) /* XXX PAGE0 */ 334 Debugger(); /* XXX PAGE0 */ 335 #endif /* XXX PAGE0 */ 336 } 337 #ifdef DEBUG_PAGE0 338 mmudebug &= ~0x100; /* XXX PAGE0 */ 339 #endif 340 #endif 341 342 if (p) 343 vm = p->p_vmspace; 344 345 if (type == T_MMUFLT && (l == &lwp0 || onfault == 0 || ( 346 #ifdef M68060 347 machineid & AMIGA_68060 ? code & FSLW_TM_SV : 348 #endif 349 mmutype == MMU_68040 ? (code & SSW_TMMASK) == FC_SUPERD : 350 (code & (SSW_DF|FC_SUPERD)) == (SSW_DF|FC_SUPERD)))) 351 map = kernel_map; 352 else 353 map = &vm->vm_map; 354 355 if ( 356 #ifdef M68060 357 machineid & AMIGA_68060 ? code & FSLW_RW_W : 358 #endif 359 mmutype == MMU_68040 ? (code & (SSW_LK|SSW_RW040)) != SSW_RW040 : 360 ((code & SSW_DF) != 0 && 361 ((code & SSW_RW) == 0 || (code & SSW_RM) != 0))) 362 ftype = VM_PROT_WRITE; 363 else 364 ftype = VM_PROT_READ; 365 va = trunc_page((vaddr_t)v); 366 #ifdef DEBUG 367 if (map == kernel_map && va == 0 && onfault == 0) { 368 printf("trap: bad kernel access at %x pc %x\n", v, fp->f_pc); 369 panictrap(type, code, v, fp); 370 } 371 372 if (mmudebug) 373 printf("vm_fault(%p,%lx,%d)\n", map, va, ftype); 374 #endif 375 376 pcb->pcb_onfault = NULL; 377 rv = uvm_fault(map, va, ftype); 378 pcb->pcb_onfault = onfault; 379 380 #ifdef DEBUG 381 if (mmudebug) 382 printf("vmfault %s %lx returned %d\n", 383 map == kernel_map ? "kernel" : "user", va, rv); 384 #endif 385 386 #ifdef M68060 387 if ((machineid & AMIGA_68060) == 0 && mmutype == MMU_68040) { 388 #else 389 if (mmutype == MMU_68040) { 390 #endif 391 if (rv != 0) { 392 goto nogo; 393 } 394 395 /* 396 * The 68040 doesn't re-run instructions that cause 397 * write page faults (unless due to a move16 isntruction). 398 * So once the page is repaired, we have to write the 399 * value of WB2D out to memory ourselves. Because 400 * the writeback could possibly span two pages in 401 * memory, so we need to check both "ends" of the 402 * address to see if they are in the same page or not. 403 * If not, then we need to make sure the second page 404 * is valid, and bring it into memory if it's not. 405 * 406 * This whole process needs to be repeated for WB3 as well. 407 * <sigh> 408 */ 409 410 /* Check WB1 */ 411 if (fp->f_fmt7.f_wb1s & WBS_VALID) { 412 printf ("trap: wb1 was valid, not handled yet\n"); 413 panictrap(type, code, v, fp); 414 } 415 416 /* 417 * Check WB2 418 * skip if it's for a move16 instruction 419 */ 420 if(fp->f_fmt7.f_wb2s & WBS_VALID && 421 ((fp->f_fmt7.f_wb2s & WBS_TTMASK)==WBS_TT_MOVE16) == 0) { 422 if (_write_back(2, fp->f_fmt7.f_wb2s, 423 fp->f_fmt7.f_wb2d, fp->f_fmt7.f_wb2a, map) != 0) 424 goto nogo; 425 if ((fp->f_fmt7.f_wb2s & WBS_TMMASK) 426 != (code & SSW_TMMASK)) 427 panictrap(type, code, v, fp); 428 } 429 430 /* Check WB3 */ 431 if(fp->f_fmt7.f_wb3s & WBS_VALID) { 432 struct vm_map *wb3_map; 433 434 if ((fp->f_fmt7.f_wb3s & WBS_TMMASK) == WBS_TM_SDATA) 435 wb3_map = kernel_map; 436 else 437 wb3_map = &vm->vm_map; 438 if (_write_back(3, fp->f_fmt7.f_wb3s, 439 fp->f_fmt7.f_wb3d, fp->f_fmt7.f_wb3a, wb3_map) != 0) 440 goto nogo; 441 } 442 } 443 444 /* 445 * If this was a stack access we keep track of the maximum 446 * accessed stack size. Also, if vm_fault gets a protection 447 * failure it is due to accessing the stack region outside 448 * the current limit and we need to reflect that as an access 449 * error. 450 */ 451 if (rv == 0) { 452 if (map != kernel_map && (void *)va >= vm->vm_maxsaddr) 453 uvm_grow(p, va); 454 455 if (type == T_MMUFLT) 456 return; 457 userret(l, fp->f_pc, sticks); 458 return; 459 } 460 nogo: 461 if (type == T_MMUFLT) { 462 if (onfault) { 463 trapcpfault(l, fp, rv); 464 return; 465 } 466 printf("uvm_fault(%p, 0x%lx, 0x%x) -> 0x%x\n", 467 map, va, ftype, rv); 468 printf(" type %x, code [mmu,,ssw]: %x\n", 469 type, code); 470 panictrap(type, code, v, fp); 471 } 472 ksi.ksi_addr = (void *)v; 473 switch (rv) { 474 case ENOMEM: 475 printf("UVM: pid %d (%s), uid %d killed: out of swap\n", 476 p->p_pid, p->p_comm, 477 l->l_cred ? kauth_cred_geteuid(l->l_cred) : -1); 478 ksi.ksi_signo = SIGKILL; 479 break; 480 case EINVAL: 481 ksi.ksi_signo = SIGBUS; 482 ksi.ksi_code = BUS_ADRERR; 483 break; 484 case EACCES: 485 ksi.ksi_signo = SIGSEGV; 486 ksi.ksi_code = SEGV_ACCERR; 487 break; 488 default: 489 ksi.ksi_signo = SIGSEGV; 490 ksi.ksi_code = SEGV_MAPERR; 491 break; 492 } 493 trapsignal(l, &ksi); 494 if ((type & T_USER) == 0) 495 return; 496 userret(l, fp->f_pc, sticks); 497 } 498 /* 499 * Trap is called from locore to handle most types of processor traps, 500 * including events such as simulated software interrupts/AST's. 501 * System calls are broken out for efficiency. 502 */ 503 /*ARGSUSED*/ 504 void 505 trap(struct frame *fp, int type, u_int code, u_int v) 506 { 507 struct lwp *l; 508 struct proc *p; 509 struct pcb *pcb; 510 ksiginfo_t ksi; 511 u_quad_t sticks = 0; 512 513 l = curlwp; 514 p = l->l_proc; 515 pcb = lwp_getpcb(l); 516 517 curcpu()->ci_data.cpu_ntrap++; 518 519 KSI_INIT_TRAP(&ksi); 520 ksi.ksi_trap = type & ~T_USER; 521 522 if (USERMODE(fp->f_sr)) { 523 type |= T_USER; 524 sticks = p->p_sticks; 525 l->l_md.md_regs = fp->f_regs; 526 } 527 528 #ifdef DDB 529 if (type == T_TRACE || type == T_BREAKPOINT) { 530 if (kdb_trap(type, (db_regs_t *)fp)) 531 return; 532 } 533 #endif 534 #ifdef DEBUG 535 if (mmudebug & 2) 536 printf("%s: t %x c %x v %x adj %x sr %x pc %x fmt %x vc %x\n", 537 __func__, type, code, v, fp->f_stackadj, fp->f_sr, 538 fp->f_pc, fp->f_format, fp->f_vector); 539 #endif 540 switch (type) { 541 default: 542 panictrap(type, code, v, fp); 543 /* 544 * Kernel Bus error 545 */ 546 case T_BUSERR: 547 if (!pcb->pcb_onfault) 548 panictrap(type, code, v, fp); 549 trapcpfault(l, fp, EFAULT); 550 return; 551 /* 552 * User Bus/Addr error. 553 */ 554 case T_BUSERR|T_USER: 555 case T_ADDRERR|T_USER: 556 ksi.ksi_addr = (void *)v; 557 ksi.ksi_signo = SIGBUS; 558 ksi.ksi_code = (type == (T_BUSERR|T_USER)) ? 559 BUS_OBJERR : BUS_ADRERR; 560 break; 561 /* 562 * User illegal/privleged inst fault 563 */ 564 case T_ILLINST|T_USER: 565 case T_PRIVINST|T_USER: 566 ksi.ksi_addr = (void *)(int)fp->f_format; 567 /* XXX was ILL_PRIVIN_FAULT */ 568 ksi.ksi_signo = SIGILL; 569 ksi.ksi_code = (type == (T_PRIVINST|T_USER)) ? 570 ILL_PRVOPC : ILL_ILLOPC; 571 break; 572 /* 573 * divde by zero, CHK/TRAPV inst 574 */ 575 case T_ZERODIV|T_USER: 576 ksi.ksi_code = FPE_INTDIV; 577 case T_CHKINST|T_USER: 578 case T_TRAPVINST|T_USER: 579 ksi.ksi_addr = (void *)(int)fp->f_format; 580 ksi.ksi_signo = SIGFPE; 581 break; 582 583 case T_FPEMULI|T_USER: 584 case T_FPEMULD|T_USER: 585 #ifdef FPU_EMULATE 586 if (fpu_emulate(fp, &pcb->pcb_fpregs, &ksi) == 0) 587 ; /* XXX - Deal with tracing? (fp->f_sr & PSL_T) */ 588 #else 589 printf("pid %d killed: no floating point support\n", p->p_pid); 590 ksi.ksi_signo = SIGILL; 591 ksi.ksi_code = ILL_ILLOPC; 592 #endif 593 break; 594 595 #ifdef FPCOPROC 596 /* 597 * User coprocessor violation 598 */ 599 case T_COPERR|T_USER: 600 /* XXX What is a proper response here? */ 601 ksi.ksi_signo = SIGFPE; 602 ksi.ksi_code = FPE_FLTINV; 603 break; 604 /* 605 * 6888x exceptions 606 */ 607 case T_FPERR|T_USER: 608 /* 609 * We pass along the 68881 status register which locore 610 * stashed in code for us. 611 */ 612 ksi.ksi_signo = SIGFPE; 613 ksi.ksi_code = fpsr2siginfocode(code); 614 break; 615 /* 616 * Kernel coprocessor violation 617 */ 618 case T_COPERR: 619 /*FALLTHROUGH*/ 620 #endif 621 /* 622 * Kernel format error 623 */ 624 case T_FMTERR: 625 /* 626 * The user has most likely trashed the RTE or FP state info 627 * in the stack frame of a signal handler. 628 */ 629 type |= T_USER; 630 #ifdef DEBUG 631 printf("pid %d: kernel %s exception\n", p->p_pid, 632 type==T_COPERR ? "coprocessor" : "format"); 633 #endif 634 mutex_enter(p->p_lock); 635 SIGACTION(p, SIGILL).sa_handler = SIG_DFL; 636 sigdelset(&p->p_sigctx.ps_sigignore, SIGILL); 637 sigdelset(&p->p_sigctx.ps_sigcatch, SIGILL); 638 sigdelset(&l->l_sigmask, SIGILL); 639 mutex_exit(p->p_lock); 640 641 ksi.ksi_signo = SIGILL; 642 ksi.ksi_addr = (void *)(int)fp->f_format; 643 /* XXX was ILL_RESAD_FAULT */ 644 ksi.ksi_code = (type == T_COPERR) ? 645 ILL_COPROC : ILL_ILLOPC; 646 break; 647 /* 648 * Trace traps. 649 * 650 * M68k NetBSD uses trap #2, 651 * SUN 3.x uses trap #15, 652 * KGDB uses trap #15 (for kernel breakpoints; handled elsewhere). 653 * 654 * Amiga traps get mapped by locore.s into T_TRACE. 655 * SUN 3.x traps get passed through as T_TRAP15 and are not really 656 * supported yet. 657 */ 658 case T_TRACE: 659 case T_TRAP15: 660 fp->f_sr &= ~PSL_T; 661 ksi.ksi_signo = SIGTRAP; 662 break; 663 case T_TRACE|T_USER: 664 case T_TRAP15|T_USER: 665 #ifdef COMPAT_SUNOS 666 /* 667 * SunOS uses Trap #2 for a "CPU cache flush". 668 * Just flush the on-chip caches and return. 669 */ 670 if (p->p_emul == &emul_sunos) { 671 ICIA(); 672 DCIU(); 673 return; 674 } 675 #endif 676 fp->f_sr &= ~PSL_T; 677 ksi.ksi_addr = (void *)fp->f_pc; 678 ksi.ksi_signo = SIGTRAP; 679 if (type == (T_TRAP15|T_USER)) 680 ksi.ksi_code = TRAP_BRKPT; 681 else 682 ksi.ksi_code = TRAP_TRACE; 683 break; 684 /* 685 * Kernel AST (should not happen) 686 */ 687 case T_ASTFLT: 688 panictrap(type, code, v, fp); 689 /* 690 * User AST 691 */ 692 case T_ASTFLT|T_USER: 693 astpending = 0; 694 spl0(); 695 if (l->l_pflag & LP_OWEUPC) { 696 l->l_pflag &= ~LP_OWEUPC; 697 ADDUPROF(l); 698 } 699 userret(l, fp->f_pc, sticks); 700 return; 701 /* 702 * Kernel/User page fault 703 */ 704 case T_MMUFLT: 705 case T_MMUFLT|T_USER: /* page fault */ 706 trapmmufault(type, code, v, fp, l, sticks); 707 return; 708 } 709 710 #ifdef DEBUG 711 if (ksi.ksi_signo != SIGTRAP) 712 printf("trapsignal(%d, %d, %d, %x, %x)\n", p->p_pid, 713 ksi.ksi_signo, ksi.ksi_code, v, fp->f_pc); 714 #endif 715 if (ksi.ksi_signo) 716 trapsignal(l, &ksi); 717 if ((type & T_USER) == 0) 718 return; 719 userret(l, fp->f_pc, sticks); 720 } 721 722 /* 723 * Process a pending write back 724 */ 725 int 726 _write_back (u_int wb, u_int wb_sts, u_int wb_data, u_int wb_addr, struct vm_map *wb_map) 727 /* wb: writeback type: 1, 2, or 3 */ 728 /* wb_sts: writeback status information */ 729 /* wb_data: data to writeback */ 730 /* wb_addr: address to writeback to */ 731 { 732 u_int wb_extra_page = 0; 733 u_int wb_rc, mmusr; 734 void *onfault; 735 736 #ifdef DEBUG 737 if (mmudebug) 738 printf("wb%d valid: %x %x %x\n",wb,wb_sts,wb_addr,wb_data); 739 #endif 740 741 /* See if we're going to span two pages (for word or long transfers) */ 742 743 if((wb_sts & WBS_SZMASK) == WBS_SIZE_WORD) 744 if(trunc_page((vaddr_t)wb_addr) != 745 trunc_page((vaddr_t)wb_addr+1)) 746 wb_extra_page = 1; 747 748 if((wb_sts & WBS_SZMASK) == WBS_SIZE_LONG) 749 if(trunc_page((vaddr_t)wb_addr) != 750 trunc_page((vaddr_t)wb_addr+3)) 751 wb_extra_page = 3; 752 753 /* 754 * if it's writeback 3, we need to check the first page 755 */ 756 if (wb == 3) { 757 mmusr = probeva(wb_addr, wb_sts & WBS_TMMASK); 758 #ifdef DEBUG 759 if (mmudebug) 760 printf("wb3: probeva(%x,%x) = %x\n", 761 wb_addr + wb_extra_page, wb_sts & WBS_TMMASK, mmusr); 762 #endif 763 764 if((mmusr & (MMUSR_R | MMUSR_W)) != MMUSR_R) { 765 #ifdef DEBUG 766 if (mmudebug) 767 printf("wb3: need to bring in first page\n"); 768 #endif 769 onfault = curpcb->pcb_onfault; 770 curpcb->pcb_onfault = NULL; 771 wb_rc = uvm_fault(wb_map, 772 trunc_page((vm_offset_t)wb_addr), 773 VM_PROT_READ | VM_PROT_WRITE); 774 curpcb->pcb_onfault = onfault; 775 776 if (wb_rc != 0) 777 return (wb_rc); 778 #ifdef DEBUG 779 if (mmudebug) 780 printf("wb3: first page brought in.\n"); 781 #endif 782 } 783 } 784 785 /* 786 * now check to see if a second page is required 787 */ 788 if(wb_extra_page) { 789 790 mmusr = probeva(wb_addr+wb_extra_page, wb_sts & WBS_TMMASK); 791 #ifdef DEBUG 792 if (mmudebug) 793 printf("wb%d: probeva %x %x = %x\n", 794 wb, wb_addr + wb_extra_page, 795 wb_sts & WBS_TMMASK,mmusr); 796 #endif 797 798 if((mmusr & (MMUSR_R | MMUSR_W)) != MMUSR_R) { 799 #ifdef DEBUG 800 if (mmudebug) 801 printf("wb%d: page boundary crossed." 802 " Bringing in extra page.\n",wb); 803 #endif 804 805 onfault = curpcb->pcb_onfault; 806 curpcb->pcb_onfault = NULL; 807 wb_rc = uvm_fault(wb_map, 808 trunc_page((vm_offset_t)wb_addr + wb_extra_page), 809 VM_PROT_READ | VM_PROT_WRITE); 810 curpcb->pcb_onfault = onfault; 811 812 if (wb_rc != 0) 813 return (wb_rc); 814 } 815 #ifdef DEBUG 816 if (mmudebug) 817 printf("wb%d: extra page brought in okay.\n", wb); 818 #endif 819 } 820 821 /* Actually do the write now */ 822 823 if ((wb_sts & WBS_TMMASK) == FC_USERD && 824 !curpcb->pcb_onfault) { 825 curpcb->pcb_onfault = (void *) _wb_fault; 826 } 827 828 switch(wb_sts & WBS_SZMASK) { 829 830 case WBS_SIZE_BYTE : 831 __asm volatile ("movec %0,%%dfc ; movesb %1,%2@":: "d" (wb_sts & WBS_TMMASK), 832 "d" (wb_data), 833 "a" (wb_addr)); 834 break; 835 836 case WBS_SIZE_WORD : 837 __asm volatile ("movec %0,%%dfc ; movesw %1,%2@":: "d" (wb_sts & WBS_TMMASK), 838 "d" (wb_data), 839 "a" (wb_addr)); 840 break; 841 842 case WBS_SIZE_LONG : 843 __asm volatile ("movec %0,%%dfc ; movesl %1,%2@":: "d" (wb_sts & WBS_TMMASK), 844 "d" (wb_data), 845 "a" (wb_addr)); 846 break; 847 848 } 849 if (curpcb->pcb_onfault == (void *) _wb_fault) 850 curpcb->pcb_onfault = NULL; 851 if ((wb_sts & WBS_TMMASK) != FC_USERD) 852 __asm volatile ("movec %0,%%dfc\n" : : "d" (FC_USERD)); 853 return 0; 854 } 855 856 /* 857 * fault handler for write back 858 */ 859 void 860 _wb_fault(void) 861 { 862 #ifdef DEBUG 863 printf ("trap: writeback fault\n"); 864 #endif 865 return; 866 } 867