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