trap.c revision 1.97
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>
86extern struct emul emul_sunos;
87#endif
88
89#ifdef KGDB
90#include <sys/kgdb.h>
91#endif
92
93void	trap(struct frame *, int, u_int, u_int);
94
95#ifdef DEBUG
96void	dumpssw(u_short);
97void	dumpwb(int, u_short, u_int, u_int);
98#endif
99
100static inline void userret(struct lwp *, struct frame *, u_quad_t, u_int, int);
101
102const 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};
118int	trap_types = sizeof trap_type / sizeof trap_type[0];
119
120/*
121 * Size of various exception stack frames (minus the standard 8 bytes)
122 */
123short	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
171int mmudebug = 0;
172int 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 */
183static inline void
184userret(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
192again:
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 */
243void machine_userret(struct lwp *, struct frame *, u_quad_t);
244
245void
246machine_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*/
258void
259trap(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;
632out:
633	userret(l, fp, sticks, v, 1);
634}
635