xref: /netbsd-src/sys/arch/vax/vax/trap.c (revision 2a399c6883d870daece976daec6ffa7bb7f934ce)
1 /*      $NetBSD: trap.c,v 1.33 1998/01/03 00:35:28 thorpej 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 
35 
36 #include <sys/types.h>
37 #include <sys/param.h>
38 #include <sys/proc.h>
39 #include <sys/user.h>
40 #include <sys/syscall.h>
41 #include <sys/systm.h>
42 #include <sys/signalvar.h>
43 #include <sys/exec.h>
44 
45 #include <vm/vm.h>
46 #include <vm/vm_kern.h>
47 #include <vm/vm_page.h>
48 
49 #include <machine/mtpr.h>
50 #include <machine/pte.h>
51 #include <machine/pcb.h>
52 #include <machine/trap.h>
53 #include <machine/pmap.h>
54 #include <machine/cpu.h>
55 
56 #ifdef DDB
57 #include <machine/db_machdep.h>
58 #endif
59 #include <kern/syscalls.c>
60 #ifdef KTRACE
61 #include <sys/ktrace.h>
62 #endif
63 
64 #ifdef TRAPDEBUG
65 volatile int startsysc = 0, faultdebug = 0;
66 #endif
67 
68 void	arithflt __P((struct trapframe *));
69 void	syscall __P((struct trapframe *));
70 void	stray __P((int, int));
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, type = frame->trap, trapsig = 1;
109 	u_int	rv, addr, umode;
110 	struct	proc *p = curproc;
111 	struct	pmap *pm;
112 	u_quad_t oticks = 0;
113 	vm_map_t map;
114 	vm_prot_t ftype;
115 	extern vm_map_t	pte_map;
116 
117 	if ((umode = USERMODE(frame))) {
118 		type |= T_USER;
119 		oticks = p->p_sticks;
120 		p->p_addr->u_pcb.framep = frame;
121 	}
122 
123 	type&=~(T_WRITE|T_PTEFETCH);
124 
125 
126 #ifdef TRAPDEBUG
127 if(frame->trap==7) goto fram;
128 if(faultdebug)printf("Trap: type %x, code %x, pc %x, psl %x\n",
129 		frame->trap, frame->code, frame->pc, frame->psl);
130 fram:
131 #endif
132 	switch(type){
133 
134 	default:
135 #ifdef DDB
136 		kdb_trap(frame);
137 #endif
138 		printf("Trap: type %x, code %x, pc %x, psl %x\n",
139 		    (u_int)frame->trap, (u_int)frame->code,
140 		    (u_int)frame->pc, (u_int)frame->psl);
141 		panic("trap");
142 
143 	case T_KSPNOTVAL:
144 		panic("kernel stack invalid");
145 
146 	case T_TRANSFLT|T_USER:
147 	case T_TRANSFLT:
148 		/*
149 		 * BUG! BUG! BUG! BUG! BUG!
150 		 * Due to a hardware bug (at in least KA65x CPUs) a double
151 		 * page table fetch trap will cause a translation fault
152 		 * even if access in the SPT PTE entry specifies 'no access'.
153 		 * In for example section 6.4.2 in VAX Architecture
154 		 * Reference Manual it states that if a page both are invalid
155 		 * and have no access set, a 'access violation fault' occurs.
156 		 * Therefore, we must fall through here...
157 		 */
158 #ifdef nohwbug
159 		panic("translation fault");
160 #endif
161 	case T_ACCFLT|T_USER:
162 		if (frame->code < 0) { /* Check for kernel space */
163 			sig = SIGSEGV;
164 			break;
165 		}
166 	case T_ACCFLT:
167 #ifdef TRAPDEBUG
168 if(faultdebug)printf("trap accflt type %x, code %x, pc %x, psl %x\n",
169                         frame->trap, frame->code, frame->pc, frame->psl);
170 #endif
171 #ifdef DIAGNOSTIC
172 		if (p == 0)
173 			panic("trap: access fault without process");
174 #endif
175 		/*
176 		 * First check for ptefetch. Can only happen to pages
177 		 * in user space.
178 		 */
179 		if (frame->trap & T_PTEFETCH) {
180 			pm = p->p_vmspace->vm_map.pmap;
181 			if (frame->code < 0x40000000) {
182 				addr = trunc_page((unsigned)&pm->pm_p0br[
183 				    frame->code >> PGSHIFT]);
184 #ifdef DEBUG
185 			} else if (frame->code < 0) {
186 				panic("ptefetch in kernel");
187 #endif
188 			} else {
189 				addr = trunc_page((unsigned)&pm->pm_p1br[
190 				    (frame->code & 0x3fffffff) >> PGSHIFT]);
191 			}
192 			rv = vm_fault(pte_map, addr,
193 			    VM_PROT_WRITE|VM_PROT_READ, FALSE);
194 			if (rv != KERN_SUCCESS) {
195 				sig = SIGSEGV;
196 				break;
197 			} else
198 				trapsig = 0;
199 		}
200 		addr = trunc_page(frame->code);
201 		if ((umode == 0) && (frame->code < 0))
202 			map = kernel_map;
203 		else
204 			map = &p->p_vmspace->vm_map;
205 
206 		if (frame->trap & T_WRITE)
207 			ftype = VM_PROT_WRITE|VM_PROT_READ;
208 		else
209 			ftype = VM_PROT_READ;
210 
211 		rv = vm_fault(map, addr, ftype, FALSE);
212 		if (rv != KERN_SUCCESS) {
213 			if (umode == 0) {
214 				FAULTCHK;
215 				panic("Segv in kernel mode: pc %x addr %x",
216 				    (u_int)frame->pc, (u_int)frame->code);
217 			}
218 			sig = SIGSEGV;
219 		} else
220 			trapsig = 0;
221 		break;
222 
223 	case T_PTELEN:
224 		FAULTCHK;
225 		panic("ptelen fault in system space");
226 
227 	case T_PTELEN|T_USER:	/* Page table length exceeded */
228 		sig = SIGSEGV;
229 		break;
230 
231 	case T_BPTFLT|T_USER:
232 	case T_TRCTRAP|T_USER:
233 		sig = SIGTRAP;
234 		frame->psl &= ~PSL_T;
235 		break;
236 
237 	case T_PRIVINFLT|T_USER:
238 	case T_RESADFLT|T_USER:
239 	case T_RESOPFLT|T_USER:
240 		sig = SIGILL;
241 		break;
242 
243 	case T_XFCFLT|T_USER:
244 		sig = SIGEMT;
245 		break;
246 
247 	case T_ARITHFLT|T_USER:
248 		sig = SIGFPE;
249 		break;
250 
251 	case T_ASTFLT|T_USER:
252 		mtpr(AST_NO,PR_ASTLVL);
253 		trapsig = 0;
254 		break;
255 
256 #ifdef DDB
257 	case T_KDBTRAP:
258 		kdb_trap(frame);
259 		return;
260 #endif
261 	}
262 
263 	if (trapsig)
264 		trapsignal(p, sig, frame->code);
265 
266 	if (umode == 0)
267 		return;
268 
269 	while ((sig = CURSIG(p)) !=0)
270 		postsig(sig);
271 	p->p_priority = p->p_usrpri;
272 	if (want_resched) {
273                 /*
274                  * Since we are curproc, clock will normally just change
275                  * our priority without moving us from one queue to another
276                  * (since the running process is not on a queue.)
277                  * If that happened after we setrunqueue ourselves but before
278 		 * we swtch()'ed, we might not be on the queue indicated by
279                  * our priority.
280                  */
281 		splstatclock();
282 		setrunqueue(p);
283 		mi_switch();
284 		while ((sig = CURSIG(p)) != 0)
285 			postsig(sig);
286 	}
287 	if (p->p_flag & P_PROFIL) {
288 		extern int psratio;
289 		addupc_task(p, frame->pc, (int)(p->p_sticks-oticks) * psratio);
290 	}
291         curpriority = p->p_priority;
292 }
293 
294 void
295 setregs(p, pack, stack)
296         struct proc *p;
297 	struct exec_package *pack;
298         u_long stack;
299 {
300 	struct trapframe *exptr;
301 
302 	exptr = p->p_addr->u_pcb.framep;
303 	exptr->pc = pack->ep_entry + 2;
304 	exptr->sp = stack;
305 }
306 
307 void
308 syscall(frame)
309 	struct	trapframe *frame;
310 {
311 	struct sysent *callp;
312 	u_quad_t oticks;
313 	int nsys, sig;
314 	int err, rval[2], args[8];
315 	struct trapframe *exptr;
316 	struct proc *p = curproc;
317 
318 #ifdef TRAPDEBUG
319 if(startsysc)printf("trap syscall %s pc %x, psl %x, sp %x, pid %d, frame %x\n",
320                syscallnames[frame->code], frame->pc, frame->psl,frame->sp,
321 		curproc->p_pid,frame);
322 #endif
323 
324 	exptr = p->p_addr->u_pcb.framep = frame;
325 	callp = p->p_emul->e_sysent;
326 	nsys = p->p_emul->e_nsysent;
327 	oticks = p->p_sticks;
328 
329 	if(frame->code == SYS___syscall){
330 		int g = *(int *)(frame->ap);
331 
332 		frame->code = *(int *)(frame->ap + 4);
333 		frame->ap += 8;
334 		*(int *)(frame->ap) = g - 2;
335 	}
336 
337 	if(frame->code < 0 || frame->code >= nsys)
338 		callp += p->p_emul->e_nosys;
339 	else
340 		callp += frame->code;
341 
342 	rval[0] = 0;
343 	rval[1] = frame->r1;
344 	if(callp->sy_narg) {
345 		err = copyin((char*)frame->ap + 4, args, callp->sy_argsize);
346 		if (err) {
347 #ifdef KTRACE
348 			if (KTRPOINT(p, KTR_SYSCALL))
349 				ktrsyscall(p->p_tracep, frame->code,
350 				    callp->sy_argsize, args);
351 #endif
352 			goto bad;
353 		}
354 	}
355 #ifdef KTRACE
356 	if (KTRPOINT(p, KTR_SYSCALL))
357 		ktrsyscall(p->p_tracep, frame->code, callp->sy_argsize, args);
358 #endif
359 	err = (*callp->sy_call)(curproc, args, rval);
360 	exptr = curproc->p_addr->u_pcb.framep;
361 
362 #ifdef TRAPDEBUG
363 if(startsysc)
364 	printf("retur %s pc %x, psl %x, sp %x, pid %d, v{rde %d r0 %d, r1 %d, frame %x\n",
365                syscallnames[exptr->code], exptr->pc, exptr->psl,exptr->sp,
366                 curproc->p_pid,err,rval[0],rval[1],exptr);
367 #endif
368 
369 bad:
370 	switch (err) {
371 	case 0:
372 		exptr->r1 = rval[1];
373 		exptr->r0 = rval[0];
374 		exptr->psl &= ~PSL_C;
375 		break;
376 
377 	case EJUSTRETURN:
378 		return;
379 
380 	case ERESTART:
381 		exptr->pc -= (exptr->code > 63 ? 4 : 2);
382 		break;
383 
384 	default:
385 		exptr->r0 = err;
386 		exptr->psl |= PSL_C;
387 		break;
388 	}
389 	p = curproc;
390 	while ((sig = CURSIG(p)) !=0)
391 		postsig(sig);
392 	p->p_priority = p->p_usrpri;
393 	if (want_resched) {
394                 /*
395                  * Since we are curproc, clock will normally just change
396                  * our priority without moving us from one queue to another
397                  * (since the running process is not on a queue.)
398                  * If that happened after we setrunqueue ourselves but before
399 		 * we swtch()'ed, we might not be on the queue indicated by
400                  * our priority.
401                  */
402 		splstatclock();
403 		setrunqueue(p);
404 		mi_switch();
405 		while ((sig = CURSIG(p)) != 0)
406 			postsig(sig);
407 	}
408 	if (p->p_flag & P_PROFIL) {
409 		extern int psratio;
410 		addupc_task(p, frame->pc, (int)(p->p_sticks-oticks) * psratio);
411 	}
412 #ifdef KTRACE
413 	if (KTRPOINT(p, KTR_SYSRET))
414 		ktrsysret(p->p_tracep, frame->code, err, rval[0]);
415 #endif
416 }
417 
418 void
419 stray(scb, vec)
420 	int scb, vec;
421 {
422 	printf("stray interrupt scb %d, vec 0x%x\n", scb, vec);
423 }
424