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