xref: /netbsd-src/sys/arch/vax/vax/trap.c (revision 481fca6e59249d8ffcf24fef7cfbe7b131bfb080)
1 /*	$NetBSD: trap.c,v 1.56 2000/06/29 07:14:34 mrg 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 __P((struct proc *, struct trapframe *, u_quad_t));
70 
71 void	arithflt __P((struct trapframe *));
72 void	syscall __P((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(p, frame, oticks)
114 	struct proc *p;
115 	struct trapframe *frame;
116 	u_quad_t oticks;
117 {
118 	int sig;
119 
120 	/* Take pending signals. */
121 	while ((sig = CURSIG(p)) != 0)
122 		postsig(sig);
123 	p->p_priority = p->p_usrpri;
124 	if (curcpu()->ci_want_resched) {
125 		/*
126 		 * We are being preempted.
127 		 */
128 		preempt(NULL);
129 		while ((sig = CURSIG(p)) != 0)
130 			postsig(sig);
131 	}
132 
133 	/*
134 	 * If profiling, charge system time to the trapped pc.
135 	 */
136 	if (p->p_flag & P_PROFIL) {
137 		extern int psratio;
138 
139 		addupc_task(p, frame->pc,
140 		    (int)(p->p_sticks - oticks) * psratio);
141 	}
142 	curcpu()->ci_schedstate.spc_curpriority = p->p_priority;
143 }
144 
145 void
146 arithflt(frame)
147 	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 	vm_map_t map;
154 	vm_prot_t ftype;
155 
156 	uvmexp.traps++;
157 	if ((umode = USERMODE(frame))) {
158 		type |= T_USER;
159 		oticks = p->p_sticks;
160 		p->p_addr->u_pcb.framep = frame;
161 	}
162 
163 	type&=~(T_WRITE|T_PTEFETCH);
164 
165 
166 #ifdef TRAPDEBUG
167 if(frame->trap==7) goto fram;
168 if(faultdebug)printf("Trap: type %lx, code %lx, pc %lx, psl %lx\n",
169 		frame->trap, frame->code, frame->pc, frame->psl);
170 fram:
171 #endif
172 	switch(type){
173 
174 	default:
175 #ifdef DDB
176 		kdb_trap(frame);
177 #endif
178 		printf("Trap: type %x, code %x, pc %x, psl %x\n",
179 		    (u_int)frame->trap, (u_int)frame->code,
180 		    (u_int)frame->pc, (u_int)frame->psl);
181 		panic("trap");
182 
183 	case T_KSPNOTVAL:
184 		panic("kernel stack invalid");
185 
186 	case T_TRANSFLT|T_USER:
187 	case T_TRANSFLT:
188 		/*
189 		 * BUG! BUG! BUG! BUG! BUG!
190 		 * Due to a hardware bug (at in least KA65x CPUs) a double
191 		 * page table fetch trap will cause a translation fault
192 		 * even if access in the SPT PTE entry specifies 'no access'.
193 		 * In for example section 6.4.2 in VAX Architecture
194 		 * Reference Manual it states that if a page both are invalid
195 		 * and have no access set, a 'access violation fault' occurs.
196 		 * Therefore, we must fall through here...
197 		 */
198 #ifdef nohwbug
199 		panic("translation fault");
200 #endif
201 	case T_ACCFLT|T_USER:
202 		if (frame->code < 0) { /* Check for kernel space */
203 			sig = SIGSEGV;
204 			break;
205 		}
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 #endif
216 
217 		/*
218 		 * Page tables are allocated in pmap_enter(). We get
219 		 * info from below if it is a page table fault, but
220 		 * UVM may want to map in pages without faults, so
221 		 * because we must check for PTE pages anyway we don't
222 		 * bother doing it here.
223 		 */
224 		addr = trunc_page(frame->code);
225 		if ((umode == 0) && (frame->code < 0))
226 			map = kernel_map;
227 		else
228 			map = &p->p_vmspace->vm_map;
229 
230 		if (frame->trap & T_WRITE)
231 			ftype = VM_PROT_WRITE|VM_PROT_READ;
232 		else
233 			ftype = VM_PROT_READ;
234 
235 		rv = uvm_fault(map, addr, 0, ftype);
236 		if (rv != KERN_SUCCESS) {
237 			if (umode == 0) {
238 				FAULTCHK;
239 				panic("Segv in kernel mode: pc %x addr %x",
240 				    (u_int)frame->pc, (u_int)frame->code);
241 			}
242 			if (rv == KERN_RESOURCE_SHORTAGE) {
243 				printf("UVM: pid %d (%s), uid %d killed: "
244 				       "out of swap\n",
245 				       p->p_pid, p->p_comm,
246 				       p->p_cred && p->p_ucred ?
247 				       p->p_ucred->cr_uid : -1);
248 				sig = SIGKILL;
249 			} else {
250 				sig = SIGSEGV;
251 			}
252 		} else
253 			trapsig = 0;
254 		break;
255 
256 	case T_PTELEN:
257 		if (p && p->p_addr)
258 			FAULTCHK;
259 		panic("ptelen fault in system space: addr %lx pc %lx",
260 		    frame->code, frame->pc);
261 
262 	case T_PTELEN|T_USER:	/* Page table length exceeded */
263 		sig = SIGSEGV;
264 		break;
265 
266 	case T_BPTFLT|T_USER:
267 	case T_TRCTRAP|T_USER:
268 		sig = SIGTRAP;
269 		frame->psl &= ~PSL_T;
270 		break;
271 
272 	case T_PRIVINFLT|T_USER:
273 	case T_RESADFLT|T_USER:
274 	case T_RESOPFLT|T_USER:
275 		sig = SIGILL;
276 		break;
277 
278 	case T_XFCFLT|T_USER:
279 		sig = SIGEMT;
280 		break;
281 
282 	case T_ARITHFLT|T_USER:
283 		sig = SIGFPE;
284 		break;
285 
286 	case T_ASTFLT|T_USER:
287 		mtpr(AST_NO,PR_ASTLVL);
288 		trapsig = 0;
289 		break;
290 
291 #ifdef DDB
292 	case T_BPTFLT: /* Kernel breakpoint */
293 	case T_KDBTRAP:
294 	case T_KDBTRAP|T_USER:
295 	case T_TRCTRAP:
296 		kdb_trap(frame);
297 		return;
298 #endif
299 	}
300 
301 	if (trapsig)
302 		trapsignal(p, sig, frame->code);
303 
304 	if (umode == 0)
305 		return;
306 
307 	userret(p, frame, oticks);
308 }
309 
310 void
311 setregs(p, pack, stack)
312 	struct proc *p;
313 	struct exec_package *pack;
314 	u_long stack;
315 {
316 	struct trapframe *exptr;
317 
318 	exptr = p->p_addr->u_pcb.framep;
319 	exptr->pc = pack->ep_entry + 2;
320 	exptr->sp = stack;
321 	exptr->r6 = stack;			/* for ELF */
322 	exptr->r7 = 0;				/* for ELF */
323 	exptr->r8 = 0;				/* for ELF */
324 	exptr->r9 = (u_long) PS_STRINGS;	/* for ELF */
325 }
326 
327 void
328 syscall(frame)
329 	struct	trapframe *frame;
330 {
331 	struct sysent *callp;
332 	u_quad_t oticks;
333 	int nsys;
334 	int err, rval[2], args[8];
335 	struct trapframe *exptr;
336 	struct proc *p = curproc;
337 
338 #ifdef TRAPDEBUG
339 if(startsysc)printf("trap syscall %s pc %lx, psl %lx, sp %lx, pid %d, frame %p\n",
340 	       syscallnames[frame->code], frame->pc, frame->psl,frame->sp,
341 		curproc->p_pid,frame);
342 #endif
343 	uvmexp.syscalls++;
344 
345 	exptr = p->p_addr->u_pcb.framep = frame;
346 	callp = p->p_emul->e_sysent;
347 	nsys = p->p_emul->e_nsysent;
348 	oticks = p->p_sticks;
349 
350 	if(frame->code == SYS___syscall){
351 		int g = *(int *)(frame->ap);
352 
353 		frame->code = *(int *)(frame->ap + 4);
354 		frame->ap += 8;
355 		*(int *)(frame->ap) = g - 2;
356 	}
357 
358 	if(frame->code < 0 || frame->code >= nsys)
359 		callp += p->p_emul->e_nosys;
360 	else
361 		callp += frame->code;
362 
363 	rval[0] = 0;
364 	rval[1] = frame->r1;
365 	if(callp->sy_narg) {
366 		err = copyin((char*)frame->ap + 4, args, callp->sy_argsize);
367 		if (err) {
368 #ifdef KTRACE
369 			if (KTRPOINT(p, KTR_SYSCALL))
370 				ktrsyscall(p, frame->code,
371 				    callp->sy_argsize, args);
372 #endif
373 			goto bad;
374 		}
375 	}
376 #ifdef KTRACE
377 	if (KTRPOINT(p, KTR_SYSCALL))
378 		ktrsyscall(p, frame->code, callp->sy_argsize, args);
379 #endif
380 	err = (*callp->sy_call)(curproc, args, rval);
381 	exptr = curproc->p_addr->u_pcb.framep;
382 
383 #ifdef TRAPDEBUG
384 if(startsysc)
385 	printf("retur %s pc %lx, psl %lx, sp %lx, pid %d, v{rde %d r0 %d, r1 %d, frame %p\n",
386 	       syscallnames[exptr->code], exptr->pc, exptr->psl,exptr->sp,
387 		p->p_pid,err,rval[0],rval[1],exptr); /* } */
388 #endif
389 
390 bad:
391 	switch (err) {
392 	case 0:
393 		exptr->r1 = rval[1];
394 		exptr->r0 = rval[0];
395 		exptr->psl &= ~PSL_C;
396 		break;
397 
398 	case EJUSTRETURN:
399 		return;
400 
401 	case ERESTART:
402 		exptr->pc -= (exptr->code > 63 ? 4 : 2);
403 		break;
404 
405 	default:
406 		exptr->r0 = err;
407 		exptr->psl |= PSL_C;
408 		break;
409 	}
410 
411 	userret(p, frame, oticks);
412 
413 #ifdef KTRACE
414 	if (KTRPOINT(p, KTR_SYSRET))
415 		ktrsysret(p, frame->code, err, rval[0]);
416 #endif
417 }
418 
419 void
420 child_return(void *arg)
421 {
422         struct proc *p = arg;
423 
424 	userret(p, p->p_addr->u_pcb.framep, 0);
425 
426 #ifdef KTRACE
427 	if (KTRPOINT(p, KTR_SYSRET))
428 		ktrsysret(p, SYS_fork, 0, 0);
429 #endif
430 }
431 
432