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