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