xref: /netbsd-src/sys/arch/vax/vax/trap.c (revision 326b2259b73e878289ebd80cd9d20bc5aee35e99)
1 /*	$NetBSD: trap.c,v 1.81 2003/07/15 02:15:06 lukem 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.81 2003/07/15 02:15:06 lukem 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 	/* 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 	while (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;
167 	u_int	rv, addr, umode;
168 	struct	lwp *l = curlwp;
169 	struct	proc *p = l->l_proc;
170 	u_quad_t oticks = 0;
171 	struct vmspace *vm;
172 	struct vm_map *map;
173 	vm_prot_t ftype;
174 	vsize_t nss;
175 
176 	uvmexp.traps++;
177 	if ((umode = USERMODE(frame))) {
178 		type |= T_USER;
179 		oticks = p->p_sticks;
180 		l->l_addr->u_pcb.framep = frame;
181 	}
182 
183 	type&=~(T_WRITE|T_PTEFETCH);
184 
185 
186 #ifdef TRAPDEBUG
187 if(frame->trap==7) goto fram;
188 if(faultdebug)printf("Trap: type %lx, code %lx, pc %lx, psl %lx\n",
189 		frame->trap, frame->code, frame->pc, frame->psl);
190 fram:
191 #endif
192 	switch(type){
193 
194 	default:
195 #ifdef DDB
196 		kdb_trap(frame);
197 #endif
198 		printf("Trap: type %x, code %x, pc %x, psl %x\n",
199 		    (u_int)frame->trap, (u_int)frame->code,
200 		    (u_int)frame->pc, (u_int)frame->psl);
201 		panic("trap");
202 
203 	case T_KSPNOTVAL:
204 		panic("kernel stack invalid");
205 
206 	case T_TRANSFLT|T_USER:
207 	case T_TRANSFLT:
208 		/*
209 		 * BUG! BUG! BUG! BUG! BUG!
210 		 * Due to a hardware bug (at in least KA65x CPUs) a double
211 		 * page table fetch trap will cause a translation fault
212 		 * even if access in the SPT PTE entry specifies 'no access'.
213 		 * In for example section 6.4.2 in VAX Architecture
214 		 * Reference Manual it states that if a page both are invalid
215 		 * and have no access set, a 'access violation fault' occurs.
216 		 * Therefore, we must fall through here...
217 		 */
218 #ifdef nohwbug
219 		panic("translation fault");
220 #endif
221 
222 	case T_PTELEN|T_USER:	/* Page table length exceeded */
223 	case T_ACCFLT|T_USER:
224 		if (frame->code < 0) { /* Check for kernel space */
225 			sig = SIGSEGV;
226 			break;
227 		}
228 
229 	case T_PTELEN:
230 	case T_ACCFLT:
231 #ifdef TRAPDEBUG
232 if(faultdebug)printf("trap accflt type %lx, code %lx, pc %lx, psl %lx\n",
233 			frame->trap, frame->code, frame->pc, frame->psl);
234 #endif
235 #ifdef DIAGNOSTIC
236 		if (p == 0)
237 			panic("trap: access fault: addr %lx code %lx",
238 			    frame->pc, frame->code);
239 		if (frame->psl & PSL_IS)
240 			panic("trap: pflt on IS");
241 #endif
242 
243 		/*
244 		 * Page tables are allocated in pmap_enter(). We get
245 		 * info from below if it is a page table fault, but
246 		 * UVM may want to map in pages without faults, so
247 		 * because we must check for PTE pages anyway we don't
248 		 * bother doing it here.
249 		 */
250 		addr = trunc_page(frame->code);
251 		if ((umode == 0) && (frame->code < 0)) {
252 			vm = NULL;
253 			map = kernel_map;
254 		} else {
255 			vm = p->p_vmspace;
256 			map = &vm->vm_map;
257 		}
258 
259 		if (frame->trap & T_WRITE)
260 			ftype = VM_PROT_WRITE;
261 		else
262 			ftype = VM_PROT_READ;
263 
264 		if (umode)
265 			KERNEL_PROC_LOCK(l);
266 		else
267 			KERNEL_LOCK(LK_CANRECURSE|LK_EXCLUSIVE);
268 
269 		nss = 0;
270 		if (map != kernel_map &&
271 		    (caddr_t)addr >= vm->vm_maxsaddr &&
272 		    (caddr_t)addr < (caddr_t)USRSTACK) {
273 			nss = btoc(USRSTACK - addr);
274 			if (nss > btoc(p->p_rlimit[RLIMIT_STACK].rlim_cur)) {
275 				/*
276 				 * Set nss to 0, since this case is not
277 				 * a "stack extension".
278 				 */
279 				nss = 0;
280 			}
281 		}
282 
283 		rv = uvm_fault(map, addr, 0, ftype);
284 		if (rv != 0) {
285 			if (umode == 0) {
286 				KERNEL_UNLOCK();
287 				FAULTCHK;
288 				panic("Segv in kernel mode: pc %x addr %x",
289 				    (u_int)frame->pc, (u_int)frame->code);
290 			}
291 			if (rv == ENOMEM) {
292 				printf("UVM: pid %d (%s), uid %d killed: "
293 				       "out of swap\n",
294 				       p->p_pid, p->p_comm,
295 				       p->p_cred && p->p_ucred ?
296 				       p->p_ucred->cr_uid : -1);
297 				sig = SIGKILL;
298 			} else {
299 				sig = SIGSEGV;
300 			}
301 		} else {
302 			trapsig = 0;
303 			if (nss != 0 && nss > vm->vm_ssize)
304 				vm->vm_ssize = nss;
305 		}
306 		if (umode)
307 			KERNEL_PROC_UNLOCK(l);
308 		else
309 			KERNEL_UNLOCK();
310 		break;
311 
312 	case T_BPTFLT|T_USER:
313 	case T_TRCTRAP|T_USER:
314 		sig = SIGTRAP;
315 		frame->psl &= ~PSL_T;
316 		break;
317 
318 	case T_PRIVINFLT|T_USER:
319 	case T_RESADFLT|T_USER:
320 	case T_RESOPFLT|T_USER:
321 		sig = SIGILL;
322 		break;
323 
324 	case T_XFCFLT|T_USER:
325 		sig = SIGEMT;
326 		break;
327 
328 	case T_ARITHFLT|T_USER:
329 		sig = SIGFPE;
330 		break;
331 
332 	case T_ASTFLT|T_USER:
333 		mtpr(AST_NO,PR_ASTLVL);
334 		trapsig = 0;
335 		break;
336 
337 #ifdef DDB
338 	case T_BPTFLT: /* Kernel breakpoint */
339 	case T_KDBTRAP:
340 	case T_KDBTRAP|T_USER:
341 	case T_TRCTRAP:
342 		kdb_trap(frame);
343 		return;
344 #endif
345 	}
346 	if (trapsig) {
347 		if ((sig == SIGSEGV || sig == SIGILL) && cpu_printfataltraps)
348 			printf("pid %d.%d (%s): sig %d: type %lx, code %lx, pc %lx, psl %lx\n",
349 			       p->p_pid, l->l_lid, p->p_comm, sig, frame->trap,
350 			       frame->code, frame->pc, frame->psl);
351 		KERNEL_PROC_LOCK(l);
352 		trapsignal(l, sig, frame->code);
353 		KERNEL_PROC_UNLOCK(l);
354 	}
355 
356 	if (umode == 0)
357 		return;
358 
359 	userret(l, frame, oticks);
360 }
361 
362 void
363 setregs(struct lwp *l, struct exec_package *pack, u_long stack)
364 {
365 	struct trapframe *exptr;
366 
367 	exptr = l->l_addr->u_pcb.framep;
368 	exptr->pc = pack->ep_entry + 2;
369 	exptr->sp = stack;
370 	exptr->r6 = stack;				/* for ELF */
371 	exptr->r7 = 0;					/* for ELF */
372 	exptr->r8 = 0;					/* for ELF */
373 	exptr->r9 = (u_long) l->l_proc->p_psstr;	/* for ELF */
374 }
375 
376 void
377 syscall(struct trapframe *frame)
378 {
379 	const struct sysent *callp;
380 	u_quad_t oticks;
381 	int nsys;
382 	int err, rval[2], args[8];
383 	struct trapframe *exptr;
384 	struct lwp *l = curlwp;
385 	struct proc *p = l->l_proc;
386 
387 #ifdef TRAPDEBUG
388 if(startsysc)printf("trap syscall %s pc %lx, psl %lx, sp %lx, pid %d, frame %p\n",
389 	       syscallnames[frame->code], frame->pc, frame->psl,frame->sp,
390 		p->p_pid,frame);
391 #endif
392 	uvmexp.syscalls++;
393 
394 	exptr = l->l_addr->u_pcb.framep = frame;
395 	callp = p->p_emul->e_sysent;
396 	nsys = p->p_emul->e_nsysent;
397 	oticks = p->p_sticks;
398 
399 	if (frame->code == SYS___syscall) {
400 		int g = *(int *)(frame->ap);
401 
402 		frame->code = *(int *)(frame->ap + 4);
403 		frame->ap += 8;
404 		*(int *)(frame->ap) = g - 2;
405 	}
406 
407 	if ((unsigned long) frame->code >= nsys)
408 		callp += p->p_emul->e_nosys;
409 	else
410 		callp += frame->code;
411 
412 	rval[0] = 0;
413 	rval[1] = frame->r1;
414 	KERNEL_PROC_LOCK(l);
415 	if (callp->sy_narg) {
416 		err = copyin((char*)frame->ap + 4, args, callp->sy_argsize);
417 		if (err)
418 			goto bad;
419 	}
420 
421 	if ((err = trace_enter(l, frame->code, frame->code, NULL, args, rval)) != 0)
422 		goto bad;
423 
424 	err = (*callp->sy_call)(curlwp, args, rval);
425 	KERNEL_PROC_UNLOCK(l);
426 	exptr = l->l_addr->u_pcb.framep;
427 
428 #ifdef TRAPDEBUG
429 if(startsysc)
430 	printf("retur %s pc %lx, psl %lx, sp %lx, pid %d, err %d r0 %d, r1 %d, frame %p\n",
431 	       syscallnames[exptr->code], exptr->pc, exptr->psl,exptr->sp,
432 		p->p_pid,err,rval[0],rval[1],exptr); /* } */
433 #endif
434 
435 bad:
436 	switch (err) {
437 	case 0:
438 		exptr->r1 = rval[1];
439 		exptr->r0 = rval[0];
440 		exptr->psl &= ~PSL_C;
441 		break;
442 
443 	case EJUSTRETURN:
444 		break;
445 
446 	case ERESTART:
447 		exptr->pc -= (exptr->code > 63 ? 4 : 2);
448 		break;
449 
450 	default:
451 		exptr->r0 = err;
452 		exptr->psl |= PSL_C;
453 		break;
454 	}
455 
456 	trace_exit(l, frame->code, args, rval, err);
457 
458 	userret(l, frame, oticks);
459 }
460 
461 void
462 child_return(void *arg)
463 {
464         struct lwp *l = arg;
465 
466 	KERNEL_PROC_UNLOCK(l);
467 	userret(l, l->l_addr->u_pcb.framep, 0);
468 
469 #ifdef KTRACE
470 	if (KTRPOINT(l->l_proc, KTR_SYSRET)) {
471 		KERNEL_PROC_LOCK(l);
472 		ktrsysret(l->l_proc, SYS_fork, 0, 0);
473 		KERNEL_PROC_UNLOCK(l);
474 	}
475 #endif
476 }
477 
478 /*
479  * Start a new LWP
480  */
481 void
482 startlwp(arg)
483 	void *arg;
484 {
485 	int err;
486 	ucontext_t *uc = arg;
487 	struct lwp *l = curlwp;
488 
489 	err = cpu_setmcontext(l, &uc->uc_mcontext, uc->uc_flags);
490 #if DIAGNOSTIC
491 	if (err) {
492 		printf("Error %d from cpu_setmcontext.", err);
493 	}
494 #endif
495 	pool_put(&lwp_uc_pool, uc);
496 
497 	/* XXX - profiling spoiled here */
498 	userret(l, l->l_addr->u_pcb.framep, l->l_proc->p_sticks);
499 }
500 
501 void
502 upcallret(struct lwp *l)
503 {
504 
505 	/* XXX - profiling */
506 	userret(l, l->l_addr->u_pcb.framep, l->l_proc->p_sticks);
507 }
508 
509