xref: /netbsd-src/sys/arch/vax/vax/trap.c (revision b8c616269f5ebf18ab2e35cb8099d683130a177c)
1 /*	$NetBSD: trap.c,v 1.77 2003/01/20 04:45:57 matt 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 static __inline void userret (struct lwp *, struct trapframe *, u_quad_t);
77 
78 void	trap (struct trapframe *);
79 void	syscall (struct trapframe *);
80 
81 char *traptypes[]={
82 	"reserved addressing",
83 	"privileged instruction",
84 	"reserved operand",
85 	"breakpoint instruction",
86 	"XFC instruction",
87 	"system call ",
88 	"arithmetic trap",
89 	"asynchronous system trap",
90 	"page table length fault",
91 	"translation violation fault",
92 	"trace trap",
93 	"compatibility mode fault",
94 	"access violation fault",
95 	"",
96 	"",
97 	"KSP invalid",
98 	"",
99 	"kernel debugger trap"
100 };
101 int no_traps = 18;
102 
103 #define USERMODE(framep)   ((((framep)->psl) & (PSL_U)) == PSL_U)
104 #define FAULTCHK						\
105 	if (l->l_addr->u_pcb.iftrap) {				\
106 		frame->pc = (unsigned)l->l_addr->u_pcb.iftrap;	\
107 		frame->psl &= ~PSL_FPD;				\
108 		frame->r0 = EFAULT;/* for copyin/out */		\
109 		frame->r1 = -1; /* for fetch/store */		\
110 		return;						\
111 	}
112 
113 /*
114  * userret:
115  *
116  *	Common code used by various execption handlers to
117  *	return to usermode.
118  */
119 static __inline void
120 userret(struct lwp *l, struct trapframe *frame, u_quad_t oticks)
121 {
122 	int sig;
123 	struct proc *p = l->l_proc;
124 
125 	/* Take pending signals. */
126 	while ((sig = CURSIG(l)) != 0)
127 		postsig(sig);
128 	l->l_priority = l->l_usrpri;
129 	if (curcpu()->ci_want_resched) {
130 		/*
131 		 * We are being preempted.
132 		 */
133 		preempt(0);
134 		while ((sig = CURSIG(l)) != 0)
135 			postsig(sig);
136 	}
137 
138 	/* Invoke per-process kernel-exit handling, if any */
139 	if (p->p_userret)
140 		(p->p_userret)(l, p->p_userret_arg);
141 
142 	/*
143 	 * If profiling, charge system time to the trapped pc.
144 	 */
145 	if (p->p_flag & P_PROFIL) {
146 		extern int psratio;
147 
148 		addupc_task(p, frame->pc,
149 		    (int)(p->p_sticks - oticks) * psratio);
150 	}
151 	/* Invoke any pending upcalls. */
152 	while (l->l_flag & L_SA_UPCALL)
153 		sa_upcall_userret(l);
154 
155 	curcpu()->ci_schedstate.spc_curpriority = l->l_priority;
156 }
157 
158 void
159 trap(struct trapframe *frame)
160 {
161 	u_int	sig = 0, type = frame->trap, trapsig = 1;
162 	u_int	rv, addr, umode;
163 	struct	lwp *l = curlwp;
164 	struct	proc *p = l->l_proc;
165 	u_quad_t oticks = 0;
166 	struct vmspace *vm;
167 	struct vm_map *map;
168 	vm_prot_t ftype;
169 	vsize_t nss;
170 
171 	uvmexp.traps++;
172 	if ((umode = USERMODE(frame))) {
173 		type |= T_USER;
174 		oticks = p->p_sticks;
175 		l->l_addr->u_pcb.framep = frame;
176 	}
177 
178 	type&=~(T_WRITE|T_PTEFETCH);
179 
180 
181 #ifdef TRAPDEBUG
182 if(frame->trap==7) goto fram;
183 if(faultdebug)printf("Trap: type %lx, code %lx, pc %lx, psl %lx\n",
184 		frame->trap, frame->code, frame->pc, frame->psl);
185 fram:
186 #endif
187 	switch(type){
188 
189 	default:
190 #ifdef DDB
191 		kdb_trap(frame);
192 #endif
193 		printf("Trap: type %x, code %x, pc %x, psl %x\n",
194 		    (u_int)frame->trap, (u_int)frame->code,
195 		    (u_int)frame->pc, (u_int)frame->psl);
196 		panic("trap");
197 
198 	case T_KSPNOTVAL:
199 		panic("kernel stack invalid");
200 
201 	case T_TRANSFLT|T_USER:
202 	case T_TRANSFLT:
203 		/*
204 		 * BUG! BUG! BUG! BUG! BUG!
205 		 * Due to a hardware bug (at in least KA65x CPUs) a double
206 		 * page table fetch trap will cause a translation fault
207 		 * even if access in the SPT PTE entry specifies 'no access'.
208 		 * In for example section 6.4.2 in VAX Architecture
209 		 * Reference Manual it states that if a page both are invalid
210 		 * and have no access set, a 'access violation fault' occurs.
211 		 * Therefore, we must fall through here...
212 		 */
213 #ifdef nohwbug
214 		panic("translation fault");
215 #endif
216 
217 	case T_PTELEN|T_USER:	/* Page table length exceeded */
218 	case T_ACCFLT|T_USER:
219 		if (frame->code < 0) { /* Check for kernel space */
220 			sig = SIGSEGV;
221 			break;
222 		}
223 
224 	case T_PTELEN:
225 	case T_ACCFLT:
226 #ifdef TRAPDEBUG
227 if(faultdebug)printf("trap accflt type %lx, code %lx, pc %lx, psl %lx\n",
228 			frame->trap, frame->code, frame->pc, frame->psl);
229 #endif
230 #ifdef DIAGNOSTIC
231 		if (p == 0)
232 			panic("trap: access fault: addr %lx code %lx",
233 			    frame->pc, frame->code);
234 		if (frame->psl & PSL_IS)
235 			panic("trap: pflt on IS");
236 #endif
237 
238 		/*
239 		 * Page tables are allocated in pmap_enter(). We get
240 		 * info from below if it is a page table fault, but
241 		 * UVM may want to map in pages without faults, so
242 		 * because we must check for PTE pages anyway we don't
243 		 * bother doing it here.
244 		 */
245 		addr = trunc_page(frame->code);
246 		if ((umode == 0) && (frame->code < 0)) {
247 			vm = NULL;
248 			map = kernel_map;
249 		} else {
250 			vm = p->p_vmspace;
251 			map = &vm->vm_map;
252 		}
253 
254 		if (frame->trap & T_WRITE)
255 			ftype = VM_PROT_WRITE;
256 		else
257 			ftype = VM_PROT_READ;
258 
259 		if (umode)
260 			KERNEL_PROC_LOCK(l);
261 		else
262 			KERNEL_LOCK(LK_CANRECURSE|LK_EXCLUSIVE);
263 
264 		nss = 0;
265 		if (map != kernel_map &&
266 		    (caddr_t)addr >= vm->vm_maxsaddr &&
267 		    (caddr_t)addr < (caddr_t)USRSTACK) {
268 			nss = btoc(USRSTACK - addr);
269 			if (nss > btoc(p->p_rlimit[RLIMIT_STACK].rlim_cur)) {
270 				/*
271 				 * Set nss to 0, since this case is not
272 				 * a "stack extension".
273 				 */
274 				nss = 0;
275 			}
276 		}
277 
278 		rv = uvm_fault(map, addr, 0, ftype);
279 		if (rv != 0) {
280 			if (umode == 0) {
281 				KERNEL_UNLOCK();
282 				FAULTCHK;
283 				panic("Segv in kernel mode: pc %x addr %x",
284 				    (u_int)frame->pc, (u_int)frame->code);
285 			}
286 			if (rv == ENOMEM) {
287 				printf("UVM: pid %d (%s), uid %d killed: "
288 				       "out of swap\n",
289 				       p->p_pid, p->p_comm,
290 				       p->p_cred && p->p_ucred ?
291 				       p->p_ucred->cr_uid : -1);
292 				sig = SIGKILL;
293 			} else {
294 				sig = SIGSEGV;
295 			}
296 		} else {
297 			trapsig = 0;
298 			if (nss != 0 && nss > vm->vm_ssize)
299 				vm->vm_ssize = nss;
300 		}
301 		if (umode)
302 			KERNEL_PROC_UNLOCK(l);
303 		else
304 			KERNEL_UNLOCK();
305 		break;
306 
307 	case T_BPTFLT|T_USER:
308 	case T_TRCTRAP|T_USER:
309 		sig = SIGTRAP;
310 		frame->psl &= ~PSL_T;
311 		break;
312 
313 	case T_PRIVINFLT|T_USER:
314 	case T_RESADFLT|T_USER:
315 	case T_RESOPFLT|T_USER:
316 		sig = SIGILL;
317 		break;
318 
319 	case T_XFCFLT|T_USER:
320 		sig = SIGEMT;
321 		break;
322 
323 	case T_ARITHFLT|T_USER:
324 		sig = SIGFPE;
325 		break;
326 
327 	case T_ASTFLT|T_USER:
328 		mtpr(AST_NO,PR_ASTLVL);
329 		trapsig = 0;
330 		break;
331 
332 #ifdef DDB
333 	case T_BPTFLT: /* Kernel breakpoint */
334 	case T_KDBTRAP:
335 	case T_KDBTRAP|T_USER:
336 	case T_TRCTRAP:
337 		kdb_trap(frame);
338 		return;
339 #endif
340 	}
341 	if (trapsig) {
342 #ifdef DEBUG
343 		if (sig == SIGSEGV || sig == SIGILL)
344 			printf("pid %d (%s): sig %d: type %lx, code %lx, pc %lx, psl %lx\n",
345 			       p->p_pid, p->p_comm, sig, frame->trap,
346 			       frame->code, frame->pc, frame->psl);
347 #endif
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