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