1/*	$NetBSD: trap.c,v 1.138 2023/10/05 19:41:06 ad Exp $     */
2
3/*
4 * Copyright (c) 1994 Ludd, University of Lule}, Sweden.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 /* All bugs are subject to removal without further notice */
29
30#include <sys/cdefs.h>
31__KERNEL_RCSID(0, "$NetBSD: trap.c,v 1.138 2023/10/05 19:41:06 ad Exp $");
32
33#include "opt_ddb.h"
34#include "opt_multiprocessor.h"
35
36#include <sys/param.h>
37#include <sys/systm.h>
38#include <sys/cpu.h>
39#include <sys/exec.h>
40#include <sys/kauth.h>
41#include <sys/proc.h>
42#include <sys/signalvar.h>
43
44#include <uvm/uvm_extern.h>
45
46#include <machine/trap.h>
47#include <machine/userret.h>
48
49#ifdef DDB
50#include <machine/db_machdep.h>
51#endif
52#include <vax/vax/db_disasm.h>
53#include <kern/syscalls.c>
54#include <sys/ktrace.h>
55
56#ifdef TRAPDEBUG
57volatile int faultdebug = 0;
58#endif
59
60int	cpu_printfataltraps = 0;
61
62void	trap (struct trapframe *);
63
64const char * const traptypes[]={
65	"reserved addressing",
66	"privileged instruction",
67	"reserved operand",
68	"breakpoint instruction",
69	"XFC instruction",
70	"system call ",
71	"arithmetic trap",
72	"asynchronous system trap",
73	"page table length fault",
74	"translation violation fault",
75	"trace trap",
76	"compatibility mode fault",
77	"access violation fault",
78	"",
79	"",
80	"KSP invalid",
81	"",
82	"kernel debugger trap"
83};
84int no_traps = 18;
85
86#define USERMODE_P(tf)   ((((tf)->tf_psl) & (PSL_U)) == PSL_U)
87
88void
89trap(struct trapframe *tf)
90{
91	u_int	sig = 0, type = tf->tf_trap, code = 0;
92	u_int	rv, addr;
93	bool trapsig = true;
94	const bool usermode = USERMODE_P(tf);
95	struct lwp * const l = curlwp;
96	struct proc * const p = l->l_proc;
97	struct pcb * const pcb = lwp_getpcb(l);
98	u_quad_t oticks = 0;
99	struct vmspace *vm;
100	struct vm_map *map;
101	vm_prot_t ftype;
102	void *onfault = pcb->pcb_onfault;
103
104	KASSERT(p != NULL);
105	curcpu()->ci_data.cpu_ntrap++;
106	if (usermode) {
107		type |= T_USER;
108		oticks = p->p_sticks;
109		l->l_md.md_utf = tf;
110	}
111
112	type &= ~(T_WRITE|T_PTEFETCH);
113
114
115#ifdef TRAPDEBUG
116if(tf->tf_trap==7) goto fram;
117if(faultdebug)printf("Trap: type %lx, code %lx, pc %lx, psl %lx\n",
118		tf->tf_trap, tf->tf_code, tf->tf_pc, tf->tf_psl);
119fram:
120#endif
121	switch (type) {
122
123	default:
124#ifdef DDB
125		kdb_trap(tf);
126#endif
127		panic("trap: type %x, code %x, pc %x, psl %x",
128		    (u_int)tf->tf_trap, (u_int)tf->tf_code,
129		    (u_int)tf->tf_pc, (u_int)tf->tf_psl);
130
131	case T_KSPNOTVAL:
132		panic("%d.%d (%s): KSP invalid %#x@%#x pcb %p fp %#x psl %#x)",
133		    p->p_pid, l->l_lid, l->l_name ? l->l_name : "??",
134		    mfpr(PR_KSP), (u_int)tf->tf_pc, pcb,
135		    (u_int)tf->tf_fp, (u_int)tf->tf_psl);
136
137	case T_TRANSFLT|T_USER:
138	case T_TRANSFLT:
139		/*
140		 * BUG! BUG! BUG! BUG! BUG!
141		 * Due to a hardware bug (at in least KA65x CPUs) a double
142		 * page table fetch trap will cause a translation fault
143		 * even if access in the SPT PTE entry specifies 'no access'.
144		 * In for example section 6.4.2 in VAX Architecture
145		 * Reference Manual it states that if a page both are invalid
146		 * and have no access set, a 'access violation fault' occurs.
147		 * Therefore, we must fall through here...
148		 */
149#ifdef nohwbug
150		panic("translation fault");
151#endif
152
153	case T_PTELEN|T_USER:	/* Page table length exceeded */
154	case T_ACCFLT|T_USER:
155		if (tf->tf_code < 0) { /* Check for kernel space */
156			sig = SIGSEGV;
157			code = SEGV_ACCERR;
158			break;
159		}
160
161	case T_PTELEN:
162#ifndef MULTIPROCESSOR
163		/*
164		 * If we referred to an address beyond the end of the system
165		 * page table, it may be due to a failed CAS
166		 * restartable-atomic-sequence.  If it is, restart it at the
167		 * beginning and restart.
168		 */
169		{
170			extern const uint8_t cas32_ras_start[], cas32_ras_end[];
171			if (tf->tf_code == CASMAGIC
172			    && tf->tf_pc >= (uintptr_t) cas32_ras_start
173			    && tf->tf_pc < (uintptr_t) cas32_ras_end) {
174				tf->tf_pc = (uintptr_t) cas32_ras_start;
175				trapsig = false;
176				break;
177			}
178		}
179		/* FALLTHROUGH */
180#endif
181	case T_ACCFLT:
182#ifdef TRAPDEBUG
183if(faultdebug)printf("trap accflt type %lx, code %lx, pc %lx, psl %lx\n",
184			tf->tf_trap, tf->tf_code, tf->tf_pc, tf->tf_psl);
185#endif
186#ifdef DIAGNOSTIC
187		if (p == 0)
188			panic("trap: access fault: addr %lx code %lx",
189			    tf->tf_pc, tf->tf_code);
190		if (tf->tf_psl & PSL_IS)
191			panic("trap: pflt on IS");
192#endif
193
194		/*
195		 * Page tables are allocated in pmap_enter(). We get
196		 * info from below if it is a page table fault, but
197		 * UVM may want to map in pages without faults, so
198		 * because we must check for PTE pages anyway we don't
199		 * bother doing it here.
200		 */
201		addr = trunc_page(tf->tf_code);
202		if (!usermode && (tf->tf_code < 0)) {
203			vm = NULL;
204			map = kernel_map;
205
206		} else {
207			vm = p->p_vmspace;
208			map = &vm->vm_map;
209		}
210
211		if (tf->tf_trap & T_WRITE)
212			ftype = VM_PROT_WRITE;
213		else
214			ftype = VM_PROT_READ;
215
216		pcb->pcb_onfault = NULL;
217		rv = uvm_fault(map, addr, ftype);
218		pcb->pcb_onfault = onfault;
219		if (rv != 0) {
220			if (!usermode) {
221				if (onfault) {
222					pcb->pcb_onfault = NULL;
223					tf->tf_pc = (unsigned)onfault;
224					tf->tf_psl &= ~PSL_FPD;
225					tf->tf_r0 = rv;
226					return;
227				}
228				printf("r0=%08lx r1=%08lx r2=%08lx r3=%08lx ",
229				    tf->tf_r0, tf->tf_r1, tf->tf_r2, tf->tf_r3);
230				printf("r4=%08lx r5=%08lx r6=%08lx r7=%08lx\n",
231				    tf->tf_r4, tf->tf_r5, tf->tf_r6, tf->tf_r7);
232				printf(
233				    "r8=%08lx r9=%08lx r10=%08lx r11=%08lx\n",
234				    tf->tf_r8, tf->tf_r9, tf->tf_r10,
235				    tf->tf_r11);
236				printf("ap=%08lx fp=%08lx sp=%08lx pc=%08lx\n",
237				    tf->tf_ap, tf->tf_fp, tf->tf_sp, tf->tf_pc);
238				panic("SEGV in kernel mode: pc %#lx addr %#lx",
239				    tf->tf_pc, tf->tf_code);
240			}
241			switch (rv) {
242			case ENOMEM:
243				printf("UVM: pid %d (%s), uid %d killed: "
244				       "out of swap\n",
245				       p->p_pid, p->p_comm,
246				       l->l_cred ?
247				       kauth_cred_geteuid(l->l_cred) : -1);
248				sig = SIGKILL;
249				code = SI_NOINFO;
250				break;
251			case EINVAL:
252				code = BUS_ADRERR;
253				sig = SIGBUS;
254				break;
255			case EACCES:
256				code = SEGV_ACCERR;
257				sig = SIGSEGV;
258				break;
259			default:
260				code = SEGV_MAPERR;
261				sig = SIGSEGV;
262				break;
263			}
264		} else {
265			trapsig = false;
266			if (map != kernel_map && addr > 0
267			    && (void *)addr >= vm->vm_maxsaddr)
268				uvm_grow(p, addr);
269		}
270		break;
271
272	case T_BPTFLT|T_USER:
273		sig = SIGTRAP;
274		code = TRAP_BRKPT;
275		break;
276	case T_TRCTRAP|T_USER:
277		sig = SIGTRAP;
278		code = TRAP_TRACE;
279		tf->tf_psl &= ~PSL_T;
280		break;
281
282	case T_PRIVINFLT|T_USER:
283		sig = SIGILL;
284		code = ILL_PRVOPC;
285		break;
286	case T_RESADFLT|T_USER:
287		sig = SIGILL;
288		code = ILL_ILLADR;
289		break;
290	case T_RESOPFLT|T_USER:
291		sig = SIGILL;
292		code = ILL_ILLOPC;
293		break;
294
295	case T_XFCFLT|T_USER:
296		sig = SIGEMT;
297		break;
298
299	case T_ARITHFLT|T_USER:
300		sig = SIGFPE;
301		switch (tf->tf_code) {
302		case ATRP_INTOVF: code = FPE_INTOVF; break;
303		case ATRP_INTDIV: code = FPE_INTDIV; break;
304		case ATRP_FLTOVF: code = FPE_FLTOVF; break;
305		case ATRP_FLTDIV: code = FPE_FLTDIV; break;
306		case ATRP_FLTUND: code = FPE_FLTUND; break;
307		case ATRP_DECOVF: code = FPE_INTOVF; break;
308		case ATRP_FLTSUB: code = FPE_FLTSUB; break;
309		case AFLT_FLTDIV: code = FPE_FLTDIV; break;
310		case AFLT_FLTUND: code = FPE_FLTUND; break;
311		case AFLT_FLTOVF: code = FPE_FLTOVF; break;
312		default:	  code = FPE_FLTINV; break;
313		}
314		break;
315
316	case T_ASTFLT|T_USER:
317		pcb->P0LR = (pcb->P0LR & ~AST_MASK) | AST_PCB;
318		mtpr(AST_NO,PR_ASTLVL);
319		trapsig = false;
320		break;
321
322#ifdef DDB
323	case T_BPTFLT: /* Kernel breakpoint */
324	case T_KDBTRAP:
325	case T_KDBTRAP|T_USER:
326	case T_TRCTRAP:
327		kdb_trap(tf);
328		return;
329#endif
330	}
331	if (trapsig) {
332		ksiginfo_t ksi;
333		if ((sig == SIGSEGV || sig == SIGILL)
334		    && cpu_printfataltraps
335		    && (p->p_slflag & PSL_TRACED) == 0
336		    && !sigismember(&p->p_sigctx.ps_sigcatch, sig))
337			printf("pid %d.%d (%s): sig %d: type %lx, code %lx, pc %lx, psl %lx\n",
338			       p->p_pid, l->l_lid, p->p_comm, sig, tf->tf_trap,
339			       tf->tf_code, tf->tf_pc, tf->tf_psl);
340		KSI_INIT_TRAP(&ksi);
341		ksi.ksi_signo = sig;
342		ksi.ksi_trap = tf->tf_trap;
343		ksi.ksi_addr = (void *)tf->tf_code;
344		ksi.ksi_code = code;
345
346		/*
347		 * Arithmetic exceptions can be of two kinds:
348		 * - traps (codes 1..7), where pc points to the
349		 *   next instruction to execute.
350		 * - faults (codes 8..10), where pc points to the
351		 *   faulting instruction.
352		 * In the latter case, we need to advance pc by ourselves
353		 * to prevent a signal loop.
354		 *
355		 * XXX this is gross -- miod
356		 */
357		if (type == (T_ARITHFLT | T_USER) && (tf->tf_code & 8))
358			tf->tf_pc = skip_opcode(tf->tf_pc);
359
360		trapsignal(l, &ksi);
361	}
362
363	if (!usermode)
364		return;
365
366	userret(l, tf, oticks);
367}
368
369void
370setregs(struct lwp *l, struct exec_package *pack, vaddr_t stack)
371{
372	struct trapframe * const tf = l->l_md.md_utf;
373
374	tf->tf_pc = pack->ep_entry + 2;
375	tf->tf_sp = stack;
376	tf->tf_r6 = stack;				/* for ELF */
377	tf->tf_r7 = 0;				/* for ELF */
378	tf->tf_r8 = 0;				/* for ELF */
379	tf->tf_r9 = l->l_proc->p_psstrp;		/* for ELF */
380}
381
382
383/*
384 * Start a new LWP
385 */
386void
387startlwp(void *arg)
388{
389	ucontext_t * const uc = arg;
390	lwp_t * const l = curlwp;
391	int error __diagused;
392
393	error = cpu_setmcontext(l, &uc->uc_mcontext, uc->uc_flags);
394	KASSERT(error == 0);
395
396	kmem_free(uc, sizeof(ucontext_t));
397	/* XXX - profiling spoiled here */
398	userret(l, l->l_md.md_utf, l->l_proc->p_sticks);
399}
400