xref: /netbsd-src/sys/arch/vax/vax/trap.c (revision 89c5a767f8fc7a4633b2d409966e2becbb98ff92)
1 /*	$NetBSD: trap.c,v 1.47 1999/08/21 19:26:20 matt Exp $     */
2 /*
3  * Copyright (c) 1994 Ludd, University of Lule}, Sweden.
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. All advertising materials mentioning features or use of this software
15  *    must display the following acknowledgement:
16  *     This product includes software developed at Ludd, University of Lule}.
17  * 4. The name of the author may not be used to endorse or promote products
18  *    derived from this software without specific prior written permission
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
21  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
22  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
23  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
24  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
25  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
29  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32  /* All bugs are subject to removal without further notice */
33 
34 #include "opt_ddb.h"
35 #include "opt_ktrace.h"
36 
37 #include <sys/types.h>
38 #include <sys/param.h>
39 #include <sys/proc.h>
40 #include <sys/user.h>
41 #include <sys/syscall.h>
42 #include <sys/systm.h>
43 #include <sys/signalvar.h>
44 #include <sys/exec.h>
45 
46 #include <vm/vm.h>
47 #include <vm/vm_kern.h>
48 #include <vm/vm_page.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 void	arithflt __P((struct trapframe *));
70 void	syscall __P((struct trapframe *));
71 
72 char *traptypes[]={
73 	"reserved addressing",
74 	"privileged instruction",
75 	"reserved operand",
76 	"breakpoint instruction",
77 	"XFC instruction",
78 	"system call ",
79 	"arithmetic trap",
80 	"asynchronous system trap",
81 	"page table length fault",
82 	"translation violation fault",
83 	"trace trap",
84 	"compatibility mode fault",
85 	"access violation fault",
86 	"",
87 	"",
88 	"KSP invalid",
89 	"",
90 	"kernel debugger trap"
91 };
92 int no_traps = 18;
93 
94 #define USERMODE(framep)   ((((framep)->psl) & (PSL_U)) == PSL_U)
95 #define FAULTCHK						\
96 	if (p->p_addr->u_pcb.iftrap) {				\
97 		frame->pc = (unsigned)p->p_addr->u_pcb.iftrap;	\
98 		frame->psl &= ~PSL_FPD;				\
99 		frame->r0 = EFAULT;/* for copyin/out */		\
100 		frame->r1 = -1; /* for fetch/store */		\
101 		return;						\
102 	}
103 
104 void
105 arithflt(frame)
106 	struct trapframe *frame;
107 {
108 	u_int	sig = 0, type = frame->trap, trapsig = 1;
109 	u_int	rv, addr, umode;
110 	struct	proc *p = curproc;
111 	u_quad_t oticks = 0;
112 	vm_map_t map;
113 	vm_prot_t ftype;
114 
115 	uvmexp.traps++;
116 	if ((umode = USERMODE(frame))) {
117 		type |= T_USER;
118 		oticks = p->p_sticks;
119 		p->p_addr->u_pcb.framep = frame;
120 	}
121 
122 	type&=~(T_WRITE|T_PTEFETCH);
123 
124 
125 #ifdef TRAPDEBUG
126 if(frame->trap==7) goto fram;
127 if(faultdebug)printf("Trap: type %lx, code %lx, pc %lx, psl %lx\n",
128 		frame->trap, frame->code, frame->pc, frame->psl);
129 fram:
130 #endif
131 	switch(type){
132 
133 	default:
134 #ifdef DDB
135 		kdb_trap(frame);
136 #endif
137 		printf("Trap: type %x, code %x, pc %x, psl %x\n",
138 		    (u_int)frame->trap, (u_int)frame->code,
139 		    (u_int)frame->pc, (u_int)frame->psl);
140 		panic("trap");
141 
142 	case T_KSPNOTVAL:
143 		panic("kernel stack invalid");
144 
145 	case T_TRANSFLT|T_USER:
146 	case T_TRANSFLT:
147 		/*
148 		 * BUG! BUG! BUG! BUG! BUG!
149 		 * Due to a hardware bug (at in least KA65x CPUs) a double
150 		 * page table fetch trap will cause a translation fault
151 		 * even if access in the SPT PTE entry specifies 'no access'.
152 		 * In for example section 6.4.2 in VAX Architecture
153 		 * Reference Manual it states that if a page both are invalid
154 		 * and have no access set, a 'access violation fault' occurs.
155 		 * Therefore, we must fall through here...
156 		 */
157 #ifdef nohwbug
158 		panic("translation fault");
159 #endif
160 	case T_ACCFLT|T_USER:
161 		if (frame->code < 0) { /* Check for kernel space */
162 			sig = SIGSEGV;
163 			break;
164 		}
165 	case T_ACCFLT:
166 #ifdef TRAPDEBUG
167 if(faultdebug)printf("trap accflt type %lx, code %lx, pc %lx, psl %lx\n",
168 			frame->trap, frame->code, frame->pc, frame->psl);
169 #endif
170 #ifdef DIAGNOSTIC
171 		if (p == 0)
172 			panic("trap: access fault: addr %lx code %lx",
173 			    frame->pc, frame->code);
174 #endif
175 
176 		/*
177 		 * Page tables are allocated in pmap_enter(). We get
178 		 * info from below if it is a page table fault, but
179 		 * UVM may want to map in pages without faults, so
180 		 * because we must check for PTE pages anyway we don't
181 		 * bother doing it here.
182 		 */
183 		addr = trunc_page(frame->code);
184 		if ((umode == 0) && (frame->code < 0))
185 			map = kernel_map;
186 		else
187 			map = &p->p_vmspace->vm_map;
188 
189 		if (frame->trap & T_WRITE)
190 			ftype = VM_PROT_WRITE|VM_PROT_READ;
191 		else
192 			ftype = VM_PROT_READ;
193 
194 		rv = uvm_fault(map, addr, 0, ftype);
195 		if (rv != KERN_SUCCESS) {
196 			if (umode == 0) {
197 				FAULTCHK;
198 				panic("Segv in kernel mode: pc %x addr %x",
199 				    (u_int)frame->pc, (u_int)frame->code);
200 			}
201 			if (rv == KERN_RESOURCE_SHORTAGE) {
202 				printf("UVM: pid %d (%s), uid %d killed: "
203 				       "out of swap\n",
204 				       p->p_pid, p->p_comm,
205 				       p->p_cred && p->p_ucred ?
206 				       p->p_ucred->cr_uid : -1);
207 				sig = SIGKILL;
208 			} else {
209 				sig = SIGSEGV;
210 			}
211 		} else
212 			trapsig = 0;
213 		break;
214 
215 	case T_PTELEN:
216 		if (p && p->p_addr)
217 			FAULTCHK;
218 		panic("ptelen fault in system space: addr %lx pc %lx",
219 		    frame->code, frame->pc);
220 
221 	case T_PTELEN|T_USER:	/* Page table length exceeded */
222 		sig = SIGSEGV;
223 		break;
224 
225 	case T_BPTFLT|T_USER:
226 	case T_TRCTRAP|T_USER:
227 		sig = SIGTRAP;
228 		frame->psl &= ~PSL_T;
229 		break;
230 
231 	case T_PRIVINFLT|T_USER:
232 	case T_RESADFLT|T_USER:
233 	case T_RESOPFLT|T_USER:
234 		sig = SIGILL;
235 		break;
236 
237 	case T_XFCFLT|T_USER:
238 		sig = SIGEMT;
239 		break;
240 
241 	case T_ARITHFLT|T_USER:
242 		sig = SIGFPE;
243 		break;
244 
245 	case T_ASTFLT|T_USER:
246 		mtpr(AST_NO,PR_ASTLVL);
247 		trapsig = 0;
248 		break;
249 
250 #ifdef DDB
251 	case T_BPTFLT: /* Kernel breakpoint */
252 	case T_KDBTRAP:
253 	case T_KDBTRAP|T_USER:
254 	case T_TRCTRAP:
255 		kdb_trap(frame);
256 		return;
257 #endif
258 	}
259 
260 	if (trapsig)
261 		trapsignal(p, sig, frame->code);
262 
263 	if (umode == 0)
264 		return;
265 
266 	while ((sig = CURSIG(p)) !=0)
267 		postsig(sig);
268 	p->p_priority = p->p_usrpri;
269 	if (want_resched) {
270 		/*
271 		 * Since we are curproc, clock will normally just change
272 		 * our priority without moving us from one queue to another
273 		 * (since the running process is not on a queue.)
274 		 * If that happened after we setrunqueue ourselves but before
275 		 * we swtch()'ed, we might not be on the queue indicated by
276 		 * our priority.
277 		 */
278 		splstatclock();
279 		setrunqueue(p);
280 		mi_switch();
281 		while ((sig = CURSIG(p)) != 0)
282 			postsig(sig);
283 	}
284 	if (p->p_flag & P_PROFIL) {
285 		extern int psratio;
286 		addupc_task(p, frame->pc, (int)(p->p_sticks-oticks) * psratio);
287 	}
288 	curpriority = p->p_priority;
289 }
290 
291 void
292 setregs(p, pack, stack)
293 	struct proc *p;
294 	struct exec_package *pack;
295 	u_long stack;
296 {
297 	struct trapframe *exptr;
298 
299 	exptr = p->p_addr->u_pcb.framep;
300 	exptr->pc = pack->ep_entry + 2;
301 	exptr->sp = stack;
302 	exptr->r6 = stack;			/* for ELF */
303 	exptr->r7 = 0;				/* for ELF */
304 	exptr->r8 = 0;				/* for ELF */
305 	exptr->r9 = (u_long) PS_STRINGS;	/* for ELF */
306 }
307 
308 void
309 syscall(frame)
310 	struct	trapframe *frame;
311 {
312 	struct sysent *callp;
313 	u_quad_t oticks;
314 	int nsys, sig;
315 	int err, rval[2], args[8];
316 	struct trapframe *exptr;
317 	struct proc *p = curproc;
318 
319 #ifdef TRAPDEBUG
320 if(startsysc)printf("trap syscall %s pc %lx, psl %lx, sp %lx, pid %d, frame %p\n",
321 	       syscallnames[frame->code], frame->pc, frame->psl,frame->sp,
322 		curproc->p_pid,frame);
323 #endif
324 	uvmexp.syscalls++;
325 
326 	exptr = p->p_addr->u_pcb.framep = frame;
327 	callp = p->p_emul->e_sysent;
328 	nsys = p->p_emul->e_nsysent;
329 	oticks = p->p_sticks;
330 
331 	if(frame->code == SYS___syscall){
332 		int g = *(int *)(frame->ap);
333 
334 		frame->code = *(int *)(frame->ap + 4);
335 		frame->ap += 8;
336 		*(int *)(frame->ap) = g - 2;
337 	}
338 
339 	if(frame->code < 0 || frame->code >= nsys)
340 		callp += p->p_emul->e_nosys;
341 	else
342 		callp += frame->code;
343 
344 	rval[0] = 0;
345 	rval[1] = frame->r1;
346 	if(callp->sy_narg) {
347 		err = copyin((char*)frame->ap + 4, args, callp->sy_argsize);
348 		if (err) {
349 #ifdef KTRACE
350 			if (KTRPOINT(p, KTR_SYSCALL))
351 				ktrsyscall(p->p_tracep, frame->code,
352 				    callp->sy_argsize, args);
353 #endif
354 			goto bad;
355 		}
356 	}
357 #ifdef KTRACE
358 	if (KTRPOINT(p, KTR_SYSCALL))
359 		ktrsyscall(p->p_tracep, frame->code, callp->sy_argsize, args);
360 #endif
361 	err = (*callp->sy_call)(curproc, args, rval);
362 	exptr = curproc->p_addr->u_pcb.framep;
363 
364 #ifdef TRAPDEBUG
365 if(startsysc)
366 	printf("retur %s pc %lx, psl %lx, sp %lx, pid %d, v{rde %d r0 %d, r1 %d, frame %p\n",
367 	       syscallnames[exptr->code], exptr->pc, exptr->psl,exptr->sp,
368 		curproc->p_pid,err,rval[0],rval[1],exptr);
369 #endif
370 
371 bad:
372 	switch (err) {
373 	case 0:
374 		exptr->r1 = rval[1];
375 		exptr->r0 = rval[0];
376 		exptr->psl &= ~PSL_C;
377 		break;
378 
379 	case EJUSTRETURN:
380 		return;
381 
382 	case ERESTART:
383 		exptr->pc -= (exptr->code > 63 ? 4 : 2);
384 		break;
385 
386 	default:
387 		exptr->r0 = err;
388 		exptr->psl |= PSL_C;
389 		break;
390 	}
391 	p = curproc;
392 	while ((sig = CURSIG(p)) !=0)
393 		postsig(sig);
394 	p->p_priority = p->p_usrpri;
395 	if (want_resched) {
396 		/*
397 		 * Since we are curproc, clock will normally just change
398 		 * our priority without moving us from one queue to another
399 		 * (since the running process is not on a queue.)
400 		 * If that happened after we setrunqueue ourselves but before
401 		 * we swtch()'ed, we might not be on the queue indicated by
402 		 * our priority.
403 		 */
404 		splstatclock();
405 		setrunqueue(p);
406 		mi_switch();
407 		while ((sig = CURSIG(p)) != 0)
408 			postsig(sig);
409 	}
410 	if (p->p_flag & P_PROFIL) {
411 		extern int psratio;
412 		addupc_task(p, frame->pc, (int)(p->p_sticks-oticks) * psratio);
413 	}
414 #ifdef KTRACE
415 	if (KTRPOINT(p, KTR_SYSRET))
416 		ktrsysret(p->p_tracep, frame->code, err, rval[0]);
417 #endif
418 }
419