1 /* $NetBSD: trap.c,v 1.139 2020/08/10 10:51:21 rin 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.139 2020/08/10 10:51:21 rin 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/pcb.h>
68 #include <machine/pte.h>
69
70 #include <m68k/fpe/fpu_emulate.h>
71 #include <m68k/cacheops.h>
72
73 #ifdef COMPAT_SUNOS
74 #include <compat/sunos/sunos_syscall.h>
75 extern struct emul emul_sunos;
76 #endif
77
78 /*
79 * XXX Hack until I can figure out what to do about this code's removal
80 * from m68k/include/frame.h
81 */
82
83 /* 68040 fault frame */
84 #define SSW_CP 0x8000 /* Continuation - Floating-Point Post*/
85 #define SSW_CU 0x4000 /* Continuation - Unimpl. FP */
86 #define SSW_CT 0x2000 /* Continuation - Trace */
87 #define SSW_CM 0x1000 /* Continuation - MOVEM */
88 #define SSW_MA 0x0800 /* Misaligned access */
89 #define SSW_ATC 0x0400 /* ATC fault */
90 #define SSW_LK 0x0200 /* Locked transfer */
91 #define SSW_RW040 0x0100 /* Read/Write */
92 #define SSW_SZMASK 0x0060 /* Transfer size */
93 #define SSW_TTMASK 0x0018 /* Transfer type */
94 #define SSW_TMMASK 0x0007 /* Transfer modifier */
95
96 #define WBS_TMMASK 0x0007
97 #define WBS_TTMASK 0x0018
98 #define WBS_SZMASK 0x0060
99 #define WBS_VALID 0x0080
100
101 #define WBS_SIZE_BYTE 0x0020
102 #define WBS_SIZE_WORD 0x0040
103 #define WBS_SIZE_LONG 0x0000
104 #define WBS_SIZE_LINE 0x0060
105
106 #define WBS_TT_NORMAL 0x0000
107 #define WBS_TT_MOVE16 0x0008
108 #define WBS_TT_ALTFC 0x0010
109 #define WBS_TT_ACK 0x0018
110
111 #define WBS_TM_PUSH 0x0000
112 #define WBS_TM_UDATA 0x0001
113 #define WBS_TM_UCODE 0x0002
114 #define WBS_TM_MMUTD 0x0003
115 #define WBS_TM_MMUTC 0x0004
116 #define WBS_TM_SDATA 0x0005
117 #define WBS_TM_SCODE 0x0006
118 #define WBS_TM_RESV 0x0007
119
120 #define MMUSR_PA_MASK 0xfffff000
121 #define MMUSR_B 0x00000800
122 #define MMUSR_G 0x00000400
123 #define MMUSR_U1 0x00000200
124 #define MMUSR_U0 0x00000100
125 #define MMUSR_S 0x00000080
126 #define MMUSR_CM 0x00000060
127 #define MMUSR_M 0x00000010
128 #define MMUSR_0 0x00000008
129 #define MMUSR_W 0x00000004
130 #define MMUSR_T 0x00000002
131 #define MMUSR_R 0x00000001
132
133 #define FSLW_STRING "\020\1SEE\3BPE\4TTR\5WE\6RE\7TWE\010WP\011SP" \
134 "\012PF\013IL\014PTB\015PTA\016SBE\017PBE"
135 /*
136 * XXX End hack
137 */
138
139 int astpending;
140
141 const char *trap_type[] = {
142 "Bus error",
143 "Address error",
144 "Illegal instruction",
145 "Zero divide",
146 "CHK instruction",
147 "TRAPV instruction",
148 "Privilege violation",
149 "Trace trap",
150 "MMU fault",
151 "SSIR trap",
152 "Format error",
153 "68881 exception",
154 "Coprocessor violation",
155 "Async system trap"
156 };
157 int trap_types = sizeof trap_type / sizeof trap_type[0];
158
159 /*
160 * Size of various exception stack frames (minus the standard 8 bytes)
161 */
162 short exframesize[] = {
163 FMT0SIZE, /* type 0 - normal (68020/030/040/060) */
164 FMT1SIZE, /* type 1 - throwaway (68020/030/040) */
165 FMT2SIZE, /* type 2 - normal 6-word (68020/030/040/060) */
166 FMT3SIZE, /* type 3 - FP post-instruction (68040/060) */
167 FMT4SIZE, /* type 4 - access error/fp disabled (68060) */
168 -1, -1, /* type 5-6 - undefined */
169 FMT7SIZE, /* type 7 - access error (68040) */
170 58, /* type 8 - bus fault (68010) */
171 FMT9SIZE, /* type 9 - coprocessor mid-instruction (68020/030) */
172 FMTASIZE, /* type A - short bus fault (68020/030) */
173 FMTBSIZE, /* type B - long bus fault (68020/030) */
174 -1, -1, -1, -1 /* type C-F - undefined */
175 };
176
177 #ifdef DEBUG
178 int mmudebug = 0;
179 #endif
180
181 extern struct pcb *curpcb;
182 int _write_back(u_int, u_int, u_int, u_int, struct vm_map *);
183 static void userret(struct lwp *, int, u_quad_t);
184 void panictrap(int, u_int, u_int, struct frame *);
185 void trapcpfault(struct lwp *, struct frame *, int);
186 void trapmmufault(int, u_int, u_int, struct frame *, struct lwp *,
187 u_quad_t);
188 void trap(struct frame *, int, u_int, u_int);
189 #ifdef DDB
190 #include <m68k/db_machdep.h>
191 int kdb_trap(int, db_regs_t *);
192 #endif
193 void _wb_fault(void);
194
195
196 static void
userret(struct lwp * l,int pc,u_quad_t oticks)197 userret(struct lwp *l, int pc, u_quad_t oticks)
198 {
199 struct proc *p = l->l_proc;
200
201 /* Invoke MI userret code */
202 mi_userret(l);
203
204 /*
205 * If profiling, charge recent system time.
206 */
207 if (p->p_stflag & PST_PROFIL) {
208 extern int psratio;
209
210 addupc_task(l, pc, (int)(p->p_sticks - oticks) * psratio);
211 }
212 }
213
214 /*
215 * Used by the common m68k syscall() and child_return() functions.
216 * XXX: Temporary until all m68k ports share common trap()/userret() code.
217 */
218 void machine_userret(struct lwp *, struct frame *, u_quad_t);
219
220 void
machine_userret(struct lwp * l,struct frame * f,u_quad_t t)221 machine_userret(struct lwp *l, struct frame *f, u_quad_t t)
222 {
223
224 userret(l, f->f_pc, t);
225 }
226
227 void
panictrap(int type,u_int code,u_int v,struct frame * fp)228 panictrap(int type, u_int code, u_int v, struct frame *fp)
229 {
230 static int panicking = 0;
231 if (panicking++ == 0) {
232 printf("trap type %d, code = %x, v = %x\n", type, code, v);
233 regdump((struct trapframe *)fp, 128);
234 }
235 type &= ~T_USER;
236 #ifdef DEBUG
237 DCIS(); /* XXX? push cache */
238 #endif
239 if ((u_int)type < trap_types)
240 panic(trap_type[type]);
241 panic("trap");
242 /*NOTREACHED*/
243 }
244
245 /*
246 * return to fault handler
247 */
248 void
trapcpfault(struct lwp * l,struct frame * fp,int error)249 trapcpfault(struct lwp *l, struct frame *fp, int error)
250 {
251 struct pcb *pcb = lwp_getpcb(l);
252
253 /*
254 * We have arranged to catch this fault in one of the
255 * copy to/from user space routines, set PC to return to
256 * indicated location and set flag informing buserror code
257 * that it may need to clean up stack frame.
258 */
259 fp->f_stackadj = exframesize[fp->f_format];
260 fp->f_format = fp->f_vector = 0;
261 fp->f_pc = (int)pcb->pcb_onfault;
262 fp->f_regs[D0] = error;
263 }
264
265 int donomore = 0;
266
267 void
trapmmufault(int type,u_int code,u_int v,struct frame * fp,struct lwp * l,u_quad_t sticks)268 trapmmufault(int type, u_int code, u_int v, struct frame *fp, struct lwp *l, u_quad_t sticks)
269 {
270 #if defined(DEBUG) && defined(M68060)
271 static u_int oldcode=0, oldv=0;
272 static struct proc *oldp=0;
273 #endif
274 extern struct vm_map *kernel_map;
275 struct proc *p = l->l_proc;
276 struct vmspace *vm = NULL;
277 struct vm_map *map;
278 struct pcb *pcb;
279 void *onfault;
280 vm_prot_t ftype;
281 vaddr_t va;
282 ksiginfo_t ksi;
283 int rv;
284
285 pcb = lwp_getpcb(l);
286 onfault = pcb->pcb_onfault;
287
288 KSI_INIT_TRAP(&ksi);
289 ksi.ksi_trap = type & ~T_USER;
290
291 /*
292 * It is only a kernel address space fault iff:
293 * 1. (type & T_USER) == 0 and
294 * 2. pcb_onfault not set or
295 * 3. pcb_onfault set but supervisor space data fault
296 * The last can occur during an exec() copyin where the
297 * argument space is lazy-allocated.
298 */
299 #ifdef DEBUG
300 /*
301 * Print out some data about the fault
302 */
303 #ifdef DEBUG_PAGE0
304 if (v < PAGE_SIZE) /* XXX PAGE0 */
305 mmudebug |= 0x100; /* XXX PAGE0 */
306 #endif
307 if (mmudebug && mmutype == MMU_68040) {
308 #ifdef M68060
309 if (machineid & AMIGA_68060) {
310 if (--donomore == 0 || mmudebug & 1) {
311 char bits[64];
312 snprintb(bits, sizeof(bits), FSLW_STRING, code);
313 printf ("68060 access error: pc %x, code %s,"
314 " ea %x\n", fp->f_pc, bits, v);
315 }
316 if (p == oldp && v == oldv && code == oldcode)
317 panic("Identical fault backtoback!");
318 if (donomore == 0)
319 panic("Tired of faulting.");
320 oldp = p;
321 oldv = v;
322 oldcode = code;
323 } else
324 #endif
325 printf("68040 access error: pc %x, code %x,"
326 " ea %x, fa %x\n", fp->f_pc, code, fp->f_fmt7.f_ea, v);
327 if (curpcb)
328 printf(" curpcb %p\n", curpcb);
329
330
331 #ifdef DDB /* XXX PAGE0 */
332 if (v < PAGE_SIZE) /* XXX PAGE0 */
333 Debugger(); /* XXX PAGE0 */
334 #endif /* XXX PAGE0 */
335 }
336 #ifdef DEBUG_PAGE0
337 mmudebug &= ~0x100; /* XXX PAGE0 */
338 #endif
339 #endif
340
341 if (p)
342 vm = p->p_vmspace;
343
344 if (type == T_MMUFLT && (l == &lwp0 || onfault == 0 || (
345 #ifdef M68060
346 machineid & AMIGA_68060 ? code & FSLW_TM_SV :
347 #endif
348 mmutype == MMU_68040 ? (code & SSW_TMMASK) == FC_SUPERD :
349 (code & (SSW_DF|FC_SUPERD)) == (SSW_DF|FC_SUPERD))))
350 map = kernel_map;
351 else
352 map = &vm->vm_map;
353
354 if (
355 #ifdef M68060
356 machineid & AMIGA_68060 ? code & FSLW_RW_W :
357 #endif
358 mmutype == MMU_68040 ? (code & (SSW_LK|SSW_RW040)) != SSW_RW040 :
359 ((code & SSW_DF) != 0 &&
360 ((code & SSW_RW) == 0 || (code & SSW_RM) != 0)))
361 ftype = VM_PROT_WRITE;
362 else
363 ftype = VM_PROT_READ;
364 va = trunc_page((vaddr_t)v);
365 #ifdef DEBUG
366 if (map == kernel_map && va == 0) {
367 printf("trap: bad kernel access at %x pc %x\n", v, fp->f_pc);
368 panictrap(type, code, v, fp);
369 }
370
371 if (mmudebug)
372 printf("vm_fault(%p,%lx,%d)\n", map, va, ftype);
373 #endif
374
375 pcb->pcb_onfault = NULL;
376 rv = uvm_fault(map, va, ftype);
377 pcb->pcb_onfault = onfault;
378
379 #ifdef DEBUG
380 if (mmudebug)
381 printf("vmfault %s %lx returned %d\n",
382 map == kernel_map ? "kernel" : "user", va, rv);
383 #endif
384
385 #ifdef M68060
386 if ((machineid & AMIGA_68060) == 0 && mmutype == MMU_68040) {
387 #else
388 if (mmutype == MMU_68040) {
389 #endif
390 if (rv != 0) {
391 goto nogo;
392 }
393
394 /*
395 * The 68040 doesn't re-run instructions that cause
396 * write page faults (unless due to a move16 isntruction).
397 * So once the page is repaired, we have to write the
398 * value of WB2D out to memory ourselves. Because
399 * the writeback could possibly span two pages in
400 * memory, so we need to check both "ends" of the
401 * address to see if they are in the same page or not.
402 * If not, then we need to make sure the second page
403 * is valid, and bring it into memory if it's not.
404 *
405 * This whole process needs to be repeated for WB3 as well.
406 * <sigh>
407 */
408
409 /* Check WB1 */
410 if (fp->f_fmt7.f_wb1s & WBS_VALID) {
411 printf ("trap: wb1 was valid, not handled yet\n");
412 panictrap(type, code, v, fp);
413 }
414
415 /*
416 * Check WB2
417 * skip if it's for a move16 instruction
418 */
419 if(fp->f_fmt7.f_wb2s & WBS_VALID &&
420 ((fp->f_fmt7.f_wb2s & WBS_TTMASK)==WBS_TT_MOVE16) == 0) {
421 if (_write_back(2, fp->f_fmt7.f_wb2s,
422 fp->f_fmt7.f_wb2d, fp->f_fmt7.f_wb2a, map) != 0)
423 goto nogo;
424 if ((fp->f_fmt7.f_wb2s & WBS_TMMASK)
425 != (code & SSW_TMMASK))
426 panictrap(type, code, v, fp);
427 }
428
429 /* Check WB3 */
430 if(fp->f_fmt7.f_wb3s & WBS_VALID) {
431 struct vm_map *wb3_map;
432
433 if ((fp->f_fmt7.f_wb3s & WBS_TMMASK) == WBS_TM_SDATA)
434 wb3_map = kernel_map;
435 else
436 wb3_map = &vm->vm_map;
437 if (_write_back(3, fp->f_fmt7.f_wb3s,
438 fp->f_fmt7.f_wb3d, fp->f_fmt7.f_wb3a, wb3_map) != 0)
439 goto nogo;
440 }
441 }
442
443 /*
444 * If this was a stack access we keep track of the maximum
445 * accessed stack size. Also, if vm_fault gets a protection
446 * failure it is due to accessing the stack region outside
447 * the current limit and we need to reflect that as an access
448 * error.
449 */
450 if (rv == 0) {
451 if (map != kernel_map && (void *)va >= vm->vm_maxsaddr)
452 uvm_grow(p, va);
453
454 if (type == T_MMUFLT)
455 return;
456 userret(l, fp->f_pc, sticks);
457 return;
458 }
459 nogo:
460 if (type == T_MMUFLT) {
461 if (onfault) {
462 trapcpfault(l, fp, rv);
463 return;
464 }
465 printf("uvm_fault(%p, 0x%lx, 0x%x) -> 0x%x\n",
466 map, va, ftype, rv);
467 printf(" type %x, code [mmu,,ssw]: %x\n",
468 type, code);
469 panictrap(type, code, v, fp);
470 }
471 ksi.ksi_addr = (void *)v;
472 switch (rv) {
473 case ENOMEM:
474 printf("UVM: pid %d (%s), uid %d killed: out of swap\n",
475 p->p_pid, p->p_comm,
476 l->l_cred ? kauth_cred_geteuid(l->l_cred) : -1);
477 ksi.ksi_signo = SIGKILL;
478 break;
479 case EINVAL:
480 ksi.ksi_signo = SIGBUS;
481 ksi.ksi_code = BUS_ADRERR;
482 break;
483 case EACCES:
484 ksi.ksi_signo = SIGSEGV;
485 ksi.ksi_code = SEGV_ACCERR;
486 break;
487 default:
488 ksi.ksi_signo = SIGSEGV;
489 ksi.ksi_code = SEGV_MAPERR;
490 break;
491 }
492 trapsignal(l, &ksi);
493 if ((type & T_USER) == 0)
494 return;
495 userret(l, fp->f_pc, sticks);
496 }
497 /*
498 * Trap is called from locore to handle most types of processor traps,
499 * including events such as simulated software interrupts/AST's.
500 * System calls are broken out for efficiency.
501 */
502 /*ARGSUSED*/
503 void
504 trap(struct frame *fp, int type, u_int code, u_int v)
505 {
506 struct lwp *l;
507 struct proc *p;
508 struct pcb *pcb;
509 ksiginfo_t ksi;
510 u_quad_t sticks = 0;
511
512 l = curlwp;
513 p = l->l_proc;
514 pcb = lwp_getpcb(l);
515
516 curcpu()->ci_data.cpu_ntrap++;
517
518 KSI_INIT_TRAP(&ksi);
519 ksi.ksi_trap = type & ~T_USER;
520
521 if (USERMODE(fp->f_sr)) {
522 type |= T_USER;
523 sticks = p->p_sticks;
524 l->l_md.md_regs = fp->f_regs;
525 LWP_CACHE_CREDS(l, p);
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