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