xref: /netbsd-src/sys/arch/vax/vax/trap.c (revision 6a493d6bc668897c91594964a732d38505b70cbb)
1 /*	$NetBSD: trap.c,v 1.132 2013/10/25 16:30:52 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.132 2013/10/25 16:30:52 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 			code = SEGV_ACCERR;
248 			if (rv == 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 			} else {
256 				sig = SIGSEGV;
257 				if (rv != EACCES)
258 					code = SEGV_MAPERR;
259 			}
260 		} else {
261 			trapsig = false;
262 			if (map != kernel_map && addr > 0
263 			    && (void *)addr >= vm->vm_maxsaddr)
264 				uvm_grow(p, addr);
265 		}
266 		break;
267 
268 	case T_BPTFLT|T_USER:
269 		sig = SIGTRAP;
270 		code = TRAP_BRKPT;
271 		break;
272 	case T_TRCTRAP|T_USER:
273 		sig = SIGTRAP;
274 		code = TRAP_TRACE;
275 		tf->tf_psl &= ~PSL_T;
276 		break;
277 
278 	case T_PRIVINFLT|T_USER:
279 		sig = SIGILL;
280 		code = ILL_PRVOPC;
281 		break;
282 	case T_RESADFLT|T_USER:
283 		sig = SIGILL;
284 		code = ILL_ILLADR;
285 		break;
286 	case T_RESOPFLT|T_USER:
287 		sig = SIGILL;
288 		code = ILL_ILLOPC;
289 		break;
290 
291 	case T_XFCFLT|T_USER:
292 		sig = SIGEMT;
293 		break;
294 
295 	case T_ARITHFLT|T_USER:
296 		sig = SIGFPE;
297 		switch (tf->tf_code) {
298 		case ATRP_INTOVF: code = FPE_INTOVF; break;
299 		case ATRP_INTDIV: code = FPE_INTDIV; break;
300 		case ATRP_FLTOVF: code = FPE_FLTOVF; break;
301 		case ATRP_FLTDIV: code = FPE_FLTDIV; break;
302 		case ATRP_FLTUND: code = FPE_FLTUND; break;
303 		case ATRP_DECOVF: code = FPE_INTOVF; break;
304 		case ATRP_FLTSUB: code = FPE_FLTSUB; break;
305 		case AFLT_FLTDIV: code = FPE_FLTDIV; break;
306 		case AFLT_FLTUND: code = FPE_FLTUND; break;
307 		case AFLT_FLTOVF: code = FPE_FLTOVF; break;
308 		default:	  code = FPE_FLTINV; break;
309 		}
310 		break;
311 
312 	case T_ASTFLT|T_USER:
313 		mtpr(AST_NO,PR_ASTLVL);
314 		trapsig = false;
315 		if (curcpu()->ci_want_resched)
316 			preempt();
317 		break;
318 
319 #ifdef DDB
320 	case T_BPTFLT: /* Kernel breakpoint */
321 	case T_KDBTRAP:
322 	case T_KDBTRAP|T_USER:
323 	case T_TRCTRAP:
324 		kdb_trap(tf);
325 		return;
326 #endif
327 	}
328 	if (trapsig) {
329 		ksiginfo_t ksi;
330 		if ((sig == SIGSEGV || sig == SIGILL)
331 		    && cpu_printfataltraps
332 		    && (p->p_slflag & PSL_TRACED) == 0
333 		    && !sigismember(&p->p_sigctx.ps_sigcatch, sig))
334 			printf("pid %d.%d (%s): sig %d: type %lx, code %lx, pc %lx, psl %lx\n",
335 			       p->p_pid, l->l_lid, p->p_comm, sig, tf->tf_trap,
336 			       tf->tf_code, tf->tf_pc, tf->tf_psl);
337 		KSI_INIT_TRAP(&ksi);
338 		ksi.ksi_signo = sig;
339 		ksi.ksi_trap = tf->tf_trap;
340 		ksi.ksi_addr = (void *)tf->tf_code;
341 		ksi.ksi_code = code;
342 
343 		/*
344 		 * Arithmetic exceptions can be of two kinds:
345 		 * - traps (codes 1..7), where pc points to the
346 		 *   next instruction to execute.
347 		 * - faults (codes 8..10), where pc points to the
348 		 *   faulting instruction.
349 		 * In the latter case, we need to advance pc by ourselves
350 		 * to prevent a signal loop.
351 		 *
352 		 * XXX this is gross -- miod
353 		 */
354 		if (type == (T_ARITHFLT | T_USER) && (tf->tf_code & 8))
355 			tf->tf_pc = skip_opcode(tf->tf_pc);
356 
357 		trapsignal(l, &ksi);
358 	}
359 
360 	if (!usermode)
361 		return;
362 
363 	userret(l, tf, oticks);
364 }
365 
366 void
367 setregs(struct lwp *l, struct exec_package *pack, vaddr_t stack)
368 {
369 	struct trapframe * const tf = l->l_md.md_utf;
370 
371 	tf->tf_pc = pack->ep_entry + 2;
372 	tf->tf_sp = stack;
373 	tf->tf_r6 = stack;				/* for ELF */
374 	tf->tf_r7 = 0;				/* for ELF */
375 	tf->tf_r8 = 0;				/* for ELF */
376 	tf->tf_r9 = l->l_proc->p_psstrp;		/* for ELF */
377 }
378 
379 
380 /*
381  * Start a new LWP
382  */
383 void
384 startlwp(void *arg)
385 {
386 	ucontext_t * const uc = arg;
387 	lwp_t * const l = curlwp;
388 	int error __diagused;
389 
390 	error = cpu_setmcontext(l, &uc->uc_mcontext, uc->uc_flags);
391 	KASSERT(error == 0);
392 
393 	kmem_free(uc, sizeof(ucontext_t));
394 	/* XXX - profiling spoiled here */
395 	userret(l, l->l_md.md_utf, l->l_proc->p_sticks);
396 }
397