1 /* $NetBSD: trap.c,v 1.97 2024/01/20 00:15:32 thorpej 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.97 2024/01/20 00:15:32 thorpej 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/syscall.h>
65 #include <sys/syslog.h>
66 #include <sys/userret.h>
67 #include <sys/kauth.h>
68
69 #ifdef DEBUG
70 #include <dev/cons.h>
71 #endif
72
73 #include <machine/db_machdep.h>
74 #include <machine/pcb.h>
75 #include <machine/psl.h>
76 #include <machine/trap.h>
77 #include <machine/cpu.h>
78 #include <machine/reg.h>
79
80 #include <m68k/cacheops.h>
81
82 #include <uvm/uvm_extern.h>
83
84 #ifdef COMPAT_SUNOS
85 #include <compat/sunos/sunos_syscall.h>
86 extern struct emul emul_sunos;
87 #endif
88
89 #ifdef KGDB
90 #include <sys/kgdb.h>
91 #endif
92
93 void trap(struct frame *, int, u_int, u_int);
94
95 #ifdef DEBUG
96 void dumpssw(u_short);
97 void dumpwb(int, u_short, u_int, u_int);
98 #endif
99
100 static inline void userret(struct lwp *, struct frame *, u_quad_t, u_int, int);
101
102 const char *trap_type[] = {
103 "Bus error",
104 "Address error",
105 "Illegal instruction",
106 "Zero divide",
107 "CHK instruction",
108 "TRAPV instruction",
109 "Privilege violation",
110 "Trace trap",
111 "MMU fault",
112 "SSIR trap",
113 "Format error",
114 "68881 exception",
115 "Coprocessor violation",
116 "Async system trap"
117 };
118 int trap_types = sizeof trap_type / sizeof trap_type[0];
119
120 /*
121 * Size of various exception stack frames (minus the standard 8 bytes)
122 */
123 short exframesize[] = {
124 FMT0SIZE, /* type 0 - normal (68020/030/040/060) */
125 FMT1SIZE, /* type 1 - throwaway (68020/030/040) */
126 FMT2SIZE, /* type 2 - normal 6-word (68020/030/040/060) */
127 FMT3SIZE, /* type 3 - FP post-instruction (68040/060) */
128 FMT4SIZE, /* type 4 - access error/fp disabled (68060) */
129 -1, -1, /* type 5-6 - undefined */
130 FMT7SIZE, /* type 7 - access error (68040) */
131 58, /* type 8 - bus fault (68010) */
132 FMT9SIZE, /* type 9 - coprocessor mid-instruction (68020/030) */
133 FMTASIZE, /* type A - short bus fault (68020/030) */
134 FMTBSIZE, /* type B - long bus fault (68020/030) */
135 -1, -1, -1, -1 /* type C-F - undefined */
136 };
137
138 #ifdef M68060
139 #define KDFAULT_060(c) (cputype == CPU_68060 && ((c) & FSLW_TM_SV))
140 #define WRFAULT_060(c) (cputype == CPU_68060 && ((c) & FSLW_RW_W))
141 #else
142 #define KDFAULT_060(c) 0
143 #define WRFAULT_060(c) 0
144 #endif
145
146 #ifdef M68040
147 #define KDFAULT_040(c) (cputype == CPU_68040 && \
148 ((c) & SSW4_TMMASK) == SSW4_TMKD)
149 #define WRFAULT_040(c) (cputype == CPU_68040 && \
150 ((c) & (SSW4_LK|SSW4_RW)) != SSW4_RW)
151 #else
152 #define KDFAULT_040(c) 0
153 #define WRFAULT_040(c) 0
154 #endif
155
156 #if defined(M68030) || defined(M68020)
157 #define KDFAULT_OTH(c) (cputype <= CPU_68030 && \
158 ((c) & (SSW_DF|SSW_FCMASK)) == (SSW_DF|FC_SUPERD))
159 #define WRFAULT_OTH(c) (cputype <= CPU_68030 && \
160 (((c) & SSW_DF) != 0 && \
161 ((((c) & SSW_RW) == 0) || (((c) & SSW_RM) != 0))))
162 #else
163 #define KDFAULT_OTH(c) 0
164 #define WRFAULT_OTH(c) 0
165 #endif
166
167 #define KDFAULT(c) (KDFAULT_060(c) || KDFAULT_040(c) || KDFAULT_OTH(c))
168 #define WRFAULT(c) (WRFAULT_060(c) || WRFAULT_040(c) || WRFAULT_OTH(c))
169
170 #ifdef DEBUG
171 int mmudebug = 0;
172 int mmupid = -1;
173 #define MDB_FOLLOW 1
174 #define MDB_WBFOLLOW 2
175 #define MDB_WBFAILED 4
176 #define MDB_ISPID(p) ((p) == mmupid)
177 #endif
178
179 /*
180 * trap and syscall both need the following work done before returning
181 * to user mode.
182 */
183 static inline void
userret(struct lwp * l,struct frame * fp,u_quad_t oticks,u_int faultaddr,int fromtrap)184 userret(struct lwp *l, struct frame *fp, u_quad_t oticks, u_int faultaddr,
185 int fromtrap)
186 {
187 struct proc *p = l->l_proc;
188 #ifdef M68040
189 int sig;
190 int beenhere = 0;
191
192 again:
193 #endif
194 /* Invoke MI userret code */
195 mi_userret(l);
196
197 /*
198 * If profiling, charge system time to the trapped pc.
199 */
200 if (p->p_stflag & PST_PROFIL) {
201 extern int psratio;
202
203 addupc_task(l, fp->f_pc,
204 (int)(p->p_sticks - oticks) * psratio);
205 }
206 #ifdef M68040
207 /*
208 * Deal with user mode writebacks (from trap, or from sigreturn).
209 * If any writeback fails, go back and attempt signal delivery.
210 * unless we have already been here and attempted the writeback
211 * (e.g. bad address with user ignoring SIGSEGV). In that case
212 * we just return to the user without successfully completing
213 * the writebacks. Maybe we should just drop the sucker?
214 */
215 if (cputype == CPU_68040 && fp->f_format == FMT7) {
216 if (beenhere) {
217 #ifdef DEBUG
218 if (mmudebug & MDB_WBFAILED)
219 printf(fromtrap ?
220 "pid %d(%s): writeback aborted, pc=%x, fa=%x\n" :
221 "pid %d(%s): writeback aborted in sigreturn, pc=%x\n",
222 p->p_pid, p->p_comm, fp->f_pc, faultaddr);
223 #endif
224 } else if ((sig = m68040_writeback(fp, fromtrap))) {
225 ksiginfo_t ksi;
226 beenhere = 1;
227 oticks = p->p_sticks;
228 (void)memset(&ksi, 0, sizeof(ksi));
229 ksi.ksi_signo = sig;
230 ksi.ksi_addr = (void *)faultaddr;
231 ksi.ksi_code = BUS_OBJERR;
232 trapsignal(l, &ksi);
233 goto again;
234 }
235 }
236 #endif
237 }
238
239 /*
240 * Used by the common m68k syscall() and child_return() functions.
241 * XXX: Temporary until all m68k ports share common trap()/userret() code.
242 */
243 void machine_userret(struct lwp *, struct frame *, u_quad_t);
244
245 void
machine_userret(struct lwp * l,struct frame * f,u_quad_t t)246 machine_userret(struct lwp *l, struct frame *f, u_quad_t t)
247 {
248
249 userret(l, f, t, 0, 0);
250 }
251
252 /*
253 * Trap is called from locore to handle most types of processor traps,
254 * including events such as simulated software interrupts/AST's.
255 * System calls are broken out for efficiency.
256 */
257 /*ARGSUSED*/
258 void
trap(struct frame * fp,int type,unsigned code,unsigned v)259 trap(struct frame *fp, int type, unsigned code, unsigned v)
260 {
261 struct lwp *l;
262 struct proc *p;
263 struct pcb *pcb;
264 void *onfault;
265 ksiginfo_t ksi;
266 int s;
267 int rv;
268 u_quad_t sticks = 0 /* XXX initialiser works around compiler bug */;
269 static int panicking __diagused;
270
271 curcpu()->ci_data.cpu_ntrap++;
272 l = curlwp;
273 p = l->l_proc;
274 pcb = lwp_getpcb(l);
275
276 KSI_INIT_TRAP(&ksi);
277 ksi.ksi_trap = type & ~T_USER;
278
279 if (USERMODE(fp->f_sr)) {
280 type |= T_USER;
281 sticks = p->p_sticks;
282 l->l_md.md_regs = fp->f_regs;
283 }
284 switch (type) {
285
286 default:
287 dopanic:
288 /*
289 * Let the kernel debugger see the trap frame that
290 * caused us to panic. This is a convenience so
291 * one can see registers at the point of failure.
292 */
293 s = splhigh();
294 panicking = 1;
295 printf("trap type %d, code = 0x%x, v = 0x%x\n", type, code, v);
296 printf("%s program counter = 0x%x\n",
297 (type & T_USER) ? "user" : "kernel", fp->f_pc);
298 #ifdef KGDB
299 /* If connected, step or cont returns 1 */
300 if (kgdb_trap(type, (db_regs_t *)fp))
301 goto kgdb_cont;
302 #endif
303 #ifdef DDB
304 (void)kdb_trap(type, (db_regs_t *)fp);
305 #endif
306 #ifdef KGDB
307 kgdb_cont:
308 #endif
309 splx(s);
310 if (panicstr) {
311 printf("trap during panic!\n");
312 #ifdef DEBUG
313 /* XXX should be a machine-dependent hook */
314 printf("(press a key)\n");
315 cnpollc(1);
316 (void)cngetc();
317 cnpollc(0);
318 #endif
319 }
320 regdump((struct trapframe *)fp, 128);
321 type &= ~T_USER;
322 if ((u_int)type < trap_types)
323 panic(trap_type[type]);
324 panic("trap");
325
326 case T_BUSERR: /* kernel bus error */
327 onfault = pcb->pcb_onfault;
328 if (onfault == NULL)
329 goto dopanic;
330 rv = EFAULT;
331 /* FALLTHROUGH */
332
333 copyfault:
334 /*
335 * If we have arranged to catch this fault in any of the
336 * copy to/from user space routines, set PC to return to
337 * indicated location and set flag informing buserror code
338 * that it may need to clean up stack frame.
339 */
340 fp->f_stackadj = exframesize[fp->f_format];
341 fp->f_format = fp->f_vector = 0;
342 fp->f_pc = (int)onfault;
343 fp->f_regs[D0] = rv;
344 return;
345
346 case T_BUSERR|T_USER: /* bus error */
347 case T_ADDRERR|T_USER: /* address error */
348 ksi.ksi_addr = (void *)v;
349 ksi.ksi_signo = SIGBUS;
350 ksi.ksi_code = (type == (T_BUSERR|T_USER)) ?
351 BUS_OBJERR : BUS_ADRERR;
352 break;
353
354 case T_COPERR: /* kernel coprocessor violation */
355 case T_FMTERR|T_USER: /* do all RTE errors come in as T_USER? */
356 case T_FMTERR: /* ...just in case... */
357 /*
358 * The user has most likely trashed the RTE or FP state info
359 * in the stack frame of a signal handler.
360 */
361 printf("pid %d: kernel %s exception\n", p->p_pid,
362 type==T_COPERR ? "coprocessor" : "format");
363 type |= T_USER;
364
365 mutex_enter(p->p_lock);
366 SIGACTION(p, SIGILL).sa_handler = SIG_DFL;
367 sigdelset(&p->p_sigctx.ps_sigignore, SIGILL);
368 sigdelset(&p->p_sigctx.ps_sigcatch, SIGILL);
369 sigdelset(&l->l_sigmask, SIGILL);
370 mutex_exit(p->p_lock);
371
372 ksi.ksi_signo = SIGILL;
373 ksi.ksi_addr = (void *)(int)fp->f_format;
374 /* XXX was ILL_RESAD_FAULT */
375 ksi.ksi_code = (type == T_COPERR) ?
376 ILL_COPROC : ILL_ILLOPC;
377 break;
378
379 case T_COPERR|T_USER: /* user coprocessor violation */
380 /* What is a proper response here? */
381 ksi.ksi_signo = SIGFPE;
382 ksi.ksi_code = FPE_FLTINV;
383 break;
384
385 case T_FPERR|T_USER: /* 68881 exceptions */
386 /*
387 * We pass along the 68881 status register which locore stashed
388 * in code for us.
389 */
390 ksi.ksi_signo = SIGFPE;
391 ksi.ksi_code = fpsr2siginfocode(code);
392 break;
393
394 #ifdef M68040
395 case T_FPEMULI|T_USER: /* unimplemented FP instruction */
396 case T_FPEMULD|T_USER: /* unimplemented FP data type */
397 /* XXX need to FSAVE */
398 printf("pid %d(%s): unimplemented FP %s at %x (EA %x)\n",
399 p->p_pid, p->p_comm,
400 fp->f_format == 2 ? "instruction" : "data type",
401 fp->f_pc, fp->f_fmt2.f_iaddr);
402 /* XXX need to FRESTORE */
403 ksi.ksi_signo = SIGFPE;
404 ksi.ksi_code = FPE_FLTINV;
405 break;
406 #endif
407
408 case T_ILLINST|T_USER: /* illegal instruction fault */
409 case T_PRIVINST|T_USER: /* privileged instruction fault */
410 ksi.ksi_addr = (void *)(int)fp->f_format;
411 /* XXX was ILL_PRIVIN_FAULT */
412 ksi.ksi_signo = SIGILL;
413 ksi.ksi_code = (type == (T_PRIVINST|T_USER)) ?
414 ILL_PRVOPC : ILL_ILLOPC;
415 break;
416
417 case T_ZERODIV|T_USER: /* Divide by zero */
418 ksi.ksi_addr = (void *)(int)fp->f_format;
419 /* XXX was FPE_INTDIV_TRAP */
420 ksi.ksi_signo = SIGFPE;
421 ksi.ksi_code = FPE_FLTDIV;
422 break;
423
424 case T_CHKINST|T_USER: /* CHK instruction trap */
425 ksi.ksi_addr = (void *)(int)fp->f_format;
426 /* XXX was FPE_SUBRNG_TRAP */
427 ksi.ksi_signo = SIGFPE;
428 break;
429
430 case T_TRAPVINST|T_USER: /* TRAPV instruction trap */
431 ksi.ksi_addr = (void *)(int)fp->f_format;
432 /* XXX was FPE_INTOVF_TRAP */
433 ksi.ksi_signo = SIGFPE;
434 break;
435
436 /*
437 * XXX: Trace traps are a nightmare.
438 *
439 * HP-UX uses trap #1 for breakpoints,
440 * NetBSD/m68k uses trap #2,
441 * SUN 3.x uses trap #15,
442 * DDB and KGDB uses trap #15 (for kernel breakpoints;
443 * handled elsewhere).
444 *
445 * NetBSD and HP-UX traps both get mapped by locore.s into T_TRACE.
446 * SUN 3.x traps get passed through as T_TRAP15 and are not really
447 * supported yet.
448 *
449 * XXX: We should never get kernel-mode T_TRAP15
450 * XXX: because locore.s now gives them special treatment.
451 */
452 case T_TRAP15: /* kernel breakpoint */
453 #ifdef DEBUG
454 printf("unexpected kernel trace trap, type = %d\n", type);
455 printf("program counter = 0x%x\n", fp->f_pc);
456 #endif
457 fp->f_sr &= ~PSL_T;
458 return;
459
460 case T_TRACE|T_USER: /* user trace trap */
461 #ifdef COMPAT_SUNOS
462 /*
463 * SunOS uses Trap #2 for a "CPU cache flush".
464 * Just flush the on-chip caches and return.
465 */
466 if (p->p_emul == &emul_sunos) {
467 ICIA();
468 DCIU();
469 return;
470 }
471 #endif
472 /* FALLTHROUGH */
473 case T_TRACE: /* tracing a trap instruction */
474 case T_TRAP15|T_USER: /* SUN user trace trap */
475 fp->f_sr &= ~PSL_T;
476 ksi.ksi_signo = SIGTRAP;
477 break;
478
479 case T_ASTFLT: /* system async trap, cannot happen */
480 goto dopanic;
481
482 case T_ASTFLT|T_USER: /* user async trap */
483 astpending = 0;
484 /*
485 * We check for software interrupts first. This is because
486 * they are at a higher level than ASTs, and on a VAX would
487 * interrupt the AST. We assume that if we are processing
488 * an AST that we must be at IPL0 so we don't bother to
489 * check. Note that we ensure that we are at least at SIR
490 * IPL while processing the SIR.
491 */
492 spl1();
493 /* fall into... */
494
495 case T_SSIR: /* software interrupt */
496 case T_SSIR|T_USER:
497 /*
498 * If this was not an AST trap, we are all done.
499 */
500 if (type != (T_ASTFLT|T_USER)) {
501 curcpu()->ci_data.cpu_ntrap--;
502 return;
503 }
504 spl0();
505 if (l->l_pflag & LP_OWEUPC) {
506 l->l_pflag &= ~LP_OWEUPC;
507 ADDUPROF(l);
508 }
509 goto out;
510
511 case T_MMUFLT: /* kernel mode page fault */
512 case T_MMUFLT|T_USER: /* page fault */
513 {
514 vaddr_t va;
515 struct vmspace *vm = p->p_vmspace;
516 struct vm_map *map;
517 vm_prot_t ftype;
518 extern struct vm_map *kernel_map;
519
520 onfault = pcb->pcb_onfault;
521
522 #ifdef DEBUG
523 if ((mmudebug & MDB_WBFOLLOW) || MDB_ISPID(p->p_pid))
524 printf("trap: T_MMUFLT pid=%d, code=%x, v=%x, pc=%x, sr=%x\n",
525 p->p_pid, code, v, fp->f_pc, fp->f_sr);
526 #endif
527 /*
528 * It is only a kernel address space fault iff:
529 * 1. (type & T_USER) == 0 and
530 * 2. pcb_onfault not set or
531 * 3. pcb_onfault set but supervisor space data fault
532 * The last can occur during an exec() copyin where the
533 * argument space is lazy-allocated.
534 */
535 if ((type & T_USER) == 0 && (onfault == NULL || KDFAULT(code)))
536 map = kernel_map;
537 else {
538 map = vm ? &vm->vm_map : kernel_map;
539 }
540
541 if (WRFAULT(code))
542 ftype = VM_PROT_WRITE;
543 else
544 ftype = VM_PROT_READ;
545
546 va = trunc_page((vaddr_t)v);
547
548 if (map == kernel_map && va == 0) {
549 printf("trap: bad kernel %s access at 0x%x\n",
550 (ftype & VM_PROT_WRITE) ? "read/write" :
551 "read", v);
552 goto dopanic;
553 }
554
555 #ifdef DIAGNOSTIC
556 if (intr_depth && !panicking) {
557 printf("trap: calling uvm_fault() from interrupt!\n");
558 goto dopanic;
559 }
560 #endif
561
562 pcb->pcb_onfault = NULL;
563 rv = uvm_fault(map, va, ftype);
564 pcb->pcb_onfault = onfault;
565 #ifdef DEBUG
566 if (rv && MDB_ISPID(p->p_pid))
567 printf("uvm_fault(%p, 0x%lx, 0x%x) -> 0x%x\n",
568 map, va, ftype, rv);
569 #endif
570 /*
571 * If this was a stack access we keep track of the maximum
572 * accessed stack size. Also, if vm_fault gets a protection
573 * failure it is due to accessing the stack region outside
574 * the current limit and we need to reflect that as an access
575 * error.
576 */
577 if (rv == 0) {
578 if (map != kernel_map && (void *)va >= vm->vm_maxsaddr)
579 uvm_grow(p, va);
580
581 if (type == T_MMUFLT) {
582 #ifdef M68040
583 if (cputype == CPU_68040)
584 (void) m68040_writeback(fp, 1);
585 #endif
586 return;
587 }
588 goto out;
589 }
590 if (rv == EACCES) {
591 ksi.ksi_code = SEGV_ACCERR;
592 rv = EFAULT;
593 } else
594 ksi.ksi_code = SEGV_MAPERR;
595 if (type == T_MMUFLT) {
596 if (onfault)
597 goto copyfault;
598 printf("uvm_fault(%p, 0x%lx, 0x%x) -> 0x%x\n",
599 map, va, ftype, rv);
600 printf(" type %x, code [mmu,,ssw]: %x\n",
601 type, code);
602 goto dopanic;
603 }
604 ksi.ksi_addr = (void *)v;
605 switch (rv) {
606 case ENOMEM:
607 printf("UVM: pid %d (%s), uid %d killed: out of swap\n",
608 p->p_pid, p->p_comm,
609 l->l_cred ?
610 kauth_cred_geteuid(l->l_cred) : -1);
611 ksi.ksi_signo = SIGKILL;
612 break;
613 case EINVAL:
614 ksi.ksi_signo = SIGBUS;
615 ksi.ksi_code = BUS_ADRERR;
616 break;
617 case EACCES:
618 ksi.ksi_signo = SIGSEGV;
619 ksi.ksi_code = SEGV_ACCERR;
620 break;
621 default:
622 ksi.ksi_signo = SIGSEGV;
623 ksi.ksi_code = SEGV_MAPERR;
624 break;
625 }
626 break;
627 }
628 }
629 trapsignal(l, &ksi);
630 if ((type & T_USER) == 0)
631 return;
632 out:
633 userret(l, fp, sticks, v, 1);
634 }
635