xref: /netbsd/sys/arch/vax/vax/trap.c (revision bf9ec67e)
1 /*	$NetBSD: trap.c,v 1.70 2002/04/29 01:54:11 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_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 
198 	case T_PTELEN|T_USER:	/* Page table length exceeded */
199 	case T_ACCFLT|T_USER:
200 		if (frame->code < 0) { /* Check for kernel space */
201 			sig = SIGSEGV;
202 			break;
203 		}
204 
205 	case T_PTELEN:
206 	case T_ACCFLT:
207 #ifdef TRAPDEBUG
208 if(faultdebug)printf("trap accflt type %lx, code %lx, pc %lx, psl %lx\n",
209 			frame->trap, frame->code, frame->pc, frame->psl);
210 #endif
211 #ifdef DIAGNOSTIC
212 		if (p == 0)
213 			panic("trap: access fault: addr %lx code %lx",
214 			    frame->pc, frame->code);
215 		if (frame->psl & PSL_IS)
216 			panic("trap: pflt on IS");
217 #endif
218 
219 		/*
220 		 * Page tables are allocated in pmap_enter(). We get
221 		 * info from below if it is a page table fault, but
222 		 * UVM may want to map in pages without faults, so
223 		 * because we must check for PTE pages anyway we don't
224 		 * bother doing it here.
225 		 */
226 		addr = trunc_page(frame->code);
227 		if ((umode == 0) && (frame->code < 0))
228 			map = kernel_map;
229 		else
230 			map = &p->p_vmspace->vm_map;
231 
232 		if (frame->trap & T_WRITE)
233 			ftype = VM_PROT_WRITE;
234 		else
235 			ftype = VM_PROT_READ;
236 
237 		if (umode)
238 			KERNEL_PROC_LOCK(p);
239 		else
240 			KERNEL_LOCK(LK_CANRECURSE|LK_EXCLUSIVE);
241 		rv = uvm_fault(map, addr, 0, ftype);
242 		if (rv != 0) {
243 			if (umode == 0) {
244 				KERNEL_UNLOCK();
245 				FAULTCHK;
246 				panic("Segv in kernel mode: pc %x addr %x",
247 				    (u_int)frame->pc, (u_int)frame->code);
248 			}
249 			if (rv == ENOMEM) {
250 				printf("UVM: pid %d (%s), uid %d killed: "
251 				       "out of swap\n",
252 				       p->p_pid, p->p_comm,
253 				       p->p_cred && p->p_ucred ?
254 				       p->p_ucred->cr_uid : -1);
255 				sig = SIGKILL;
256 			} else {
257 				sig = SIGSEGV;
258 			}
259 		} else
260 			trapsig = 0;
261 		if (umode)
262 			KERNEL_PROC_UNLOCK(p);
263 		else
264 			KERNEL_UNLOCK();
265 		break;
266 
267 	case T_BPTFLT|T_USER:
268 	case T_TRCTRAP|T_USER:
269 		sig = SIGTRAP;
270 		frame->psl &= ~PSL_T;
271 		break;
272 
273 	case T_PRIVINFLT|T_USER:
274 	case T_RESADFLT|T_USER:
275 	case T_RESOPFLT|T_USER:
276 		sig = SIGILL;
277 		break;
278 
279 	case T_XFCFLT|T_USER:
280 		sig = SIGEMT;
281 		break;
282 
283 	case T_ARITHFLT|T_USER:
284 		sig = SIGFPE;
285 		break;
286 
287 	case T_ASTFLT|T_USER:
288 		mtpr(AST_NO,PR_ASTLVL);
289 		trapsig = 0;
290 		break;
291 
292 #ifdef DDB
293 	case T_BPTFLT: /* Kernel breakpoint */
294 	case T_KDBTRAP:
295 	case T_KDBTRAP|T_USER:
296 	case T_TRCTRAP:
297 		kdb_trap(frame);
298 		return;
299 #endif
300 	}
301 	if (trapsig) {
302 #ifdef DEBUG
303 		if (sig == SIGSEGV || sig == SIGILL)
304 			printf("pid %d (%s): sig %d: type %lx, code %lx, pc %lx, psl %lx\n",
305 			       p->p_pid, p->p_comm, sig, frame->trap,
306 			       frame->code, frame->pc, frame->psl);
307 #endif
308 		KERNEL_PROC_LOCK(p);
309 		trapsignal(p, sig, frame->code);
310 		KERNEL_PROC_UNLOCK(p);
311 	}
312 
313 	if (umode == 0)
314 		return;
315 
316 	userret(p, frame, oticks);
317 }
318 
319 void
320 setregs(struct proc *p, struct exec_package *pack, u_long stack)
321 {
322 	struct trapframe *exptr;
323 
324 	exptr = p->p_addr->u_pcb.framep;
325 	exptr->pc = pack->ep_entry + 2;
326 	exptr->sp = stack;
327 	exptr->r6 = stack;			/* for ELF */
328 	exptr->r7 = 0;				/* for ELF */
329 	exptr->r8 = 0;				/* for ELF */
330 	exptr->r9 = (u_long) p->p_psstr;	/* for ELF */
331 }
332 
333 void
334 syscall(struct trapframe *frame)
335 {
336 	const struct sysent *callp;
337 	u_quad_t oticks;
338 	int nsys;
339 	int err, rval[2], args[8];
340 	struct trapframe *exptr;
341 	struct proc *p = curproc;
342 
343 
344 #ifdef TRAPDEBUG
345 if(startsysc)printf("trap syscall %s pc %lx, psl %lx, sp %lx, pid %d, frame %p\n",
346 	       syscallnames[frame->code], frame->pc, frame->psl,frame->sp,
347 		curproc->p_pid,frame);
348 #endif
349 	uvmexp.syscalls++;
350 
351 	exptr = p->p_addr->u_pcb.framep = frame;
352 	callp = p->p_emul->e_sysent;
353 	nsys = p->p_emul->e_nsysent;
354 	oticks = p->p_sticks;
355 
356 	if (frame->code == SYS___syscall) {
357 		int g = *(int *)(frame->ap);
358 
359 		frame->code = *(int *)(frame->ap + 4);
360 		frame->ap += 8;
361 		*(int *)(frame->ap) = g - 2;
362 	}
363 
364 	if ((unsigned long) frame->code >= nsys)
365 		callp += p->p_emul->e_nosys;
366 	else
367 		callp += frame->code;
368 
369 	rval[0] = 0;
370 	rval[1] = frame->r1;
371 	KERNEL_PROC_LOCK(p);
372 	if (callp->sy_narg) {
373 		err = copyin((char*)frame->ap + 4, args, callp->sy_argsize);
374 		if (err) {
375 #ifdef KTRACE
376 			if (KTRPOINT(p, KTR_SYSCALL))
377 				ktrsyscall(p, frame->code,
378 				    callp->sy_argsize, args);
379 #endif
380 			goto bad;
381 		}
382 	}
383 #ifdef KTRACE
384 	if (KTRPOINT(p, KTR_SYSCALL))
385 		ktrsyscall(p, frame->code, callp->sy_argsize, args);
386 #endif
387 	err = (*callp->sy_call)(curproc, args, rval);
388 	KERNEL_PROC_UNLOCK(p);
389 	exptr = curproc->p_addr->u_pcb.framep;
390 
391 #ifdef TRAPDEBUG
392 if(startsysc)
393 	printf("retur %s pc %lx, psl %lx, sp %lx, pid %d, err %d r0 %d, r1 %d, frame %p\n",
394 	       syscallnames[exptr->code], exptr->pc, exptr->psl,exptr->sp,
395 		p->p_pid,err,rval[0],rval[1],exptr); /* } */
396 #endif
397 
398 bad:
399 	switch (err) {
400 	case 0:
401 		exptr->r1 = rval[1];
402 		exptr->r0 = rval[0];
403 		exptr->psl &= ~PSL_C;
404 		break;
405 
406 	case EJUSTRETURN:
407 		break;
408 
409 	case ERESTART:
410 		exptr->pc -= (exptr->code > 63 ? 4 : 2);
411 		break;
412 
413 	default:
414 		exptr->r0 = err;
415 		exptr->psl |= PSL_C;
416 		break;
417 	}
418 
419 	userret(p, frame, oticks);
420 
421 #ifdef KTRACE
422 	if (KTRPOINT(p, KTR_SYSRET)) {
423 		KERNEL_PROC_LOCK(p);
424 		ktrsysret(p, frame->code, err, rval[0]);
425 		KERNEL_PROC_UNLOCK(p);
426 	}
427 #endif
428 }
429 
430 void
431 child_return(void *arg)
432 {
433         struct proc *p = arg;
434 
435 	KERNEL_PROC_UNLOCK(p);
436 	userret(p, p->p_addr->u_pcb.framep, 0);
437 
438 #ifdef KTRACE
439 	if (KTRPOINT(p, KTR_SYSRET)) {
440 		KERNEL_PROC_LOCK(p);
441 		ktrsysret(p, SYS_fork, 0, 0);
442 		KERNEL_PROC_UNLOCK(p);
443 	}
444 #endif
445 }
446