xref: /netbsd-src/sys/arch/vax/vax/trap.c (revision 3816d47b2c42fcd6e549e3407f842a5b1a1d23ad)
1 /*	$NetBSD: trap.c,v 1.122 2010/01/05 13:20:30 mbalmer 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.122 2010/01/05 13:20:30 mbalmer Exp $");
37 
38 #include "opt_ddb.h"
39 #include "opt_multiprocessor.h"
40 
41 #include <sys/types.h>
42 #include <sys/param.h>
43 #include <sys/proc.h>
44 #include <sys/syscall.h>
45 #include <sys/systm.h>
46 #include <sys/signalvar.h>
47 #include <sys/exec.h>
48 #include <sys/sa.h>
49 #include <sys/savar.h>
50 #include <sys/pool.h>
51 #include <sys/kauth.h>
52 
53 #include <uvm/uvm_extern.h>
54 
55 #include <machine/mtpr.h>
56 #include <machine/pte.h>
57 #include <machine/pcb.h>
58 #include <machine/trap.h>
59 #include <machine/pmap.h>
60 #include <machine/cpu.h>
61 #include <machine/userret.h>
62 
63 #ifdef DDB
64 #include <machine/db_machdep.h>
65 #endif
66 #include <vax/vax/db_disasm.h>
67 #include <kern/syscalls.c>
68 #include <sys/ktrace.h>
69 
70 #ifdef TRAPDEBUG
71 volatile int faultdebug = 0;
72 #endif
73 
74 int	cpu_printfataltraps = 0;
75 
76 void	trap (struct trapframe *);
77 
78 const char * const traptypes[]={
79 	"reserved addressing",
80 	"privileged instruction",
81 	"reserved operand",
82 	"breakpoint instruction",
83 	"XFC instruction",
84 	"system call ",
85 	"arithmetic trap",
86 	"asynchronous system trap",
87 	"page table length fault",
88 	"translation violation fault",
89 	"trace trap",
90 	"compatibility mode fault",
91 	"access violation fault",
92 	"",
93 	"",
94 	"KSP invalid",
95 	"",
96 	"kernel debugger trap"
97 };
98 int no_traps = 18;
99 
100 #define USERMODE_P(framep)   ((((framep)->psl) & (PSL_U)) == PSL_U)
101 #define FAULTCHK(pcb)						\
102 	if (pcb->iftrap) {					\
103 		frame->pc = (unsigned)pcb->iftrap;		\
104 		frame->psl &= ~PSL_FPD;				\
105 		frame->r0 = EFAULT;/* for copyin/out */		\
106 		frame->r1 = -1; /* for fetch/store */		\
107 		return;						\
108 	}
109 
110 
111 void
112 trap(struct trapframe *frame)
113 {
114 	u_int	sig = 0, type = frame->trap, code = 0;
115 	u_int	rv, addr;
116 	bool trapsig = true;
117 	const bool usermode = USERMODE_P(frame);
118 	struct	lwp *l;
119 	struct	proc *p;
120 	struct	pcb *pcb;
121 	u_quad_t oticks = 0;
122 	struct vmspace *vm;
123 	struct vm_map *map;
124 	vm_prot_t ftype;
125 
126 	l = curlwp;
127 	KASSERT(l != NULL);
128 	p = l->l_proc;
129 	KASSERT(p != NULL);
130 	pcb = lwp_getpcb(l);
131 	uvmexp.traps++;
132 	if (usermode) {
133 		type |= T_USER;
134 		oticks = p->p_sticks;
135 		pcb->framep = frame;
136 		LWP_CACHE_CREDS(l, p);
137 	}
138 
139 	type &= ~(T_WRITE|T_PTEFETCH);
140 
141 
142 #ifdef TRAPDEBUG
143 if(frame->trap==7) goto fram;
144 if(faultdebug)printf("Trap: type %lx, code %lx, pc %lx, psl %lx\n",
145 		frame->trap, frame->code, frame->pc, frame->psl);
146 fram:
147 #endif
148 	switch (type) {
149 
150 	default:
151 #ifdef DDB
152 		kdb_trap(frame);
153 #endif
154 		panic("trap: type %x, code %x, pc %x, psl %x",
155 		    (u_int)frame->trap, (u_int)frame->code,
156 		    (u_int)frame->pc, (u_int)frame->psl);
157 
158 	case T_KSPNOTVAL:
159 		panic("%d.%d (%s): KSP invalid %#x@%#x pcb %p fp %#x psl %#x)",
160 		    p->p_pid, l->l_lid, l->l_name ? l->l_name : "??",
161 		    mfpr(PR_KSP), (u_int)frame->pc, lwp_getpcb(l),
162 		    (u_int)frame->fp, (u_int)frame->psl);
163 
164 	case T_TRANSFLT|T_USER:
165 	case T_TRANSFLT:
166 		/*
167 		 * BUG! BUG! BUG! BUG! BUG!
168 		 * Due to a hardware bug (at in least KA65x CPUs) a double
169 		 * page table fetch trap will cause a translation fault
170 		 * even if access in the SPT PTE entry specifies 'no access'.
171 		 * In for example section 6.4.2 in VAX Architecture
172 		 * Reference Manual it states that if a page both are invalid
173 		 * and have no access set, a 'access violation fault' occurs.
174 		 * Therefore, we must fall through here...
175 		 */
176 #ifdef nohwbug
177 		panic("translation fault");
178 #endif
179 
180 	case T_PTELEN|T_USER:	/* Page table length exceeded */
181 	case T_ACCFLT|T_USER:
182 		if (frame->code < 0) { /* Check for kernel space */
183 			sig = SIGSEGV;
184 			code = SEGV_ACCERR;
185 			break;
186 		}
187 
188 	case T_PTELEN:
189 	case T_ACCFLT:
190 #ifdef TRAPDEBUG
191 if(faultdebug)printf("trap accflt type %lx, code %lx, pc %lx, psl %lx\n",
192 			frame->trap, frame->code, frame->pc, frame->psl);
193 #endif
194 #ifdef DIAGNOSTIC
195 		if (p == 0)
196 			panic("trap: access fault: addr %lx code %lx",
197 			    frame->pc, frame->code);
198 		if (frame->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(frame->code);
210 		if (!usermode && (frame->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 (frame->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)frame->code;
226 			l->l_pflag |= LP_SA_PAGEFAULT;
227 		}
228 
229 		rv = uvm_fault(map, addr, ftype);
230 		if (rv != 0) {
231 			if (!usermode) {
232 				FAULTCHK(pcb);
233 				panic("Segv in kernel mode: pc %x addr %x",
234 				    (u_int)frame->pc, (u_int)frame->code);
235 			}
236 			code = SEGV_ACCERR;
237 			if (rv == ENOMEM) {
238 				printf("UVM: pid %d (%s), uid %d killed: "
239 				       "out of swap\n",
240 				       p->p_pid, p->p_comm,
241 				       l->l_cred ?
242 				       kauth_cred_geteuid(l->l_cred) : -1);
243 				sig = SIGKILL;
244 			} else {
245 				sig = SIGSEGV;
246 				if (rv != EACCES)
247 					code = SEGV_MAPERR;
248 			}
249 		} else {
250 			trapsig = false;
251 			if (map != kernel_map && addr > 0
252 			    && (void *)addr >= vm->vm_maxsaddr)
253 				uvm_grow(p, addr);
254 		}
255 		if (usermode) {
256 			l->l_pflag &= ~LP_SA_PAGEFAULT;
257 		}
258 		break;
259 
260 	case T_BPTFLT|T_USER:
261 		sig = SIGTRAP;
262 		code = TRAP_BRKPT;
263 		break;
264 	case T_TRCTRAP|T_USER:
265 		sig = SIGTRAP;
266 		code = TRAP_TRACE;
267 		frame->psl &= ~PSL_T;
268 		break;
269 
270 	case T_PRIVINFLT|T_USER:
271 		sig = SIGILL;
272 		code = ILL_PRVOPC;
273 		break;
274 	case T_RESADFLT|T_USER:
275 		sig = SIGILL;
276 		code = ILL_ILLADR;
277 		break;
278 	case T_RESOPFLT|T_USER:
279 		sig = SIGILL;
280 		code = ILL_ILLOPC;
281 		break;
282 
283 	case T_XFCFLT|T_USER:
284 		sig = SIGEMT;
285 		break;
286 
287 	case T_ARITHFLT|T_USER:
288 		sig = SIGFPE;
289 		switch (frame->code) {
290 		case ATRP_INTOVF: code = FPE_INTOVF; break;
291 		case ATRP_INTDIV: code = FPE_INTDIV; break;
292 		case ATRP_FLTOVF: code = FPE_FLTOVF; break;
293 		case ATRP_FLTDIV: code = FPE_FLTDIV; break;
294 		case ATRP_FLTUND: code = FPE_FLTUND; break;
295 		case ATRP_DECOVF: code = FPE_INTOVF; break;
296 		case ATRP_FLTSUB: code = FPE_FLTSUB; break;
297 		case AFLT_FLTDIV: code = FPE_FLTDIV; break;
298 		case AFLT_FLTUND: code = FPE_FLTUND; break;
299 		case AFLT_FLTOVF: code = FPE_FLTOVF; break;
300 		default:	  code = FPE_FLTINV; break;
301 		}
302 		break;
303 
304 	case T_ASTFLT|T_USER:
305 		mtpr(AST_NO,PR_ASTLVL);
306 		trapsig = false;
307 		if (curcpu()->ci_want_resched)
308 			preempt();
309 		break;
310 
311 #ifdef DDB
312 	case T_BPTFLT: /* Kernel breakpoint */
313 	case T_KDBTRAP:
314 	case T_KDBTRAP|T_USER:
315 	case T_TRCTRAP:
316 		kdb_trap(frame);
317 		return;
318 #endif
319 	}
320 	if (trapsig) {
321 		ksiginfo_t ksi;
322 		if ((sig == SIGSEGV || sig == SIGILL) && cpu_printfataltraps)
323 			printf("pid %d.%d (%s): sig %d: type %lx, code %lx, pc %lx, psl %lx\n",
324 			       p->p_pid, l->l_lid, p->p_comm, sig, frame->trap,
325 			       frame->code, frame->pc, frame->psl);
326 		KSI_INIT_TRAP(&ksi);
327 		ksi.ksi_signo = sig;
328 		ksi.ksi_trap = frame->trap;
329 		ksi.ksi_addr = (void *)frame->code;
330 		ksi.ksi_code = code;
331 
332 		/*
333 		 * Arithmetic exceptions can be of two kinds:
334 		 * - traps (codes 1..7), where pc points to the
335 		 *   next instruction to execute.
336 		 * - faults (codes 8..10), where pc points to the
337 		 *   faulting instruction.
338 		 * In the latter case, we need to advance pc by ourselves
339 		 * to prevent a signal loop.
340 		 *
341 		 * XXX this is gross -- miod
342 		 */
343 		if (type == (T_ARITHFLT | T_USER) && (frame->code & 8))
344 			frame->pc = skip_opcode(frame->pc);
345 
346 		trapsignal(l, &ksi);
347 	}
348 
349 	if (!usermode)
350 		return;
351 
352 	userret(l, frame, oticks);
353 }
354 
355 void
356 setregs(struct lwp *l, struct exec_package *pack, vaddr_t stack)
357 {
358 	struct trapframe *exptr;
359 	struct pcb *pcb;
360 
361 	pcb = lwp_getpcb(l);
362 	exptr = pcb->framep;
363 	exptr->pc = pack->ep_entry + 2;
364 	exptr->sp = stack;
365 	exptr->r6 = stack;				/* for ELF */
366 	exptr->r7 = 0;					/* for ELF */
367 	exptr->r8 = 0;					/* for ELF */
368 	exptr->r9 = (u_long) l->l_proc->p_psstr;	/* for ELF */
369 }
370 
371 
372 /*
373  * Start a new LWP
374  */
375 void
376 startlwp(void *arg)
377 {
378 	int err;
379 	ucontext_t *uc = arg;
380 	struct lwp *l = curlwp;
381 	struct pcb *pcb;
382 
383 	err = cpu_setmcontext(l, &uc->uc_mcontext, uc->uc_flags);
384 #if DIAGNOSTIC
385 	if (err) {
386 		printf("Error %d from cpu_setmcontext.", err);
387 	}
388 #endif
389 	pool_put(&lwp_uc_pool, uc);
390 
391 	/* XXX - profiling spoiled here */
392 	pcb = lwp_getpcb(l);
393 	userret(l, pcb->framep, l->l_proc->p_sticks);
394 }
395 
396 void
397 upcallret(struct lwp *l)
398 {
399 	struct pcb *pcb;
400 
401 	/* XXX - profiling */
402 	pcb = lwp_getpcb(l);
403 	userret(l, pcb->framep, l->l_proc->p_sticks);
404 }
405 
406