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