xref: /netbsd-src/sys/arch/vax/vax/trap.c (revision 4b896b232495b7a9b8b94a1cf1e21873296d53b8)
1 /*	$NetBSD: trap.c,v 1.93 2004/03/14 01:08:49 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.93 2004/03/14 01:08:49 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 				l->l_savp->savp_faultaddr = (vaddr_t)frame->code;
275 				l->l_flag |= L_SA_PAGEFAULT;
276 			}
277 		} else
278 			KERNEL_LOCK(LK_CANRECURSE|LK_EXCLUSIVE);
279 
280 		nss = 0;
281 		if (map != kernel_map &&
282 		    (caddr_t)addr >= vm->vm_maxsaddr &&
283 		    (caddr_t)addr < (caddr_t)USRSTACK) {
284 			nss = btoc(USRSTACK - addr);
285 			if (nss > btoc(p->p_rlimit[RLIMIT_STACK].rlim_cur)) {
286 				/*
287 				 * Set nss to 0, since this case is not
288 				 * a "stack extension".
289 				 */
290 				nss = 0;
291 			}
292 		}
293 
294 		rv = uvm_fault(map, addr, 0, ftype);
295 		if (rv != 0) {
296 			if (umode == 0) {
297 				KERNEL_UNLOCK();
298 				FAULTCHK;
299 				panic("Segv in kernel mode: pc %x addr %x",
300 				    (u_int)frame->pc, (u_int)frame->code);
301 			}
302 			code = SEGV_ACCERR;
303 			if (rv == ENOMEM) {
304 				printf("UVM: pid %d (%s), uid %d killed: "
305 				       "out of swap\n",
306 				       p->p_pid, p->p_comm,
307 				       p->p_cred && p->p_ucred ?
308 				       p->p_ucred->cr_uid : -1);
309 				sig = SIGKILL;
310 			} else {
311 				sig = SIGSEGV;
312 				if (rv != EACCES)
313 					code = SEGV_MAPERR;
314 			}
315 		} else {
316 			trapsig = 0;
317 			if (nss != 0 && nss > vm->vm_ssize)
318 				vm->vm_ssize = nss;
319 		}
320 		if (umode) {
321 			l->l_flag &= ~L_SA_PAGEFAULT;
322 			KERNEL_PROC_UNLOCK(l);
323 		} else
324 			KERNEL_UNLOCK();
325 		break;
326 
327 	case T_BPTFLT|T_USER:
328 		sig = SIGTRAP;
329 		code = TRAP_BRKPT;
330 		break;
331 	case T_TRCTRAP|T_USER:
332 		sig = SIGTRAP;
333 		code = TRAP_TRACE;
334 		frame->psl &= ~PSL_T;
335 		break;
336 
337 	case T_PRIVINFLT|T_USER:
338 		sig = SIGILL;
339 		code = ILL_PRVOPC;
340 		break;
341 	case T_RESADFLT|T_USER:
342 		sig = SIGILL;
343 		code = ILL_ILLADR;
344 		break;
345 	case T_RESOPFLT|T_USER:
346 		sig = SIGILL;
347 		code = ILL_ILLOPC;
348 		break;
349 
350 	case T_XFCFLT|T_USER:
351 		sig = SIGEMT;
352 		break;
353 
354 	case T_ARITHFLT|T_USER:
355 		sig = SIGFPE;
356 		break;
357 
358 	case T_ASTFLT|T_USER:
359 		mtpr(AST_NO,PR_ASTLVL);
360 		trapsig = 0;
361 		break;
362 
363 #ifdef DDB
364 	case T_BPTFLT: /* Kernel breakpoint */
365 	case T_KDBTRAP:
366 	case T_KDBTRAP|T_USER:
367 	case T_TRCTRAP:
368 		kdb_trap(frame);
369 		return;
370 #endif
371 	}
372 	if (trapsig) {
373 		ksiginfo_t ksi;
374 		if ((sig == SIGSEGV || sig == SIGILL) && cpu_printfataltraps)
375 			printf("pid %d.%d (%s): sig %d: type %lx, code %lx, pc %lx, psl %lx\n",
376 			       p->p_pid, l->l_lid, p->p_comm, sig, frame->trap,
377 			       frame->code, frame->pc, frame->psl);
378 		KERNEL_PROC_LOCK(l);
379 		KSI_INIT_TRAP(&ksi);
380 		ksi.ksi_signo = sig;
381 		ksi.ksi_trap = frame->trap;
382 		ksi.ksi_addr = (void *)frame->code;
383 		ksi.ksi_code = code;
384 		trapsignal(l, &ksi);
385 		KERNEL_PROC_UNLOCK(l);
386 	}
387 
388 	if (umode == 0)
389 		return;
390 
391 	userret(l, frame, oticks);
392 }
393 
394 void
395 setregs(struct lwp *l, struct exec_package *pack, u_long stack)
396 {
397 	struct trapframe *exptr;
398 
399 	exptr = l->l_addr->u_pcb.framep;
400 	exptr->pc = pack->ep_entry + 2;
401 	exptr->sp = stack;
402 	exptr->r6 = stack;				/* for ELF */
403 	exptr->r7 = 0;					/* for ELF */
404 	exptr->r8 = 0;					/* for ELF */
405 	exptr->r9 = (u_long) l->l_proc->p_psstr;	/* for ELF */
406 }
407 
408 void
409 syscall(struct trapframe *frame)
410 {
411 	const struct sysent *callp;
412 	u_quad_t oticks;
413 	int nsys;
414 	int err, rval[2], args[8];
415 	struct trapframe *exptr;
416 	struct lwp *l = curlwp;
417 	struct proc *p = l->l_proc;
418 
419 #ifdef TRAPDEBUG
420 if(startsysc)printf("trap syscall %s pc %lx, psl %lx, sp %lx, pid %d, frame %p\n",
421 	       syscallnames[frame->code], frame->pc, frame->psl,frame->sp,
422 		p->p_pid,frame);
423 #endif
424 	uvmexp.syscalls++;
425 
426 	exptr = l->l_addr->u_pcb.framep = frame;
427 	callp = p->p_emul->e_sysent;
428 	nsys = p->p_emul->e_nsysent;
429 	oticks = p->p_sticks;
430 
431 	if (frame->code == SYS___syscall) {
432 		int g = *(int *)(frame->ap);
433 
434 		frame->code = *(int *)(frame->ap + 4);
435 		frame->ap += 8;
436 		*(int *)(frame->ap) = g - 2;
437 	}
438 
439 	if ((unsigned long) frame->code >= nsys)
440 		callp += p->p_emul->e_nosys;
441 	else
442 		callp += frame->code;
443 
444 	rval[0] = 0;
445 	rval[1] = frame->r1;
446 	KERNEL_PROC_LOCK(l);
447 	if (callp->sy_narg) {
448 		err = copyin((char*)frame->ap + 4, args, callp->sy_argsize);
449 		if (err) {
450 			KERNEL_PROC_UNLOCK(l);
451 			goto bad;
452 		}
453 	}
454 
455 	if ((err = trace_enter(l, frame->code, frame->code, NULL, args)) != 0) {
456 		KERNEL_PROC_UNLOCK(l);
457 		goto bad;
458 	}
459 
460 	err = (*callp->sy_call)(curlwp, args, rval);
461 	KERNEL_PROC_UNLOCK(l);
462 	exptr = l->l_addr->u_pcb.framep;
463 
464 #ifdef TRAPDEBUG
465 if(startsysc)
466 	printf("retur %s pc %lx, psl %lx, sp %lx, pid %d, err %d r0 %d, r1 %d, frame %p\n",
467 	       syscallnames[exptr->code], exptr->pc, exptr->psl,exptr->sp,
468 		p->p_pid,err,rval[0],rval[1],exptr); /* } */
469 #endif
470 
471 bad:
472 	switch (err) {
473 	case 0:
474 		exptr->r1 = rval[1];
475 		exptr->r0 = rval[0];
476 		exptr->psl &= ~PSL_C;
477 		break;
478 
479 	case EJUSTRETURN:
480 		break;
481 
482 	case ERESTART:
483 		exptr->pc -= (exptr->code > 63 ? 4 : 2);
484 		break;
485 
486 	default:
487 		exptr->r0 = err;
488 		exptr->psl |= PSL_C;
489 		break;
490 	}
491 
492 	trace_exit(l, frame->code, args, rval, err);
493 
494 	userret(l, frame, oticks);
495 }
496 
497 void
498 child_return(void *arg)
499 {
500         struct lwp *l = arg;
501 
502 	KERNEL_PROC_UNLOCK(l);
503 	userret(l, l->l_addr->u_pcb.framep, 0);
504 
505 #ifdef KTRACE
506 	if (KTRPOINT(l->l_proc, KTR_SYSRET)) {
507 		KERNEL_PROC_LOCK(l);
508 		ktrsysret(l->l_proc, SYS_fork, 0, 0);
509 		KERNEL_PROC_UNLOCK(l);
510 	}
511 #endif
512 }
513 
514 /*
515  * Start a new LWP
516  */
517 void
518 startlwp(arg)
519 	void *arg;
520 {
521 	int err;
522 	ucontext_t *uc = arg;
523 	struct lwp *l = curlwp;
524 
525 	err = cpu_setmcontext(l, &uc->uc_mcontext, uc->uc_flags);
526 #if DIAGNOSTIC
527 	if (err) {
528 		printf("Error %d from cpu_setmcontext.", err);
529 	}
530 #endif
531 	pool_put(&lwp_uc_pool, uc);
532 
533 	/* XXX - profiling spoiled here */
534 	userret(l, l->l_addr->u_pcb.framep, l->l_proc->p_sticks);
535 }
536 
537 void
538 upcallret(struct lwp *l)
539 {
540 
541 	/* XXX - profiling */
542 	userret(l, l->l_addr->u_pcb.framep, l->l_proc->p_sticks);
543 }
544 
545