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