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