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