xref: /netbsd-src/sys/arch/vax/vax/trap.c (revision 1b9578b8c2c1f848eeb16dabbfd7d1f0d9fdefbd)
1 /*	$NetBSD: trap.c,v 1.128 2011/07/03 02:18:21 matt 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.128 2011/07/03 02:18:21 matt 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/sa.h>
48 #include <sys/savar.h>
49 #include <sys/signalvar.h>
50 
51 #include <uvm/uvm_extern.h>
52 
53 #include <machine/trap.h>
54 #include <machine/userret.h>
55 
56 #ifdef DDB
57 #include <machine/db_machdep.h>
58 #endif
59 #include <vax/vax/db_disasm.h>
60 #include <kern/syscalls.c>
61 #include <sys/ktrace.h>
62 
63 #ifdef TRAPDEBUG
64 volatile int faultdebug = 0;
65 #endif
66 
67 int	cpu_printfataltraps = 0;
68 
69 void	trap (struct trapframe *);
70 
71 const char * const traptypes[]={
72 	"reserved addressing",
73 	"privileged instruction",
74 	"reserved operand",
75 	"breakpoint instruction",
76 	"XFC instruction",
77 	"system call ",
78 	"arithmetic trap",
79 	"asynchronous system trap",
80 	"page table length fault",
81 	"translation violation fault",
82 	"trace trap",
83 	"compatibility mode fault",
84 	"access violation fault",
85 	"",
86 	"",
87 	"KSP invalid",
88 	"",
89 	"kernel debugger trap"
90 };
91 int no_traps = 18;
92 
93 #define USERMODE_P(tf)   ((((tf)->tf_psl) & (PSL_U)) == PSL_U)
94 
95 void
96 trap(struct trapframe *tf)
97 {
98 	u_int	sig = 0, type = tf->tf_trap, code = 0;
99 	u_int	rv, addr;
100 	bool trapsig = true;
101 	const bool usermode = USERMODE_P(tf);
102 	struct lwp * const l = curlwp;
103 	struct proc * const p = l->l_proc;
104 	struct pcb * const pcb = lwp_getpcb(l);
105 	u_quad_t oticks = 0;
106 	struct vmspace *vm;
107 	struct vm_map *map;
108 	vm_prot_t ftype;
109 	void *onfault = pcb->pcb_onfault;
110 
111 	KASSERT(p != NULL);
112 	curcpu()->ci_data.cpu_ntrap++;
113 	if (usermode) {
114 		type |= T_USER;
115 		oticks = p->p_sticks;
116 		l->l_md.md_utf = tf;
117 		LWP_CACHE_CREDS(l, p);
118 	}
119 
120 	type &= ~(T_WRITE|T_PTEFETCH);
121 
122 
123 #ifdef TRAPDEBUG
124 if(tf->tf_trap==7) goto fram;
125 if(faultdebug)printf("Trap: type %lx, code %lx, pc %lx, psl %lx\n",
126 		tf->tf_trap, tf->tf_code, tf->tf_pc, tf->tf_psl);
127 fram:
128 #endif
129 	switch (type) {
130 
131 	default:
132 #ifdef DDB
133 		kdb_trap(tf);
134 #endif
135 		panic("trap: type %x, code %x, pc %x, psl %x",
136 		    (u_int)tf->tf_trap, (u_int)tf->tf_code,
137 		    (u_int)tf->tf_pc, (u_int)tf->tf_psl);
138 
139 	case T_KSPNOTVAL:
140 		panic("%d.%d (%s): KSP invalid %#x@%#x pcb %p fp %#x psl %#x)",
141 		    p->p_pid, l->l_lid, l->l_name ? l->l_name : "??",
142 		    mfpr(PR_KSP), (u_int)tf->tf_pc, pcb,
143 		    (u_int)tf->tf_fp, (u_int)tf->tf_psl);
144 
145 	case T_TRANSFLT|T_USER:
146 	case T_TRANSFLT:
147 		/*
148 		 * BUG! BUG! BUG! BUG! BUG!
149 		 * Due to a hardware bug (at in least KA65x CPUs) a double
150 		 * page table fetch trap will cause a translation fault
151 		 * even if access in the SPT PTE entry specifies 'no access'.
152 		 * In for example section 6.4.2 in VAX Architecture
153 		 * Reference Manual it states that if a page both are invalid
154 		 * and have no access set, a 'access violation fault' occurs.
155 		 * Therefore, we must fall through here...
156 		 */
157 #ifdef nohwbug
158 		panic("translation fault");
159 #endif
160 
161 	case T_PTELEN|T_USER:	/* Page table length exceeded */
162 	case T_ACCFLT|T_USER:
163 		if (tf->tf_code < 0) { /* Check for kernel space */
164 			sig = SIGSEGV;
165 			code = SEGV_ACCERR;
166 			break;
167 		}
168 
169 	case T_PTELEN:
170 #ifndef MULTIPROCESSOR
171 		/*
172 		 * If we referred to an address beyond the end of the system
173 		 * page table, it may be due to a failed CAS
174 		 * restartable-atomic-sequence.  If it is, restart it at the
175 		 * beginning and restart.
176 		 */
177 		{
178 			extern const uint8_t cas32_ras_start[], cas32_ras_end[];
179 			if (tf->tf_code == CASMAGIC
180 			    && tf->tf_pc >= (uintptr_t) cas32_ras_start
181 			    && tf->tf_pc < (uintptr_t) cas32_ras_end) {
182 				tf->tf_pc = (uintptr_t) cas32_ras_start;
183 				trapsig = false;
184 				break;
185 			}
186 		}
187 		/* FALLTHROUGH */
188 #endif
189 	case T_ACCFLT:
190 #ifdef TRAPDEBUG
191 if(faultdebug)printf("trap accflt type %lx, code %lx, pc %lx, psl %lx\n",
192 			tf->tf_trap, tf->tf_code, tf->tf_pc, tf->tf_psl);
193 #endif
194 #ifdef DIAGNOSTIC
195 		if (p == 0)
196 			panic("trap: access fault: addr %lx code %lx",
197 			    tf->tf_pc, tf->tf_code);
198 		if (tf->tf_psl & PSL_IS)
199 			panic("trap: pflt on IS");
200 #endif
201 
202 		/*
203 		 * Page tables are allocated in pmap_enter(). We get
204 		 * info from below if it is a page table fault, but
205 		 * UVM may want to map in pages without faults, so
206 		 * because we must check for PTE pages anyway we don't
207 		 * bother doing it here.
208 		 */
209 		addr = trunc_page(tf->tf_code);
210 		if (!usermode && (tf->tf_code < 0)) {
211 			vm = NULL;
212 			map = kernel_map;
213 
214 		} else {
215 			vm = p->p_vmspace;
216 			map = &vm->vm_map;
217 		}
218 
219 		if (tf->tf_trap & T_WRITE)
220 			ftype = VM_PROT_WRITE;
221 		else
222 			ftype = VM_PROT_READ;
223 
224 		if ((usermode) && (l->l_flag & LW_SA)) {
225 			l->l_savp->savp_faultaddr = (vaddr_t)tf->tf_code;
226 			l->l_pflag |= LP_SA_PAGEFAULT;
227 		}
228 
229 		pcb->pcb_onfault = NULL;
230 		rv = uvm_fault(map, addr, ftype);
231 		pcb->pcb_onfault = onfault;
232 		if (rv != 0) {
233 			if (!usermode) {
234 				if (onfault) {
235 					pcb->pcb_onfault = NULL;
236 					tf->tf_pc = (unsigned)onfault;
237 					tf->tf_psl &= ~PSL_FPD;
238 					tf->tf_r0 = rv;
239 					return;
240 				}
241 				panic("Segv in kernel mode: pc %#lx addr %#lx",
242 				    tf->tf_pc, tf->tf_code);
243 			}
244 			code = SEGV_ACCERR;
245 			if (rv == ENOMEM) {
246 				printf("UVM: pid %d (%s), uid %d killed: "
247 				       "out of swap\n",
248 				       p->p_pid, p->p_comm,
249 				       l->l_cred ?
250 				       kauth_cred_geteuid(l->l_cred) : -1);
251 				sig = SIGKILL;
252 			} else {
253 				sig = SIGSEGV;
254 				if (rv != EACCES)
255 					code = SEGV_MAPERR;
256 			}
257 		} else {
258 			trapsig = false;
259 			if (map != kernel_map && addr > 0
260 			    && (void *)addr >= vm->vm_maxsaddr)
261 				uvm_grow(p, addr);
262 		}
263 		if (usermode) {
264 			l->l_pflag &= ~LP_SA_PAGEFAULT;
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) && cpu_printfataltraps)
331 			printf("pid %d.%d (%s): sig %d: type %lx, code %lx, pc %lx, psl %lx\n",
332 			       p->p_pid, l->l_lid, p->p_comm, sig, tf->tf_trap,
333 			       tf->tf_code, tf->tf_pc, tf->tf_psl);
334 		KSI_INIT_TRAP(&ksi);
335 		ksi.ksi_signo = sig;
336 		ksi.ksi_trap = tf->tf_trap;
337 		ksi.ksi_addr = (void *)tf->tf_code;
338 		ksi.ksi_code = code;
339 
340 		/*
341 		 * Arithmetic exceptions can be of two kinds:
342 		 * - traps (codes 1..7), where pc points to the
343 		 *   next instruction to execute.
344 		 * - faults (codes 8..10), where pc points to the
345 		 *   faulting instruction.
346 		 * In the latter case, we need to advance pc by ourselves
347 		 * to prevent a signal loop.
348 		 *
349 		 * XXX this is gross -- miod
350 		 */
351 		if (type == (T_ARITHFLT | T_USER) && (tf->tf_code & 8))
352 			tf->tf_pc = skip_opcode(tf->tf_pc);
353 
354 		trapsignal(l, &ksi);
355 	}
356 
357 	if (!usermode)
358 		return;
359 
360 	userret(l, tf, oticks);
361 }
362 
363 void
364 setregs(struct lwp *l, struct exec_package *pack, vaddr_t stack)
365 {
366 	struct trapframe * const tf = l->l_md.md_utf;
367 
368 	tf->tf_pc = pack->ep_entry + 2;
369 	tf->tf_sp = stack;
370 	tf->tf_r6 = stack;				/* for ELF */
371 	tf->tf_r7 = 0;				/* for ELF */
372 	tf->tf_r8 = 0;				/* for ELF */
373 	tf->tf_r9 = l->l_proc->p_psstrp;		/* for ELF */
374 }
375 
376 
377 /*
378  * Start a new LWP
379  */
380 void
381 startlwp(void *arg)
382 {
383 	ucontext_t * const uc = arg;
384 	lwp_t * const l = curlwp;
385 	int error;
386 
387 	error = cpu_setmcontext(l, &uc->uc_mcontext, uc->uc_flags);
388 	KASSERT(error == 0);
389 
390 	kmem_free(uc, sizeof(ucontext_t));
391 	/* XXX - profiling spoiled here */
392 	userret(l, l->l_md.md_utf, l->l_proc->p_sticks);
393 }
394 
395 void
396 upcallret(struct lwp *l)
397 {
398 
399 	/* XXX - profiling */
400 	userret(l, l->l_md.md_utf, l->l_proc->p_sticks);
401 }
402 
403