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