xref: /netbsd-src/sys/arch/vax/vax/trap.c (revision eb961d0e02b7a46a9acfa877b02df48df6637278)
1 /*	$NetBSD: trap.c,v 1.99 2006/03/07 03:32:06 thorpej 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.99 2006/03/07 03:32:06 thorpej 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 
54 #include <uvm/uvm_extern.h>
55 
56 #include <machine/mtpr.h>
57 #include <machine/pte.h>
58 #include <machine/pcb.h>
59 #include <machine/trap.h>
60 #include <machine/pmap.h>
61 #include <machine/cpu.h>
62 
63 #ifdef DDB
64 #include <machine/db_machdep.h>
65 #endif
66 #include <kern/syscalls.c>
67 #ifdef KTRACE
68 #include <sys/ktrace.h>
69 #endif
70 
71 #ifdef TRAPDEBUG
72 volatile int startsysc = 0, faultdebug = 0;
73 #endif
74 
75 int	cpu_printfataltraps = 0;
76 
77 static inline void userret (struct lwp *, struct trapframe *, u_quad_t);
78 
79 void	trap (struct trapframe *);
80 void	syscall (struct trapframe *);
81 
82 const char * const traptypes[]={
83 	"reserved addressing",
84 	"privileged instruction",
85 	"reserved operand",
86 	"breakpoint instruction",
87 	"XFC instruction",
88 	"system call ",
89 	"arithmetic trap",
90 	"asynchronous system trap",
91 	"page table length fault",
92 	"translation violation fault",
93 	"trace trap",
94 	"compatibility mode fault",
95 	"access violation fault",
96 	"",
97 	"",
98 	"KSP invalid",
99 	"",
100 	"kernel debugger trap"
101 };
102 int no_traps = 18;
103 
104 #define USERMODE(framep)   ((((framep)->psl) & (PSL_U)) == PSL_U)
105 #define FAULTCHK						\
106 	if (l->l_addr->u_pcb.iftrap) {				\
107 		frame->pc = (unsigned)l->l_addr->u_pcb.iftrap;	\
108 		frame->psl &= ~PSL_FPD;				\
109 		frame->r0 = EFAULT;/* for copyin/out */		\
110 		frame->r1 = -1; /* for fetch/store */		\
111 		return;						\
112 	}
113 
114 /*
115  * userret:
116  *
117  *	Common code used by various execption handlers to
118  *	return to usermode.
119  */
120 static inline void
121 userret(struct lwp *l, struct trapframe *frame, u_quad_t oticks)
122 {
123 	int sig;
124 	struct proc *p = l->l_proc;
125 
126 	/* Generate UNBLOCKED upcall. */
127 	if (l->l_flag & L_SA_BLOCKING)
128 		sa_unblock_userret(l);
129 
130 	/* Take pending signals. */
131 	while ((sig = CURSIG(l)) != 0)
132 		postsig(sig);
133 	l->l_priority = l->l_usrpri;
134 	if (curcpu()->ci_want_resched) {
135 		/*
136 		 * We are being preempted.
137 		 */
138 		preempt(0);
139 		while ((sig = CURSIG(l)) != 0)
140 			postsig(sig);
141 	}
142 
143 	/* Invoke per-process kernel-exit handling, if any */
144 	if (p->p_userret)
145 		(p->p_userret)(l, p->p_userret_arg);
146 
147 	/*
148 	 * If profiling, charge system time to the trapped pc.
149 	 */
150 	if (p->p_flag & P_PROFIL) {
151 		extern int psratio;
152 
153 		addupc_task(p, frame->pc,
154 		    (int)(p->p_sticks - oticks) * psratio);
155 	}
156 	/* Invoke any pending upcalls. */
157 	if (l->l_flag & L_SA_UPCALL)
158 		sa_upcall_userret(l);
159 
160 	curcpu()->ci_schedstate.spc_curpriority = l->l_priority;
161 }
162 
163 void
164 trap(struct trapframe *frame)
165 {
166 	u_int	sig = 0, type = frame->trap, trapsig = 1, code = 0;
167 	u_int	rv, addr, umode;
168 	struct	lwp *l;
169 	struct	proc *p = NULL;
170 	u_quad_t oticks = 0;
171 	struct vmspace *vm;
172 	struct vm_map *map;
173 	vm_prot_t ftype;
174 
175 	if ((l = curlwp) != NULL)
176 		p = l->l_proc;
177 	uvmexp.traps++;
178 	if ((umode = USERMODE(frame))) {
179 		type |= T_USER;
180 		oticks = p->p_sticks;
181 		l->l_addr->u_pcb.framep = frame;
182 	}
183 
184 	type&=~(T_WRITE|T_PTEFETCH);
185 
186 
187 #ifdef TRAPDEBUG
188 if(frame->trap==7) goto fram;
189 if(faultdebug)printf("Trap: type %lx, code %lx, pc %lx, psl %lx\n",
190 		frame->trap, frame->code, frame->pc, frame->psl);
191 fram:
192 #endif
193 	switch(type){
194 
195 	default:
196 #ifdef DDB
197 		kdb_trap(frame);
198 #endif
199 		printf("Trap: type %x, code %x, pc %x, psl %x\n",
200 		    (u_int)frame->trap, (u_int)frame->code,
201 		    (u_int)frame->pc, (u_int)frame->psl);
202 		panic("trap");
203 
204 	case T_KSPNOTVAL:
205 		panic("kernel stack invalid");
206 
207 	case T_TRANSFLT|T_USER:
208 	case T_TRANSFLT:
209 		/*
210 		 * BUG! BUG! BUG! BUG! BUG!
211 		 * Due to a hardware bug (at in least KA65x CPUs) a double
212 		 * page table fetch trap will cause a translation fault
213 		 * even if access in the SPT PTE entry specifies 'no access'.
214 		 * In for example section 6.4.2 in VAX Architecture
215 		 * Reference Manual it states that if a page both are invalid
216 		 * and have no access set, a 'access violation fault' occurs.
217 		 * Therefore, we must fall through here...
218 		 */
219 #ifdef nohwbug
220 		panic("translation fault");
221 #endif
222 
223 	case T_PTELEN|T_USER:	/* Page table length exceeded */
224 	case T_ACCFLT|T_USER:
225 		if (frame->code < 0) { /* Check for kernel space */
226 			sig = SIGSEGV;
227 			code = SEGV_ACCERR;
228 			break;
229 		}
230 
231 	case T_PTELEN:
232 	case T_ACCFLT:
233 #ifdef TRAPDEBUG
234 if(faultdebug)printf("trap accflt type %lx, code %lx, pc %lx, psl %lx\n",
235 			frame->trap, frame->code, frame->pc, frame->psl);
236 #endif
237 #ifdef DIAGNOSTIC
238 		if (p == 0)
239 			panic("trap: access fault: addr %lx code %lx",
240 			    frame->pc, frame->code);
241 		if (frame->psl & PSL_IS)
242 			panic("trap: pflt on IS");
243 #endif
244 
245 		/*
246 		 * Page tables are allocated in pmap_enter(). We get
247 		 * info from below if it is a page table fault, but
248 		 * UVM may want to map in pages without faults, so
249 		 * because we must check for PTE pages anyway we don't
250 		 * bother doing it here.
251 		 */
252 		addr = trunc_page(frame->code);
253 		if ((umode == 0) && (frame->code < 0)) {
254 			vm = NULL;
255 			map = kernel_map;
256 		} else {
257 			vm = p->p_vmspace;
258 			map = &vm->vm_map;
259 		}
260 
261 		if (frame->trap & T_WRITE)
262 			ftype = VM_PROT_WRITE;
263 		else
264 			ftype = VM_PROT_READ;
265 
266 		if (umode) {
267 			KERNEL_PROC_LOCK(l);
268 			if (l->l_flag & L_SA) {
269 				l->l_savp->savp_faultaddr = (vaddr_t)frame->code;
270 				l->l_flag |= L_SA_PAGEFAULT;
271 			}
272 		} else
273 			KERNEL_LOCK(LK_CANRECURSE|LK_EXCLUSIVE);
274 
275 		rv = uvm_fault(map, addr, 0, ftype);
276 		if (rv != 0) {
277 			if (umode == 0) {
278 				KERNEL_UNLOCK();
279 				FAULTCHK;
280 				panic("Segv in kernel mode: pc %x addr %x",
281 				    (u_int)frame->pc, (u_int)frame->code);
282 			}
283 			code = SEGV_ACCERR;
284 			if (rv == ENOMEM) {
285 				printf("UVM: pid %d (%s), uid %d killed: "
286 				       "out of swap\n",
287 				       p->p_pid, p->p_comm,
288 				       p->p_cred && p->p_ucred ?
289 				       p->p_ucred->cr_uid : -1);
290 				sig = SIGKILL;
291 			} else {
292 				sig = SIGSEGV;
293 				if (rv != EACCES)
294 					code = SEGV_MAPERR;
295 			}
296 		} else {
297 			trapsig = 0;
298 			if (map != kernel_map && (caddr_t)addr >= vm->vm_maxsaddr)
299 				uvm_grow(p, addr);
300 		}
301 		if (umode) {
302 			l->l_flag &= ~L_SA_PAGEFAULT;
303 			KERNEL_PROC_UNLOCK(l);
304 		} else
305 			KERNEL_UNLOCK();
306 		break;
307 
308 	case T_BPTFLT|T_USER:
309 		sig = SIGTRAP;
310 		code = TRAP_BRKPT;
311 		break;
312 	case T_TRCTRAP|T_USER:
313 		sig = SIGTRAP;
314 		code = TRAP_TRACE;
315 		frame->psl &= ~PSL_T;
316 		break;
317 
318 	case T_PRIVINFLT|T_USER:
319 		sig = SIGILL;
320 		code = ILL_PRVOPC;
321 		break;
322 	case T_RESADFLT|T_USER:
323 		sig = SIGILL;
324 		code = ILL_ILLADR;
325 		break;
326 	case T_RESOPFLT|T_USER:
327 		sig = SIGILL;
328 		code = ILL_ILLOPC;
329 		break;
330 
331 	case T_XFCFLT|T_USER:
332 		sig = SIGEMT;
333 		break;
334 
335 	case T_ARITHFLT|T_USER:
336 		sig = SIGFPE;
337 		break;
338 
339 	case T_ASTFLT|T_USER:
340 		mtpr(AST_NO,PR_ASTLVL);
341 		trapsig = 0;
342 		break;
343 
344 #ifdef DDB
345 	case T_BPTFLT: /* Kernel breakpoint */
346 	case T_KDBTRAP:
347 	case T_KDBTRAP|T_USER:
348 	case T_TRCTRAP:
349 		kdb_trap(frame);
350 		return;
351 #endif
352 	}
353 	if (trapsig) {
354 		ksiginfo_t ksi;
355 		if ((sig == SIGSEGV || sig == SIGILL) && cpu_printfataltraps)
356 			printf("pid %d.%d (%s): sig %d: type %lx, code %lx, pc %lx, psl %lx\n",
357 			       p->p_pid, l->l_lid, p->p_comm, sig, frame->trap,
358 			       frame->code, frame->pc, frame->psl);
359 		KERNEL_PROC_LOCK(l);
360 		KSI_INIT_TRAP(&ksi);
361 		ksi.ksi_signo = sig;
362 		ksi.ksi_trap = frame->trap;
363 		ksi.ksi_addr = (void *)frame->code;
364 		ksi.ksi_code = code;
365 		trapsignal(l, &ksi);
366 		KERNEL_PROC_UNLOCK(l);
367 	}
368 
369 	if (umode == 0)
370 		return;
371 
372 	userret(l, frame, oticks);
373 }
374 
375 void
376 setregs(struct lwp *l, struct exec_package *pack, u_long stack)
377 {
378 	struct trapframe *exptr;
379 
380 	exptr = l->l_addr->u_pcb.framep;
381 	exptr->pc = pack->ep_entry + 2;
382 	exptr->sp = stack;
383 	exptr->r6 = stack;				/* for ELF */
384 	exptr->r7 = 0;					/* for ELF */
385 	exptr->r8 = 0;					/* for ELF */
386 	exptr->r9 = (u_long) l->l_proc->p_psstr;	/* for ELF */
387 }
388 
389 void
390 syscall(struct trapframe *frame)
391 {
392 	const struct sysent *callp;
393 	u_quad_t oticks;
394 	int nsys;
395 	int err, rval[2], args[8];
396 	struct trapframe *exptr;
397 	struct lwp *l = curlwp;
398 	struct proc *p = l->l_proc;
399 
400 #ifdef TRAPDEBUG
401 if(startsysc)printf("trap syscall %s pc %lx, psl %lx, sp %lx, pid %d, frame %p\n",
402 	       syscallnames[frame->code], frame->pc, frame->psl,frame->sp,
403 		p->p_pid,frame);
404 #endif
405 	uvmexp.syscalls++;
406 
407 	exptr = l->l_addr->u_pcb.framep = frame;
408 	callp = p->p_emul->e_sysent;
409 	nsys = p->p_emul->e_nsysent;
410 	oticks = p->p_sticks;
411 
412 	if (frame->code == SYS___syscall) {
413 		int g = *(int *)(frame->ap);
414 
415 		frame->code = *(int *)(frame->ap + 4);
416 		frame->ap += 8;
417 		*(int *)(frame->ap) = g - 2;
418 	}
419 
420 	if ((unsigned long) frame->code >= nsys)
421 		callp += p->p_emul->e_nosys;
422 	else
423 		callp += frame->code;
424 
425 	rval[0] = 0;
426 	rval[1] = frame->r1;
427 	KERNEL_PROC_LOCK(l);
428 	if (callp->sy_narg) {
429 		err = copyin((char*)frame->ap + 4, args, callp->sy_argsize);
430 		if (err) {
431 			KERNEL_PROC_UNLOCK(l);
432 			goto bad;
433 		}
434 	}
435 
436 	if ((err = trace_enter(l, frame->code, frame->code, NULL, args)) != 0)
437 		goto out;
438 
439 	err = (*callp->sy_call)(curlwp, args, rval);
440 out:
441 	KERNEL_PROC_UNLOCK(l);
442 	exptr = l->l_addr->u_pcb.framep;
443 
444 #ifdef TRAPDEBUG
445 if(startsysc)
446 	printf("retur %s pc %lx, psl %lx, sp %lx, pid %d, err %d r0 %d, r1 %d, frame %p\n",
447 	       syscallnames[exptr->code], exptr->pc, exptr->psl,exptr->sp,
448 		p->p_pid,err,rval[0],rval[1],exptr); /* } */
449 #endif
450 
451 bad:
452 	switch (err) {
453 	case 0:
454 		exptr->r1 = rval[1];
455 		exptr->r0 = rval[0];
456 		exptr->psl &= ~PSL_C;
457 		break;
458 
459 	case EJUSTRETURN:
460 		break;
461 
462 	case ERESTART:
463 		exptr->pc -= (exptr->code > 63 ? 4 : 2);
464 		break;
465 
466 	default:
467 		exptr->r0 = err;
468 		exptr->psl |= PSL_C;
469 		break;
470 	}
471 
472 	trace_exit(l, frame->code, args, rval, err);
473 
474 	userret(l, frame, oticks);
475 }
476 
477 void
478 child_return(void *arg)
479 {
480         struct lwp *l = arg;
481 
482 	KERNEL_PROC_UNLOCK(l);
483 	userret(l, l->l_addr->u_pcb.framep, 0);
484 
485 #ifdef KTRACE
486 	if (KTRPOINT(l->l_proc, KTR_SYSRET)) {
487 		KERNEL_PROC_LOCK(l);
488 		ktrsysret(l, SYS_fork, 0, 0);
489 		KERNEL_PROC_UNLOCK(l);
490 	}
491 #endif
492 }
493 
494 /*
495  * Start a new LWP
496  */
497 void
498 startlwp(arg)
499 	void *arg;
500 {
501 	int err;
502 	ucontext_t *uc = arg;
503 	struct lwp *l = curlwp;
504 
505 	err = cpu_setmcontext(l, &uc->uc_mcontext, uc->uc_flags);
506 #if DIAGNOSTIC
507 	if (err) {
508 		printf("Error %d from cpu_setmcontext.", err);
509 	}
510 #endif
511 	pool_put(&lwp_uc_pool, uc);
512 
513 	/* XXX - profiling spoiled here */
514 	userret(l, l->l_addr->u_pcb.framep, l->l_proc->p_sticks);
515 }
516 
517 void
518 upcallret(struct lwp *l)
519 {
520 
521 	/* XXX - profiling */
522 	userret(l, l->l_addr->u_pcb.framep, l->l_proc->p_sticks);
523 }
524 
525