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