xref: /netbsd-src/sys/arch/news68k/news68k/trap.c (revision c13a5359d541fd49b4c406f5b12209b1640235a5)
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