xref: /netbsd-src/sys/arch/vax/vax/trap.c (revision 8ac07aec990b9d2e483062509d0a9fa5b4f57cf2)
1 /*	$NetBSD: trap.c,v 1.113 2008/03/11 05:34:03 matt 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.113 2008/03/11 05:34:03 matt 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_P(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, code = 0;
113 	u_int	rv, addr;
114 	bool trapsig = true;
115 	const bool usermode = USERMODE_P(frame);;
116 	struct	lwp *l;
117 	struct	proc *p;
118 	u_quad_t oticks = 0;
119 	struct vmspace *vm;
120 	struct vm_map *map;
121 	vm_prot_t ftype;
122 
123 	l = curlwp;
124 	KASSERT(l != NULL);
125 	p = l->l_proc;
126 	KASSERT(p != NULL);
127 	uvmexp.traps++;
128 	if (usermode) {
129 		type |= T_USER;
130 		oticks = p->p_sticks;
131 		l->l_addr->u_pcb.framep = frame;
132 		LWP_CACHE_CREDS(l, p);
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 		panic("trap: type %x, code %x, pc %x, psl %x",
151 		    (u_int)frame->trap, (u_int)frame->code,
152 		    (u_int)frame->pc, (u_int)frame->psl);
153 
154 	case T_KSPNOTVAL:
155 		panic("%d.%d (%s): KSP invalid %#x@%#x pcb %p fp %#x psl %#x)",
156 		    p->p_pid, l->l_lid, l->l_name ? l->l_name : "??",
157 		    mfpr(PR_KSP), (u_int)frame->pc, l->l_addr,
158 		    (u_int)frame->fp, (u_int)frame->psl);
159 
160 	case T_TRANSFLT|T_USER:
161 	case T_TRANSFLT:
162 		/*
163 		 * BUG! BUG! BUG! BUG! BUG!
164 		 * Due to a hardware bug (at in least KA65x CPUs) a double
165 		 * page table fetch trap will cause a translation fault
166 		 * even if access in the SPT PTE entry specifies 'no access'.
167 		 * In for example section 6.4.2 in VAX Architecture
168 		 * Reference Manual it states that if a page both are invalid
169 		 * and have no access set, a 'access violation fault' occurs.
170 		 * Therefore, we must fall through here...
171 		 */
172 #ifdef nohwbug
173 		panic("translation fault");
174 #endif
175 
176 	case T_PTELEN|T_USER:	/* Page table length exceeded */
177 	case T_ACCFLT|T_USER:
178 		if (frame->code < 0) { /* Check for kernel space */
179 			sig = SIGSEGV;
180 			code = SEGV_ACCERR;
181 			break;
182 		}
183 
184 	case T_PTELEN:
185 	case T_ACCFLT:
186 #ifdef TRAPDEBUG
187 if(faultdebug)printf("trap accflt type %lx, code %lx, pc %lx, psl %lx\n",
188 			frame->trap, frame->code, frame->pc, frame->psl);
189 #endif
190 #ifdef DIAGNOSTIC
191 		if (p == 0)
192 			panic("trap: access fault: addr %lx code %lx",
193 			    frame->pc, frame->code);
194 		if (frame->psl & PSL_IS)
195 			panic("trap: pflt on IS");
196 #endif
197 
198 		/*
199 		 * Page tables are allocated in pmap_enter(). We get
200 		 * info from below if it is a page table fault, but
201 		 * UVM may want to map in pages without faults, so
202 		 * because we must check for PTE pages anyway we don't
203 		 * bother doing it here.
204 		 */
205 		addr = trunc_page(frame->code);
206 		if (!usermode && (frame->code < 0)) {
207 			vm = NULL;
208 			map = kernel_map;
209 
210 		} else {
211 			vm = p->p_vmspace;
212 			map = &vm->vm_map;
213 		}
214 
215 		if (frame->trap & T_WRITE)
216 			ftype = VM_PROT_WRITE;
217 		else
218 			ftype = VM_PROT_READ;
219 
220 		if (usermode)
221 			KERNEL_LOCK(1, l);
222 		else
223 			KERNEL_LOCK(1, NULL);
224 
225 		rv = uvm_fault(map, addr, ftype);
226 		if (rv != 0) {
227 			if (!usermode) {
228 				KERNEL_UNLOCK_ONE(NULL);
229 				FAULTCHK;
230 				panic("Segv in kernel mode: pc %x addr %x",
231 				    (u_int)frame->pc, (u_int)frame->code);
232 			}
233 			code = SEGV_ACCERR;
234 			if (rv == ENOMEM) {
235 				printf("UVM: pid %d (%s), uid %d killed: "
236 				       "out of swap\n",
237 				       p->p_pid, p->p_comm,
238 				       l->l_cred ?
239 				       kauth_cred_geteuid(l->l_cred) : -1);
240 				sig = SIGKILL;
241 			} else {
242 				sig = SIGSEGV;
243 				if (rv != EACCES)
244 					code = SEGV_MAPERR;
245 			}
246 		} else {
247 			trapsig = false;
248 			if (map != kernel_map && addr > 0
249 			    && (void *)addr >= vm->vm_maxsaddr)
250 				uvm_grow(p, addr);
251 		}
252 		if (usermode)
253 			KERNEL_UNLOCK_LAST(l);
254 		else
255 			KERNEL_UNLOCK_ONE(NULL);
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 		break;
288 
289 	case T_ASTFLT|T_USER:
290 		mtpr(AST_NO,PR_ASTLVL);
291 		trapsig = false;
292 		break;
293 
294 #ifdef DDB
295 	case T_BPTFLT: /* Kernel breakpoint */
296 	case T_KDBTRAP:
297 	case T_KDBTRAP|T_USER:
298 	case T_TRCTRAP:
299 		kdb_trap(frame);
300 		return;
301 #endif
302 	}
303 	if (trapsig) {
304 		ksiginfo_t ksi;
305 		if ((sig == SIGSEGV || sig == SIGILL) && cpu_printfataltraps)
306 			printf("pid %d.%d (%s): sig %d: type %lx, code %lx, pc %lx, psl %lx\n",
307 			       p->p_pid, l->l_lid, p->p_comm, sig, frame->trap,
308 			       frame->code, frame->pc, frame->psl);
309 		KERNEL_LOCK(1, l);
310 		KSI_INIT_TRAP(&ksi);
311 		ksi.ksi_signo = sig;
312 		ksi.ksi_trap = frame->trap;
313 		ksi.ksi_addr = (void *)frame->code;
314 		ksi.ksi_code = code;
315 		trapsignal(l, &ksi);
316 		KERNEL_UNLOCK_LAST(l);
317 	}
318 
319 	if (!usermode)
320 		return;
321 
322 	userret(l, frame, oticks);
323 }
324 
325 void
326 setregs(struct lwp *l, struct exec_package *pack, u_long stack)
327 {
328 	struct trapframe *exptr;
329 
330 	exptr = l->l_addr->u_pcb.framep;
331 	exptr->pc = pack->ep_entry + 2;
332 	exptr->sp = stack;
333 	exptr->r6 = stack;				/* for ELF */
334 	exptr->r7 = 0;					/* for ELF */
335 	exptr->r8 = 0;					/* for ELF */
336 	exptr->r9 = (u_long) l->l_proc->p_psstr;	/* for ELF */
337 }
338 
339 
340 /*
341  * Start a new LWP
342  */
343 void
344 startlwp(void *arg)
345 {
346 	int err;
347 	ucontext_t *uc = arg;
348 	struct lwp *l = curlwp;
349 
350 	err = cpu_setmcontext(l, &uc->uc_mcontext, uc->uc_flags);
351 #if DIAGNOSTIC
352 	if (err) {
353 		printf("Error %d from cpu_setmcontext.", err);
354 	}
355 #endif
356 	pool_put(&lwp_uc_pool, uc);
357 
358 	/* XXX - profiling spoiled here */
359 	userret(l, l->l_addr->u_pcb.framep, l->l_proc->p_sticks);
360 }
361