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