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