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