1 /* $NetBSD: trap.c,v 1.63 2002/02/14 07:08:06 chs 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. All advertising materials mentioning features or use of this software 21 * must display the following acknowledgement: 22 * This product includes software developed by the University of 23 * California, Berkeley and its contributors. 24 * 4. Neither the name of the University nor the names of its contributors 25 * may be used to endorse or promote products derived from this software 26 * without specific prior written permission. 27 * 28 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 29 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 30 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 31 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 32 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 33 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 34 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 35 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 36 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 37 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 38 * SUCH DAMAGE. 39 * 40 * from: Utah $Hdr: trap.c 1.32 91/04/06$ 41 * 42 * @(#)trap.c 7.15 (Berkeley) 8/2/91 43 */ 44 45 #include "opt_ddb.h" 46 #include "opt_execfmt.h" 47 #include "opt_kgdb.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/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 60 #include <sys/user.h> 61 62 #include <uvm/uvm_extern.h> 63 64 #include <m68k/cpu.h> 65 #include <m68k/cacheops.h> 66 67 #include <machine/psl.h> 68 #include <machine/trap.h> 69 #include <machine/cpu.h> 70 #include <machine/reg.h> 71 #include <machine/mtpr.h> 72 #include <machine/pte.h> 73 #ifdef DDB 74 #include <machine/db_machdep.h> 75 #endif 76 77 #ifdef DEBUG 78 #include <dev/cons.h> /* cngetc() */ 79 #endif 80 81 #ifdef FPU_EMULATE 82 #include <m68k/fpe/fpu_emulate.h> 83 #endif 84 85 #ifdef COMPAT_SUNOS 86 #include <compat/sunos/sunos_syscall.h> 87 extern struct emul emul_sunos; 88 #endif 89 90 void trap __P((int, u_int, u_int, struct frame)); 91 92 static void panictrap __P((int, u_int, u_int, struct frame *)); 93 static void trapcpfault __P((struct proc *, struct frame *)); 94 static void userret __P((struct proc *, struct frame *fp, u_quad_t, u_int,int)); 95 #ifdef M68040 96 static int writeback __P((struct frame *, int)); 97 #endif /* M68040 */ 98 99 char *trap_type[] = { 100 "Bus error", 101 "Address error", 102 "Illegal instruction", 103 "Zero divide", 104 "CHK instruction", 105 "TRAPV instruction", 106 "Privilege violation", 107 "Trace trap", 108 "MMU fault", 109 "SSIR trap", 110 "Format error", 111 "68881 exception", 112 "Coprocessor violation", 113 "Async system trap" 114 }; 115 int trap_types = sizeof trap_type / sizeof trap_type[0]; 116 117 /* 118 * Size of various exception stack frames (minus the standard 8 bytes) 119 */ 120 short exframesize[] = { 121 FMT0SIZE, /* type 0 - normal (68020/030/040/060) */ 122 FMT1SIZE, /* type 1 - throwaway (68020/030/040) */ 123 FMT2SIZE, /* type 2 - normal 6-word (68020/030/040/060) */ 124 FMT3SIZE, /* type 3 - FP post-instruction (68040/060) */ 125 FMT4SIZE, /* type 4 - access error/fp disabled (68060) */ 126 -1, -1, /* type 5-6 - undefined */ 127 FMT7SIZE, /* type 7 - access error (68040) */ 128 58, /* type 8 - bus fault (68010) */ 129 FMT9SIZE, /* type 9 - coprocessor mid-instruction (68020/030) */ 130 FMTASIZE, /* type A - short bus fault (68020/030) */ 131 FMTBSIZE, /* type B - long bus fault (68020/030) */ 132 -1, -1, -1, -1 /* type C-F - undefined */ 133 }; 134 135 #ifdef M68060 136 #define KDFAULT_060(c) (cputype == CPU_68060 && ((c) & FSLW_TM_SV)) 137 #define WRFAULT_060(c) (cputype == CPU_68060 && ((c) & FSLW_RW_W)) 138 #else 139 #define KDFAULT_060(c) 0 140 #define WRFAULT_060(c) 0 141 #endif 142 143 #ifdef M68040 144 #define KDFAULT_040(c) (cputype == CPU_68040 && \ 145 ((c) & SSW4_TMMASK) == SSW4_TMKD) 146 #define WRFAULT_040(c) (cputype == CPU_68040 && \ 147 ((c) & SSW4_RW) == 0) 148 #else 149 #define KDFAULT_040(c) 0 150 #define WRFAULT_040(c) 0 151 #endif 152 153 #if defined(M68030) || defined(M68020) 154 #define KDFAULT_OTH(c) (cputype <= CPU_68030 && \ 155 ((c) & (SSW_DF|SSW_FCMASK)) == (SSW_DF|FC_SUPERD)) 156 #define WRFAULT_OTH(c) (cputype <= CPU_68030 && \ 157 ((c) & (SSW_DF|SSW_RW)) == SSW_DF) 158 #else 159 #define KDFAULT_OTH(c) 0 160 #define WRFAULT_OTH(c) 0 161 #endif 162 163 #define KDFAULT(c) (KDFAULT_060(c) || KDFAULT_040(c) || KDFAULT_OTH(c)) 164 #define WRFAULT(c) (WRFAULT_060(c) || WRFAULT_040(c) || WRFAULT_OTH(c)) 165 166 #ifdef DEBUG 167 int mmudebug = 0; 168 int mmupid = -1; 169 #define MDB_FOLLOW 1 170 #define MDB_WBFOLLOW 2 171 #define MDB_WBFAILED 4 172 #define MDB_ISPID(pid) ((pid) == mmupid) 173 #endif 174 175 extern struct pcb *curpcb; 176 177 /* 178 * trap and syscall both need the following work done before returning 179 * to user mode. 180 */ 181 static inline void 182 userret(p, fp, oticks, faultaddr, fromtrap) 183 register struct proc *p; 184 register struct frame *fp; 185 u_quad_t oticks; 186 u_int faultaddr; 187 int fromtrap; 188 { 189 int sig; 190 #ifdef M68040 191 int beenhere = 0; 192 193 again: 194 #endif 195 /* take pending signals */ 196 while ((sig = CURSIG(p)) != 0) 197 postsig(sig); 198 p->p_priority = p->p_usrpri; 199 if (want_resched) { 200 /* 201 * We are being preempted. 202 */ 203 preempt(NULL); 204 while ((sig = CURSIG(p)) != 0) 205 postsig(sig); 206 } 207 208 /* 209 * If profiling, charge system time to the trapped pc. 210 */ 211 if (p->p_flag & P_PROFIL) { 212 extern int psratio; 213 214 addupc_task(p, fp->f_pc, 215 (int)(p->p_sticks - oticks) * psratio); 216 } 217 #ifdef M68040 218 /* 219 * Deal with user mode writebacks (from trap, or from sigreturn). 220 * If any writeback fails, go back and attempt signal delivery. 221 * unless we have already been here and attempted the writeback 222 * (e.g. bad address with user ignoring SIGSEGV). In that case 223 * we just return to the user without sucessfully completing 224 * the writebacks. Maybe we should just drop the sucker? 225 */ 226 if (cputype == CPU_68040 && fp->f_format == FMT7) { 227 if (beenhere) { 228 #ifdef DEBUG 229 if (mmudebug & MDB_WBFAILED) 230 printf(fromtrap ? 231 "pid %d(%s): writeback aborted, pc=%x, fa=%x\n" : 232 "pid %d(%s): writeback aborted in sigreturn, pc=%x\n", 233 p->p_pid, p->p_comm, fp->f_pc, faultaddr); 234 #endif 235 } else if ((sig = writeback(fp, fromtrap))) { 236 beenhere = 1; 237 oticks = p->p_sticks; 238 trapsignal(p, sig, faultaddr); 239 goto again; 240 } 241 } 242 #endif 243 curcpu()->ci_schedstate.spc_curpriority = p->p_priority; 244 } 245 246 /* 247 * Used by the common m68k syscall() and child_return() functions. 248 * XXX: Temporary until all m68k ports share common trap()/userret() code. 249 */ 250 void machine_userret(struct proc *, struct frame *, u_quad_t); 251 252 void 253 machine_userret(p, f, t) 254 struct proc *p; 255 struct frame *f; 256 u_quad_t t; 257 { 258 259 userret(p, f, t, 0, 0); 260 } 261 262 static void 263 panictrap(type, code, v, fp) 264 int type; 265 u_int code, v; 266 struct frame *fp; 267 { 268 int s; 269 270 printf("trap type %d, code = %x, v = %x\n", type, code, v); 271 printf("%s program counter = 0x%x\n", 272 (type & T_USER) ? "user" : "kernel", fp->f_pc); 273 274 /* 275 * Let the kernel debugger see the trap frame that 276 * caused us to panic. This is a convenience so 277 * one can see registers at the point of failure. 278 */ 279 s = splhigh(); 280 #ifdef KGDB 281 /* If connected, step or cont returns 1 */ 282 if (kgdb_trap(type, &fp)) 283 goto kgdb_cont; 284 #endif 285 #ifdef DDB 286 (void)kdb_trap(type, (db_regs_t *)fp); 287 #endif 288 #ifdef KGDB 289 kgdb_cont: 290 #endif 291 splx(s); 292 293 if (panicstr) { 294 printf("Double panic\n"); 295 #ifdef DEBUG 296 /* XXX Should be a machine dependent hook */ 297 printf("(press a key)\n"); (void)cngetc(); 298 #endif 299 } 300 301 regdump((struct trapframe *)fp, 128); 302 DCIS(); /* XXX? push cache */ 303 304 type &= ~T_USER; 305 if ((u_int)type < trap_types) 306 panic(trap_type[type]); 307 panic("trap"); 308 /*NOTREACHED*/ 309 } 310 311 /* 312 * return to fault handler 313 */ 314 static void 315 trapcpfault(p, fp) 316 struct proc *p; 317 struct frame *fp; 318 { 319 /* 320 * We have arranged to catch this fault in one 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) p->p_addr->u_pcb.pcb_onfault; 328 } 329 330 /* 331 * Trap is called from locore to handle most types of processor traps, 332 * including events such as simulated software interrupts/AST's. 333 * System calls are broken out for efficiency. 334 */ 335 /*ARGSUSED*/ 336 void 337 trap(type, code, v, frame) 338 int type; 339 u_int code, v; 340 struct frame frame; 341 { 342 struct proc *p; 343 u_int ucode; 344 u_quad_t sticks; 345 int i; 346 extern char fubail[], subail[]; 347 348 p = curproc; 349 sticks = ucode = 0; 350 351 uvmexp.traps++; 352 353 /* I have verified that this DOES happen! -gwr */ 354 if (p == NULL) 355 p = &proc0; 356 #ifdef DIAGNOSTIC 357 if (p->p_addr == NULL) 358 panic("trap: no pcb"); 359 #endif 360 361 if (USERMODE(frame.f_sr)) { 362 type |= T_USER; 363 sticks = p->p_sticks; 364 p->p_md.md_regs = frame.f_regs; 365 } 366 switch (type) { 367 default: 368 panictrap(type, code, v, &frame); 369 /* 370 * Kernel Bus error 371 */ 372 case T_BUSERR: 373 if (p->p_addr->u_pcb.pcb_onfault == 0) 374 panictrap(type, code, v, &frame); 375 trapcpfault(p, &frame); 376 return; 377 /* 378 * User Bus/Addr error. 379 */ 380 case T_BUSERR|T_USER: 381 case T_ADDRERR|T_USER: 382 ucode = v; 383 i = SIGBUS; 384 break; 385 386 /* 387 * Kernel coprocessor violation 388 */ 389 case T_COPERR: 390 /*FALLTHROUGH*/ 391 /* 392 * Kernel/User format error 393 */ 394 case T_FMTERR|T_USER: /* do all RTE errors come in as T_USER? */ 395 case T_FMTERR: 396 /* 397 * The user has most likely trashed the RTE or FP state info 398 * in the stack frame of a signal handler. 399 */ 400 type |= T_USER; 401 #ifdef DEBUG 402 printf("pid %d: kernel %s exception\n", p->p_pid, 403 type==T_COPERR ? "coprocessor" : "format"); 404 #endif 405 SIGACTION(p, SIGILL).sa_handler = SIG_DFL; 406 sigdelset(&p->p_sigctx.ps_sigignore, SIGILL); 407 sigdelset(&p->p_sigctx.ps_sigcatch, SIGILL); 408 sigdelset(&p->p_sigctx.ps_sigmask, SIGILL); 409 i = SIGILL; 410 ucode = frame.f_format; /* XXX was ILL_RESAD_FAULT */ 411 break; 412 413 /* 414 * User coprocessor violation 415 */ 416 case T_COPERR|T_USER: 417 ucode = 0; 418 i = SIGFPE; /* XXX What is a proper response here? */ 419 break; 420 421 /* 422 * 6888x exceptions 423 */ 424 case T_FPERR|T_USER: 425 /* 426 * We pass along the 68881 status register which locore 427 * stashed in code for us. Note that there is a 428 * possibility that the bit pattern of this register 429 * will conflict with one of the FPE_* codes defined 430 * in signal.h. Fortunately for us, the only such 431 * codes we use are all in the range 1-7 and the low 432 * 3 bits of the status register are defined as 0 so 433 * there is no clash. 434 */ 435 ucode = code; 436 i = SIGFPE; 437 break; 438 439 /* 440 * Unimplemented FPU instructions/datatypes. 441 */ 442 case T_FPEMULI|T_USER: 443 case T_FPEMULD|T_USER: 444 #ifdef FPU_EMULATE 445 i = fpu_emulate(&frame, &p->p_addr->u_pcb.pcb_fpregs); 446 /* XXX -- deal with tracing? (frame.f_sr & PSL_T) */ 447 #else 448 uprintf("pid %d killed: no floating point support.\n", 449 p->p_pid); 450 i = SIGILL; 451 #endif 452 break; 453 454 /* 455 * FPU faults in supervisor mode. 456 */ 457 case T_FPEMULI: 458 case T_FPEMULD: { 459 extern int *nofault; 460 461 if (nofault) /* If we're probing. */ 462 longjmp((label_t *) nofault); 463 panictrap(type, code, v, &frame); 464 } 465 466 /* 467 * User illegal/privileged inst fault 468 */ 469 case T_ILLINST|T_USER: 470 case T_PRIVINST|T_USER: 471 ucode = frame.f_format; /* XXX was ILL_PRIVIN_FAULT */ 472 i = SIGILL; 473 break; 474 475 /* 476 * divde by zero, CHK/TRAPV inst 477 */ 478 case T_ZERODIV|T_USER: 479 case T_CHKINST|T_USER: 480 case T_TRAPVINST|T_USER: 481 ucode = frame.f_format; 482 i = SIGFPE; 483 break; 484 /* 485 * XXX: Trace traps are a nightmare. 486 * 487 * HP-UX uses trap #1 for breakpoints, 488 * NetBSD/m68k uses trap #2, 489 * SUN 3.x uses trap #15, 490 * DDB and KGDB use trap #15 (for kernel breakpoints; 491 * handled elsewhere). 492 * 493 * NetBSD and HP-UX traps get mapped by locore.s into T_TRACE. 494 * SUN 3.x traps get passed through as T_TRAP15 and are not really 495 * supported yet. 496 * 497 * XXX: We should never get kernel-mode T_TRAP15 498 * XXX: because locore.s now gives them special treatment. 499 */ 500 case T_TRAP15: 501 frame.f_sr &= ~PSL_T; 502 return; 503 504 case T_TRACE|T_USER: 505 #ifdef COMPAT_SUNOS 506 /* 507 * SunOS uses Trap #2 for a "CPU cache flush". 508 * Just flush the on-chip caches and return. 509 */ 510 if (p->p_emul == &emul_sunos) { 511 ICIA(); 512 DCIU(); 513 return; 514 } 515 #endif 516 /* FALLTHROUGH */ 517 case T_TRACE: /* tracing a trap instruction */ 518 case T_TRAP15|T_USER: 519 frame.f_sr &= ~PSL_T; 520 i = SIGTRAP; 521 break; 522 /* 523 * Kernel AST (should not happen) 524 */ 525 case T_ASTFLT: 526 panictrap(type, code, v, &frame); 527 /* 528 * User AST 529 */ 530 case T_ASTFLT|T_USER: 531 astpending = 0; 532 /* 533 * We check for software interrupts first. This is because 534 * they are at a higher level than ASTs, and on a VAX would 535 * interrupt the AST. We assume that if we are processing 536 * an AST that we must be at IPL0 so we don't bother to 537 * check. Note that we ensure that we are at least at SIR 538 * IPL while processing the SIR. 539 */ 540 spl1(); 541 /*FALLTHROUGH*/ 542 /* 543 * Software interrupt 544 */ 545 case T_SSIR: 546 case T_SSIR|T_USER: 547 if(ssir) 548 softint(); 549 /* 550 * If this was not an AST trap, we are all done. 551 */ 552 if (type != (T_ASTFLT|T_USER)) { 553 uvmexp.traps--; 554 return; 555 } 556 spl0(); 557 if (p->p_flag & P_OWEUPC) { 558 p->p_flag &= ~P_OWEUPC; 559 ADDUPROF(p); 560 } 561 goto out; 562 /* 563 * Kernel/User page fault 564 */ 565 case T_MMUFLT: 566 /* 567 * If we were doing profiling ticks or other user mode 568 * stuff from interrupt code, Just Say No. 569 */ 570 if (p->p_addr->u_pcb.pcb_onfault == (caddr_t)fubail || 571 p->p_addr->u_pcb.pcb_onfault == (caddr_t)subail) { 572 trapcpfault(p, &frame); 573 return; 574 } 575 /*FALLTHROUGH*/ 576 case T_MMUFLT|T_USER: /* page fault */ 577 { 578 register vaddr_t va; 579 register struct vmspace *vm = p->p_vmspace; 580 register struct vm_map *map; 581 int rv; 582 vm_prot_t ftype; 583 extern struct vm_map * kernel_map; 584 585 #ifdef DEBUG 586 if ((mmudebug & MDB_WBFOLLOW) || MDB_ISPID(p->p_pid)) 587 printf("trap: T_MMUFLT pid=%d, code=%x, v=%x, pc=%x, sr=%x\n", 588 p ? p->p_pid : -1, code, v, frame.f_pc, frame.f_sr); 589 #endif 590 /* 591 * It is only a kernel address space fault iff: 592 * 1. (type & T_USER) == 0 and 593 * 2. pcb_onfault not set or 594 * 3. pcb_onfault set but supervisor space data fault 595 * The last can occur during an exec() copyin where the 596 * argument space is lazy-allocated. 597 */ 598 if (type == T_MMUFLT && 599 ((p->p_addr->u_pcb.pcb_onfault == 0) || KDFAULT(code))) 600 map = kernel_map; 601 else 602 map = vm ? &vm->vm_map : kernel_map; 603 if (WRFAULT(code)) 604 ftype = VM_PROT_WRITE; 605 else 606 ftype = VM_PROT_READ; 607 va = trunc_page(v); 608 #ifdef DEBUG 609 if (map == kernel_map && va == 0) { 610 printf("trap: bad kernel access at %x\n", v); 611 panictrap(type, code, v, &frame); 612 } 613 #endif 614 rv = uvm_fault(map, va, 0, ftype); 615 #ifdef DEBUG 616 if (rv && MDB_ISPID(p->p_pid)) 617 printf("vm_fault(%p, %lx, %x, 0) -> %x\n", 618 map, va, ftype, rv); 619 #endif 620 /* 621 * If this was a stack access we keep track of the maximum 622 * accessed stack size. Also, if vm_fault gets a protection 623 * failure it is due to accessing the stack region outside 624 * the current limit and we need to reflect that as an access 625 * error. 626 */ 627 if ((vm != NULL && (caddr_t)va >= vm->vm_maxsaddr) 628 && map != kernel_map) { 629 if (rv == 0) { 630 unsigned nss; 631 632 nss = btoc(USRSTACK-(unsigned)va); 633 if (nss > vm->vm_ssize) 634 vm->vm_ssize = nss; 635 } else if (rv == EACCES) 636 rv = EFAULT; 637 } 638 if (rv == 0) { 639 if (type == T_MMUFLT) { 640 #ifdef M68040 641 if (cputype == CPU_68040) 642 (void) writeback(&frame, 1); 643 #endif 644 return; 645 } 646 goto out; 647 } 648 if (type == T_MMUFLT) { 649 if (p->p_addr->u_pcb.pcb_onfault) { 650 trapcpfault(p, &frame); 651 return; 652 } 653 printf("\nvm_fault(%p, %lx, %x, 0) -> %x\n", 654 map, va, ftype, rv); 655 printf(" type %x, code [mmu,,ssw]: %x\n", 656 type, code); 657 panictrap(type, code, v, &frame); 658 } 659 ucode = v; 660 if (rv == ENOMEM) { 661 printf("UVM: pid %d (%s), uid %d killed: out of swap\n", 662 p->p_pid, p->p_comm, 663 p->p_cred && p->p_ucred ? 664 p->p_ucred->cr_uid : -1); 665 i = SIGKILL; 666 } else { 667 i = SIGSEGV; 668 } 669 break; 670 } 671 } 672 673 if (i) 674 trapsignal(p, i, ucode); 675 if ((type & T_USER) == 0) 676 return; 677 out: 678 userret(p, &frame, sticks, v, 1); 679 } 680 681 #ifdef M68040 682 #ifdef DEBUG 683 struct writebackstats { 684 int calls; 685 int cpushes; 686 int move16s; 687 int wb1s, wb2s, wb3s; 688 int wbsize[4]; 689 } wbstats; 690 691 char *f7sz[] = { "longword", "byte", "word", "line" }; 692 char *f7tt[] = { "normal", "MOVE16", "AFC", "ACK" }; 693 char *f7tm[] = { "d-push", "u-data", "u-code", "M-data", 694 "M-code", "k-data", "k-code", "RES" }; 695 char wberrstr[] = 696 "WARNING: pid %d(%s) writeback [%s] failed, pc=%x fa=%x wba=%x wbd=%x\n"; 697 698 static void dumpwb __P((int, u_short, u_int, u_int)); 699 static void dumpssw __P((u_short)); 700 #endif /* DEBUG */ 701 702 static int 703 writeback(fp, docachepush) 704 struct frame *fp; 705 int docachepush; 706 { 707 register struct fmt7 *f = &fp->f_fmt7; 708 register struct proc *p = curproc; 709 int err = 0; 710 u_int fa = 0; 711 caddr_t oonfault = p->p_addr->u_pcb.pcb_onfault; 712 paddr_t pa; 713 714 #ifdef DEBUG 715 if ((mmudebug & MDB_WBFOLLOW) || MDB_ISPID(p->p_pid)) { 716 printf(" pid=%d, fa=%x,", p->p_pid, f->f_fa); 717 dumpssw(f->f_ssw); 718 } 719 wbstats.calls++; 720 #endif 721 /* 722 * Deal with special cases first. 723 */ 724 if ((f->f_ssw & SSW4_TMMASK) == SSW4_TMDCP) { 725 /* 726 * Dcache push fault. 727 * Line-align the address and write out the push data to 728 * the indicated physical address. 729 */ 730 #ifdef DEBUG 731 if ((mmudebug & MDB_WBFOLLOW) || MDB_ISPID(p->p_pid)) { 732 printf(" pushing %s to PA %x, data %x", 733 f7sz[(f->f_ssw & SSW4_SZMASK) >> 5], 734 f->f_fa, f->f_pd0); 735 if ((f->f_ssw & SSW4_SZMASK) == SSW4_SZLN) 736 printf("/%x/%x/%x", 737 f->f_pd1, f->f_pd2, f->f_pd3); 738 printf("\n"); 739 } 740 if (f->f_wb1s & SSW4_WBSV) 741 panic("writeback: cache push with WB1S valid"); 742 wbstats.cpushes++; 743 #endif 744 /* 745 * XXX there are security problems if we attempt to do a 746 * cache push after a signal handler has been called. 747 */ 748 if (docachepush) { 749 pmap_enter(pmap_kernel(), (vaddr_t)vmmap, 750 trunc_page(f->f_fa), VM_PROT_WRITE, 751 VM_PROT_WRITE|PMAP_WIRED); 752 pmap_update(pmap_kernel()); 753 fa = (u_int)&vmmap[(f->f_fa & PGOFSET) & ~0xF]; 754 bcopy((caddr_t)&f->f_pd0, (caddr_t)fa, 16); 755 (void) pmap_extract(pmap_kernel(), (vaddr_t)fa, &pa); 756 DCFL(pa); 757 pmap_remove(pmap_kernel(), (vaddr_t)vmmap, 758 (vaddr_t)&vmmap[NBPG]); 759 pmap_update(pmap_kernel()); 760 } else 761 printf("WARNING: pid %d(%s) uid %d: CPUSH not done\n", 762 p->p_pid, p->p_comm, p->p_ucred->cr_uid); 763 } else if ((f->f_ssw & (SSW4_RW|SSW4_TTMASK)) == SSW4_TTM16) { 764 /* 765 * MOVE16 fault. 766 * Line-align the address and write out the push data to 767 * the indicated virtual address. 768 */ 769 #ifdef DEBUG 770 if ((mmudebug & MDB_WBFOLLOW) || MDB_ISPID(p->p_pid)) 771 printf(" MOVE16 to VA %x(%x), data %x/%x/%x/%x\n", 772 f->f_fa, f->f_fa & ~0xF, f->f_pd0, f->f_pd1, 773 f->f_pd2, f->f_pd3); 774 if (f->f_wb1s & SSW4_WBSV) 775 panic("writeback: MOVE16 with WB1S valid"); 776 wbstats.move16s++; 777 #endif 778 if (KDFAULT(f->f_wb1s)) 779 bcopy((caddr_t)&f->f_pd0, (caddr_t)(f->f_fa & ~0xF), 16); 780 else 781 err = suline((caddr_t)(f->f_fa & ~0xF), (caddr_t)&f->f_pd0); 782 if (err) { 783 fa = f->f_fa & ~0xF; 784 #ifdef DEBUG 785 if (mmudebug & MDB_WBFAILED) 786 printf(wberrstr, p->p_pid, p->p_comm, 787 "MOVE16", fp->f_pc, f->f_fa, 788 f->f_fa & ~0xF, f->f_pd0); 789 #endif 790 } 791 } else if (f->f_wb1s & SSW4_WBSV) { 792 /* 793 * Writeback #1. 794 * Position the "memory-aligned" data and write it out. 795 */ 796 register u_int wb1d = f->f_wb1d; 797 register int off; 798 799 #ifdef DEBUG 800 if ((mmudebug & MDB_WBFOLLOW) || MDB_ISPID(p->p_pid)) 801 dumpwb(1, f->f_wb1s, f->f_wb1a, f->f_wb1d); 802 wbstats.wb1s++; 803 wbstats.wbsize[(f->f_wb2s&SSW4_SZMASK)>>5]++; 804 #endif 805 off = (f->f_wb1a & 3) * 8; 806 switch (f->f_wb1s & SSW4_SZMASK) { 807 case SSW4_SZLW: 808 if (off) 809 wb1d = (wb1d >> (32 - off)) | (wb1d << off); 810 if (KDFAULT(f->f_wb1s)) 811 *(long *)f->f_wb1a = wb1d; 812 else 813 err = suword((caddr_t)f->f_wb1a, wb1d); 814 break; 815 case SSW4_SZB: 816 off = 24 - off; 817 if (off) 818 wb1d >>= off; 819 if (KDFAULT(f->f_wb1s)) 820 *(char *)f->f_wb1a = wb1d; 821 else 822 err = subyte((caddr_t)f->f_wb1a, wb1d); 823 break; 824 case SSW4_SZW: 825 off = (off + 16) % 32; 826 if (off) 827 wb1d = (wb1d >> (32 - off)) | (wb1d << off); 828 if (KDFAULT(f->f_wb1s)) 829 *(short *)f->f_wb1a = wb1d; 830 else 831 err = susword((caddr_t)f->f_wb1a, wb1d); 832 break; 833 } 834 if (err) { 835 fa = f->f_wb1a; 836 #ifdef DEBUG 837 if (mmudebug & MDB_WBFAILED) 838 printf(wberrstr, p->p_pid, p->p_comm, 839 "#1", fp->f_pc, f->f_fa, 840 f->f_wb1a, f->f_wb1d); 841 #endif 842 } 843 } 844 /* 845 * Deal with the "normal" writebacks. 846 * 847 * XXX writeback2 is known to reflect a LINE size writeback after 848 * a MOVE16 was already dealt with above. Ignore it. 849 */ 850 if (err == 0 && (f->f_wb2s & SSW4_WBSV) && 851 (f->f_wb2s & SSW4_SZMASK) != SSW4_SZLN) { 852 #ifdef DEBUG 853 if ((mmudebug & MDB_WBFOLLOW) || MDB_ISPID(p->p_pid)) 854 dumpwb(2, f->f_wb2s, f->f_wb2a, f->f_wb2d); 855 wbstats.wb2s++; 856 wbstats.wbsize[(f->f_wb2s&SSW4_SZMASK)>>5]++; 857 #endif 858 switch (f->f_wb2s & SSW4_SZMASK) { 859 case SSW4_SZLW: 860 if (KDFAULT(f->f_wb2s)) 861 *(long *)f->f_wb2a = f->f_wb2d; 862 else 863 err = suword((caddr_t)f->f_wb2a, f->f_wb2d); 864 break; 865 case SSW4_SZB: 866 if (KDFAULT(f->f_wb2s)) 867 *(char *)f->f_wb2a = f->f_wb2d; 868 else 869 err = subyte((caddr_t)f->f_wb2a, f->f_wb2d); 870 break; 871 case SSW4_SZW: 872 if (KDFAULT(f->f_wb2s)) 873 *(short *)f->f_wb2a = f->f_wb2d; 874 else 875 err = susword((caddr_t)f->f_wb2a, f->f_wb2d); 876 break; 877 } 878 if (err) { 879 fa = f->f_wb2a; 880 #ifdef DEBUG 881 if (mmudebug & MDB_WBFAILED) { 882 printf(wberrstr, p->p_pid, p->p_comm, 883 "#2", fp->f_pc, f->f_fa, 884 f->f_wb2a, f->f_wb2d); 885 dumpssw(f->f_ssw); 886 dumpwb(2, f->f_wb2s, f->f_wb2a, f->f_wb2d); 887 } 888 #endif 889 } 890 } 891 if (err == 0 && (f->f_wb3s & SSW4_WBSV)) { 892 #ifdef DEBUG 893 if ((mmudebug & MDB_WBFOLLOW) || MDB_ISPID(p->p_pid)) 894 dumpwb(3, f->f_wb3s, f->f_wb3a, f->f_wb3d); 895 wbstats.wb3s++; 896 wbstats.wbsize[(f->f_wb3s&SSW4_SZMASK)>>5]++; 897 #endif 898 switch (f->f_wb3s & SSW4_SZMASK) { 899 case SSW4_SZLW: 900 if (KDFAULT(f->f_wb3s)) 901 *(long *)f->f_wb3a = f->f_wb3d; 902 else 903 err = suword((caddr_t)f->f_wb3a, f->f_wb3d); 904 break; 905 case SSW4_SZB: 906 if (KDFAULT(f->f_wb3s)) 907 *(char *)f->f_wb3a = f->f_wb3d; 908 else 909 err = subyte((caddr_t)f->f_wb3a, f->f_wb3d); 910 break; 911 case SSW4_SZW: 912 if (KDFAULT(f->f_wb3s)) 913 *(short *)f->f_wb3a = f->f_wb3d; 914 else 915 err = susword((caddr_t)f->f_wb3a, f->f_wb3d); 916 break; 917 #ifdef DEBUG 918 case SSW4_SZLN: 919 panic("writeback: wb3s indicates LINE write"); 920 #endif 921 } 922 if (err) { 923 fa = f->f_wb3a; 924 #ifdef DEBUG 925 if (mmudebug & MDB_WBFAILED) 926 printf(wberrstr, p->p_pid, p->p_comm, 927 "#3", fp->f_pc, f->f_fa, 928 f->f_wb3a, f->f_wb3d); 929 #endif 930 } 931 } 932 p->p_addr->u_pcb.pcb_onfault = oonfault; 933 if (err) 934 err = SIGSEGV; 935 return(err); 936 } 937 938 #ifdef DEBUG 939 static void 940 dumpssw(ssw) 941 register u_short ssw; 942 { 943 printf(" SSW: %x: ", ssw); 944 if (ssw & SSW4_CP) 945 printf("CP,"); 946 if (ssw & SSW4_CU) 947 printf("CU,"); 948 if (ssw & SSW4_CT) 949 printf("CT,"); 950 if (ssw & SSW4_CM) 951 printf("CM,"); 952 if (ssw & SSW4_MA) 953 printf("MA,"); 954 if (ssw & SSW4_ATC) 955 printf("ATC,"); 956 if (ssw & SSW4_LK) 957 printf("LK,"); 958 if (ssw & SSW4_RW) 959 printf("RW,"); 960 printf(" SZ=%s, TT=%s, TM=%s\n", 961 f7sz[(ssw & SSW4_SZMASK) >> 5], 962 f7tt[(ssw & SSW4_TTMASK) >> 3], 963 f7tm[ssw & SSW4_TMMASK]); 964 } 965 966 static void 967 dumpwb(num, s, a, d) 968 int num; 969 u_short s; 970 u_int a, d; 971 { 972 register struct proc *p = curproc; 973 paddr_t pa; 974 975 printf(" writeback #%d: VA %x, data %x, SZ=%s, TT=%s, TM=%s\n", 976 num, a, d, f7sz[(s & SSW4_SZMASK) >> 5], 977 f7tt[(s & SSW4_TTMASK) >> 3], f7tm[s & SSW4_TMMASK]); 978 printf(" PA "); 979 if (pmap_extract(p->p_vmspace->vm_map.pmap, (vaddr_t)a, &pa) == FALSE) 980 printf("<invalid address>"); 981 else 982 printf("%lx, current value %lx", pa, fuword((caddr_t)a)); 983 printf("\n"); 984 } 985 #endif /* DEBUG */ 986 #endif /* M68040 */ 987