xref: /netbsd-src/sys/arch/vax/vax/trap.c (revision f5d3fbbc6ff4a77159fb268d247bd94cb7d7e332)
1 /*      $NetBSD: trap.c,v 1.30 1997/10/19 12:32:52 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 
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 
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 extern 	int want_resched,whichqs;
65 #ifdef TRAPDEBUG
66 volatile int startsysc=0,faultdebug=0;
67 #endif
68 
69 static	void userret __P((struct proc *, u_int, u_int));
70 void	arithflt __P((struct trapframe *));
71 void	syscall __P((struct trapframe *));
72 void	showregs __P((struct trapframe *));
73 void	stray __P((int, int));
74 
75 void
76 userret(p, pc, psl)
77 	struct proc *p;
78 	u_int pc, psl;
79 {
80 	int s,sig;
81 
82         while ((sig = CURSIG(p)) !=0)
83                 postsig(sig);
84         p->p_priority = p->p_usrpri;
85         if (want_resched) {
86                 /*
87                  * Since we are curproc, clock will normally just change
88                  * our priority without moving us from one queue to another
89                  * (since the running process is not on a queue.)
90                  * If that happened after we setrunqueue ourselves but before
91 		 * we swtch()'ed, we might not be on the queue indicated by
92                  * our priority.
93                  */
94                 s=splstatclock();
95                 setrunqueue(curproc);
96                 mi_switch();
97                 splx(s);
98                 while ((sig = CURSIG(curproc)) != 0)
99                         postsig(sig);
100         }
101 
102         curpriority = curproc->p_priority;
103 }
104 
105 char *traptypes[]={
106 	"reserved addressing",
107 	"privileged instruction",
108 	"reserved operand",
109 	"breakpoint instruction",
110 	"XFC instruction",
111 	"system call ",
112 	"arithmetic trap",
113 	"asynchronous system trap",
114 	"page table length fault",
115 	"translation violation fault",
116 	"trace trap",
117 	"compatibility mode fault",
118 	"access violation fault",
119 	"",
120 	"",
121 	"KSP invalid",
122 	"",
123 	"kernel debugger trap"
124 };
125 int no_traps = 18;
126 
127 #define USERMODE(framep)   ((((framep)->psl) & (PSL_U)) == PSL_U)
128 #define FAULTCHK                                                \
129         if (p->p_addr->u_pcb.iftrap) {                          \
130                 frame->pc = (unsigned)p->p_addr->u_pcb.iftrap;  \
131                 return;                                         \
132         }
133 
134 void
135 arithflt(frame)
136 	struct trapframe *frame;
137 {
138 	u_int	sig, type=frame->trap,trapsig=1,s;
139 	u_int	rv, addr, umode;
140 	struct	proc *p=curproc;
141 	struct	pmap *pm;
142 	vm_map_t map;
143 	vm_prot_t ftype;
144 	extern vm_map_t	pte_map;
145 
146 	if ((umode = USERMODE(frame))) {
147 		type |= T_USER;
148 		p->p_addr->u_pcb.framep = frame;
149 	}
150 
151 	type&=~(T_WRITE|T_PTEFETCH);
152 
153 
154 #ifdef TRAPDEBUG
155 if(frame->trap==7) goto fram;
156 if(faultdebug)printf("Trap: type %x, code %x, pc %x, psl %x\n",
157 		frame->trap, frame->code, frame->pc, frame->psl);
158 fram:
159 #endif
160 	switch(type){
161 
162 	default:
163 faulter:
164 #ifdef DDB
165 		kdb_trap(frame);
166 #endif
167 		printf("Trap: type %x, code %x, pc %x, psl %x\n",
168 		    frame->trap, frame->code, frame->pc, frame->psl);
169 		showregs(frame);
170 		panic("trap: adr %x",frame->code);
171 	case T_KSPNOTVAL:
172 		goto faulter;
173 
174 	case T_TRANSFLT|T_USER:
175 	case T_TRANSFLT: /* Translation invalid - may be simul page ref */
176 		if(frame->trap&T_PTEFETCH){
177 			u_int	*ptep, *pte, *pte1;
178 
179 			if(frame->code<0x40000000)
180 				ptep=(u_int *)p->p_addr->u_pcb.P0BR;
181 			else
182 				ptep=(u_int *)p->p_addr->u_pcb.P1BR;
183 			pte1=(u_int *)trunc_page(&ptep[(frame->code
184 				&0x3fffffff)>>PGSHIFT]);
185 			pte=(u_int*)&Sysmap[((u_int)pte1&0x3fffffff)>>PGSHIFT];
186 			if(*pte&PG_SREF){ /* Yes, simulated */
187 				s=splhigh();
188 
189 				*pte|=PG_REF|PG_V;*pte&=~PG_SREF;pte++;
190 				*pte|=PG_REF|PG_V;*pte&=~PG_SREF;
191 				mtpr(0,PR_TBIA);
192 				splx(s);
193 				goto uret;
194 			}
195 		} else {
196 			u_int   *ptep, *pte;
197 
198 			frame->code = trunc_page(frame->code);
199 			if ((u_int)frame->code < (u_int)0x40000000) {
200 				ptep = (u_int *)p->p_addr->u_pcb.P0BR;
201 				pte = &ptep[(frame->code >> PGSHIFT)];
202 			} else if ((u_int)frame->code > (u_int)0x7fffffff) {
203 				pte = (u_int *)&Sysmap[((u_int)frame->code &
204 					0x3fffffff) >> PGSHIFT];
205 			} else {
206 				ptep = (u_int *)p->p_addr->u_pcb.P1BR;
207 				pte = &ptep[(frame->code&0x3fffffff)>>PGSHIFT];
208 			}
209 			if (*pte & PG_SREF) {
210 				s = splhigh();
211 				*pte|=PG_REF|PG_V;*pte&=~PG_SREF;pte++;
212 				*pte|=PG_REF|PG_V;*pte&=~PG_SREF;
213 			/*	mtpr(frame->code,PR_TBIS); */
214 			/*	mtpr(frame->code+NBPG,PR_TBIS); */
215 				mtpr(0,PR_TBIA);
216 				splx(s);
217 				goto uret;
218 			}
219 		}
220 		/* Fall into... */
221 	case T_ACCFLT:
222 	case T_ACCFLT|T_USER:
223 #ifdef TRAPDEBUG
224 if(faultdebug)printf("trap accflt type %x, code %x, pc %x, psl %x\n",
225                         frame->trap, frame->code, frame->pc, frame->psl);
226 #endif
227 		if (!p)
228 			panic("trap: access fault without process");
229 		pm = p->p_vmspace->vm_map.pmap;
230 		if(frame->trap&T_PTEFETCH){
231 			u_int faultaddr,testaddr=(u_int)frame->code&0x3fffffff;
232 			int P0 = 0, P1 = 0, SYS = 0;
233 
234 			if (frame->code == testaddr)
235 				P0++;
236 			else if ((u_int)frame->code > (u_int)0x7fffffff)
237 				SYS++;
238 			else
239 				P1++;
240 
241 			if (P0) {
242 				faultaddr = (u_int)pm->pm_pcb->P0BR +
243 					((testaddr >> PGSHIFT) << 2);
244 			} else if (P1) {
245 				faultaddr= (u_int)pm->pm_pcb->P1BR +
246 					((testaddr >> PGSHIFT) << 2);
247 			} else
248 				panic("pageflt: PTE fault in SPT\n");
249 
250 			faultaddr &= ~PAGE_MASK;
251 			rv = vm_fault(pte_map, faultaddr,
252 				VM_PROT_WRITE|VM_PROT_READ, FALSE);
253 			if (rv != KERN_SUCCESS) {
254 
255 				sig = SIGSEGV;
256 				goto bad;
257 			} else
258 				trapsig = 0;
259 		}
260 		addr=(frame->code& ~PAGE_MASK);
261 		if ((umode == 0) && (frame->code < 0)) {
262 			map=kernel_map;
263 		} else {
264 			map= &p->p_vmspace->vm_map;
265 		}
266 		if(frame->trap&T_WRITE) ftype=VM_PROT_WRITE|VM_PROT_READ;
267 		else ftype = VM_PROT_READ;
268 
269 		rv = vm_fault(map, addr, ftype, FALSE);
270 		if (rv != KERN_SUCCESS) {
271 			if (umode == 0) {
272 				FAULTCHK;
273 				panic("Segv in kernel mode: rv %d\n",rv);
274 			}
275 			sig=SIGSEGV;
276 		} else
277 			trapsig=0;
278 		break;
279 
280 	case T_PTELEN:
281 	case T_PTELEN|T_USER:	/* Page table length exceeded */
282 		pm = p->p_vmspace->vm_map.pmap;
283 #ifdef TRAPDEBUG
284 if(faultdebug)printf("trap ptelen type %x, code %x, pc %x, psl %x\n",
285                         frame->trap, frame->code, frame->pc, frame->psl);
286 #endif
287 		if ((u_int)frame->code < (u_int)0x40000000) { /* P0 */
288 			int i;
289 
290 			if (p->p_vmspace == 0){
291 				printf("no vmspace in fault\n");
292 				goto faulter;
293 			}
294 			i = p->p_vmspace->vm_tsize + p->p_vmspace->vm_dsize;
295 			if (i > (frame->code >> PAGE_SHIFT)){
296 				pmap_expandp0(pm, i << 1);
297 				trapsig = 0;
298 			} else {
299 				FAULTCHK;
300 				sig = SIGSEGV;
301 			}
302 		} else if ((u_int)frame->code > (u_int)0x7fffffff){ /* System, segv */
303 			FAULTCHK;
304 			if (umode == 0)
305 				panic("ptelen");
306 			sig = SIGSEGV;
307 		} else { /* P1 */
308 			int i;
309 
310 			i = (u_int)(p->p_vmspace->vm_maxsaddr);
311 			if (frame->code < i){
312 				FAULTCHK;
313 				sig = SIGSEGV;
314 			} else {
315 				pmap_expandp1(pm);
316 				trapsig = 0;
317 			}
318 		}
319 		break;
320 
321 	case T_BPTFLT|T_USER:
322 	case T_TRCTRAP|T_USER:
323 		sig = SIGTRAP;
324 		frame->psl &= ~PSL_T;
325 		break;
326 
327 	case T_PRIVINFLT|T_USER:
328 	case T_RESADFLT|T_USER:
329 	case T_RESOPFLT|T_USER:
330 		sig=SIGILL;
331 		break;
332 
333 	case T_XFCFLT|T_USER:
334 		sig = SIGEMT;
335 		break;
336 
337 	case T_ARITHFLT|T_USER:
338 		sig=SIGFPE;
339 		break;
340 
341 	case T_ASTFLT|T_USER:
342 		mtpr(AST_NO,PR_ASTLVL);
343 		trapsig=0;
344 		break;
345 
346 #ifdef DDB
347 	case T_KDBTRAP:
348 		kdb_trap(frame);
349 		return;
350 #endif
351 	}
352 bad:
353 	if (trapsig)
354 		trapsignal(curproc, sig, frame->code);
355 uret:
356 	if (umode)
357 		userret(curproc, frame->pc, frame->psl);
358 };
359 
360 void
361 setregs(p, pack, stack)
362         struct proc *p;
363 	struct exec_package *pack;
364         u_long stack;
365 {
366 	struct trapframe *exptr;
367 
368 	exptr = p->p_addr->u_pcb.framep;
369 	exptr->pc = pack->ep_entry + 2;
370 	exptr->sp = stack;
371 }
372 
373 void
374 syscall(frame)
375 	struct	trapframe *frame;
376 {
377 	struct sysent *callp;
378 	int nsys;
379 	int err, rval[2], args[8];
380 	struct trapframe *exptr;
381 	struct proc *p = curproc;
382 
383 #ifdef TRAPDEBUG
384 if(startsysc)printf("trap syscall %s pc %x, psl %x, sp %x, pid %d, frame %x\n",
385                syscallnames[frame->code], frame->pc, frame->psl,frame->sp,
386 		curproc->p_pid,frame);
387 #endif
388 
389 	exptr = p->p_addr->u_pcb.framep = frame;
390 	callp = p->p_emul->e_sysent;
391 	nsys = p->p_emul->e_nsysent;
392 
393 	if(frame->code == SYS___syscall){
394 		int g = *(int *)(frame->ap);
395 
396 		frame->code=*(int *)(frame->ap+4);
397 		frame->ap+=8;
398 		*(int *)(frame->ap)=g-2;
399 	}
400 
401 	if(frame->code<0||frame->code>=nsys)
402 		callp += p->p_emul->e_nosys;
403 	else
404 		callp += frame->code;
405 
406 	rval[0]=0;
407 	rval[1]=frame->r1;
408 	if(callp->sy_narg) {
409 		err = copyin((char*)frame->ap+4, args, callp->sy_argsize);
410 		if (err) {
411 #ifdef KTRACE
412 			if (KTRPOINT(p, KTR_SYSCALL))
413 				ktrsyscall(p->p_tracep, frame->code,
414 				    callp->sy_argsize, args);
415 #endif
416 			goto bad;
417 		}
418 	}
419 #ifdef KTRACE
420 	if (KTRPOINT(p, KTR_SYSCALL))
421 		ktrsyscall(p->p_tracep, frame->code, callp->sy_argsize, args);
422 #endif
423 	err=(*callp->sy_call)(curproc,args,rval);
424 	exptr = curproc->p_addr->u_pcb.framep;
425 
426 #ifdef TRAPDEBUG
427 if(startsysc)
428 	printf("retur %s pc %x, psl %x, sp %x, pid %d, v{rde %d r0 %d, r1 %d, frame %x\n",
429                syscallnames[exptr->code], exptr->pc, exptr->psl,exptr->sp,
430                 curproc->p_pid,err,rval[0],rval[1],exptr);
431 #endif
432 
433 bad:
434 	switch (err) {
435 	case 0:
436 		exptr->r1 = rval[1];
437 		exptr->r0 = rval[0];
438 		exptr->psl &= ~PSL_C;
439 		break;
440 
441 	case EJUSTRETURN:
442 		return;
443 
444 	case ERESTART:
445 		exptr->pc -= (exptr->code > 63 ? 4 : 2);
446 		break;
447 
448 	default:
449 		exptr->r0 = err;
450 		exptr->psl |= PSL_C;
451 		break;
452 	}
453 	userret(curproc, exptr->pc, exptr->psl);
454 #ifdef KTRACE
455 	if (KTRPOINT(p, KTR_SYSRET))
456 		ktrsysret(p->p_tracep, frame->code, err, rval[0]);
457 #endif
458 }
459 
460 void
461 stray(scb, vec)
462 	int scb, vec;
463 {
464 	printf("stray interrupt scb %d, vec 0x%x\n", scb, vec);
465 }
466 
467 void
468 showregs(frame)
469 	struct trapframe *frame;
470 {
471 	printf("P0BR %8x   P1BR %8x   P0LR %8x   P1LR %8x\n",
472 	    mfpr(PR_P0BR), mfpr(PR_P1BR), mfpr(PR_P0LR), mfpr(PR_P1LR));
473 	printf("KSP  %8x   ISP  %8x   USP  %8x\n",
474 	    mfpr(PR_KSP), mfpr(PR_ISP), mfpr(PR_USP));
475 	printf("R0   %8x   R1   %8x   R2   %8x   R3   %8x\n",
476 	    frame->r0, frame->r1, frame->r2, frame->r3);
477 	printf("R4   %8x   R5   %8x   R6   %8x   R7   %8x\n",
478 	    frame->r4, frame->r5, frame->r6, frame->r7);
479 	printf("R8   %8x   R9   %8x   R10  %8x   R11  %8x\n",
480 	    frame->r8, frame->r9, frame->r10, frame->r11);
481 	printf("FP   %8x   AP   %8x   PC   %8x   PSL  %8x\n",
482 	    frame->fp, frame->ap, frame->pc, frame->psl);
483 }
484