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