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