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