xref: /netbsd-src/sys/arch/vax/vax/trap.c (revision 404fbe5fb94ca1e054339640cabb2801ce52dd30)
1 /*	$NetBSD: trap.c,v 1.116 2008/10/15 06:51:19 wrstuden 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.116 2008/10/15 06:51:19 wrstuden 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 <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						\
102 	if (l->l_addr->u_pcb.iftrap) {				\
103 		frame->pc = (unsigned)l->l_addr->u_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 	u_quad_t oticks = 0;
121 	struct vmspace *vm;
122 	struct vm_map *map;
123 	vm_prot_t ftype;
124 
125 	l = curlwp;
126 	KASSERT(l != NULL);
127 	p = l->l_proc;
128 	KASSERT(p != NULL);
129 	uvmexp.traps++;
130 	if (usermode) {
131 		type |= T_USER;
132 		oticks = p->p_sticks;
133 		l->l_addr->u_pcb.framep = frame;
134 		LWP_CACHE_CREDS(l, p);
135 	}
136 
137 	type &= ~(T_WRITE|T_PTEFETCH);
138 
139 
140 #ifdef TRAPDEBUG
141 if(frame->trap==7) goto fram;
142 if(faultdebug)printf("Trap: type %lx, code %lx, pc %lx, psl %lx\n",
143 		frame->trap, frame->code, frame->pc, frame->psl);
144 fram:
145 #endif
146 	switch (type) {
147 
148 	default:
149 #ifdef DDB
150 		kdb_trap(frame);
151 #endif
152 		panic("trap: type %x, code %x, pc %x, psl %x",
153 		    (u_int)frame->trap, (u_int)frame->code,
154 		    (u_int)frame->pc, (u_int)frame->psl);
155 
156 	case T_KSPNOTVAL:
157 		panic("%d.%d (%s): KSP invalid %#x@%#x pcb %p fp %#x psl %#x)",
158 		    p->p_pid, l->l_lid, l->l_name ? l->l_name : "??",
159 		    mfpr(PR_KSP), (u_int)frame->pc, l->l_addr,
160 		    (u_int)frame->fp, (u_int)frame->psl);
161 
162 	case T_TRANSFLT|T_USER:
163 	case T_TRANSFLT:
164 		/*
165 		 * BUG! BUG! BUG! BUG! BUG!
166 		 * Due to a hardware bug (at in least KA65x CPUs) a double
167 		 * page table fetch trap will cause a translation fault
168 		 * even if access in the SPT PTE entry specifies 'no access'.
169 		 * In for example section 6.4.2 in VAX Architecture
170 		 * Reference Manual it states that if a page both are invalid
171 		 * and have no access set, a 'access violation fault' occurs.
172 		 * Therefore, we must fall through here...
173 		 */
174 #ifdef nohwbug
175 		panic("translation fault");
176 #endif
177 
178 	case T_PTELEN|T_USER:	/* Page table length exceeded */
179 	case T_ACCFLT|T_USER:
180 		if (frame->code < 0) { /* Check for kernel space */
181 			sig = SIGSEGV;
182 			code = SEGV_ACCERR;
183 			break;
184 		}
185 
186 	case T_PTELEN:
187 	case T_ACCFLT:
188 #ifdef TRAPDEBUG
189 if(faultdebug)printf("trap accflt type %lx, code %lx, pc %lx, psl %lx\n",
190 			frame->trap, frame->code, frame->pc, frame->psl);
191 #endif
192 #ifdef DIAGNOSTIC
193 		if (p == 0)
194 			panic("trap: access fault: addr %lx code %lx",
195 			    frame->pc, frame->code);
196 		if (frame->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(frame->code);
208 		if (!usermode && (frame->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 (frame->trap & T_WRITE)
218 			ftype = VM_PROT_WRITE;
219 		else
220 			ftype = VM_PROT_READ;
221 
222 		if ((usermode) && (l->l_flag & LW_SA)) {
223 			l->l_savp->savp_faultaddr = (vaddr_t)frame->code;
224 			l->l_pflag |= LP_SA_PAGEFAULT;
225 		}
226 
227 		rv = uvm_fault(map, addr, ftype);
228 		if (rv != 0) {
229 			if (!usermode) {
230 				FAULTCHK;
231 				panic("Segv in kernel mode: pc %x addr %x",
232 				    (u_int)frame->pc, (u_int)frame->code);
233 			}
234 			code = SEGV_ACCERR;
235 			if (rv == ENOMEM) {
236 				printf("UVM: pid %d (%s), uid %d killed: "
237 				       "out of swap\n",
238 				       p->p_pid, p->p_comm,
239 				       l->l_cred ?
240 				       kauth_cred_geteuid(l->l_cred) : -1);
241 				sig = SIGKILL;
242 			} else {
243 				sig = SIGSEGV;
244 				if (rv != EACCES)
245 					code = SEGV_MAPERR;
246 			}
247 		} else {
248 			trapsig = false;
249 			if (map != kernel_map && addr > 0
250 			    && (void *)addr >= vm->vm_maxsaddr)
251 				uvm_grow(p, addr);
252 		}
253 		if (usermode) {
254 			l->l_pflag &= ~LP_SA_PAGEFAULT;
255 		}
256 		break;
257 
258 	case T_BPTFLT|T_USER:
259 		sig = SIGTRAP;
260 		code = TRAP_BRKPT;
261 		break;
262 	case T_TRCTRAP|T_USER:
263 		sig = SIGTRAP;
264 		code = TRAP_TRACE;
265 		frame->psl &= ~PSL_T;
266 		break;
267 
268 	case T_PRIVINFLT|T_USER:
269 		sig = SIGILL;
270 		code = ILL_PRVOPC;
271 		break;
272 	case T_RESADFLT|T_USER:
273 		sig = SIGILL;
274 		code = ILL_ILLADR;
275 		break;
276 	case T_RESOPFLT|T_USER:
277 		sig = SIGILL;
278 		code = ILL_ILLOPC;
279 		break;
280 
281 	case T_XFCFLT|T_USER:
282 		sig = SIGEMT;
283 		break;
284 
285 	case T_ARITHFLT|T_USER:
286 		sig = SIGFPE;
287 		switch (frame->code) {
288 		case AFLT_FLTDIV: code = FPE_FLTDIV; break;
289 		case AFLT_FLTUND: code = FPE_FLTUND; break;
290 		case AFLT_FLTOVF: code = FPE_FLTOVF; break;
291 		}
292 		break;
293 
294 	case T_ASTFLT|T_USER:
295 		mtpr(AST_NO,PR_ASTLVL);
296 		trapsig = false;
297 		break;
298 
299 #ifdef DDB
300 	case T_BPTFLT: /* Kernel breakpoint */
301 	case T_KDBTRAP:
302 	case T_KDBTRAP|T_USER:
303 	case T_TRCTRAP:
304 		kdb_trap(frame);
305 		return;
306 #endif
307 	}
308 	if (trapsig) {
309 		ksiginfo_t ksi;
310 		if ((sig == SIGSEGV || sig == SIGILL) && cpu_printfataltraps)
311 			printf("pid %d.%d (%s): sig %d: type %lx, code %lx, pc %lx, psl %lx\n",
312 			       p->p_pid, l->l_lid, p->p_comm, sig, frame->trap,
313 			       frame->code, frame->pc, frame->psl);
314 		KSI_INIT_TRAP(&ksi);
315 		ksi.ksi_signo = sig;
316 		ksi.ksi_trap = frame->trap;
317 		ksi.ksi_addr = (void *)frame->code;
318 		ksi.ksi_code = code;
319 		trapsignal(l, &ksi);
320 	}
321 
322 	if (!usermode)
323 		return;
324 
325 	userret(l, frame, oticks);
326 }
327 
328 void
329 setregs(struct lwp *l, struct exec_package *pack, u_long stack)
330 {
331 	struct trapframe *exptr;
332 
333 	exptr = l->l_addr->u_pcb.framep;
334 	exptr->pc = pack->ep_entry + 2;
335 	exptr->sp = stack;
336 	exptr->r6 = stack;				/* for ELF */
337 	exptr->r7 = 0;					/* for ELF */
338 	exptr->r8 = 0;					/* for ELF */
339 	exptr->r9 = (u_long) l->l_proc->p_psstr;	/* for ELF */
340 }
341 
342 
343 /*
344  * Start a new LWP
345  */
346 void
347 startlwp(void *arg)
348 {
349 	int err;
350 	ucontext_t *uc = arg;
351 	struct lwp *l = curlwp;
352 
353 	err = cpu_setmcontext(l, &uc->uc_mcontext, uc->uc_flags);
354 #if DIAGNOSTIC
355 	if (err) {
356 		printf("Error %d from cpu_setmcontext.", err);
357 	}
358 #endif
359 	pool_put(&lwp_uc_pool, uc);
360 
361 	/* XXX - profiling spoiled here */
362 	userret(l, l->l_addr->u_pcb.framep, l->l_proc->p_sticks);
363 }
364 
365 void
366 upcallret(struct lwp *l)
367 {
368 
369 	/* XXX - profiling */
370 	userret(l, l->l_addr->u_pcb.framep, l->l_proc->p_sticks);
371 }
372 
373