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