xref: /original-bsd/sys/luna68k/luna68k/trap.c (revision 4a884f8b)
1 /*
2  * Copyright (c) 1988 University of Utah.
3  * Copyright (c) 1992 OMRON Corporation.
4  * Copyright (c) 1982, 1986, 1990 The Regents of the University of California.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * the Systems Programming Group of the University of Utah Computer
9  * Science Department.
10  *
11  * %sccs.include.redist.c%
12  *
13  * from: Utah $Hdr: trap.c 1.35 91/12/26$
14  * from: hp300/hp300/trap.c	7.26 (Berkeley) 12/27/92
15  *
16  *	@(#)trap.c	7.4 (Berkeley) 01/02/93
17  */
18 
19 #include <sys/param.h>
20 #include <sys/systm.h>
21 #include <sys/proc.h>
22 #include <sys/acct.h>
23 #include <sys/kernel.h>
24 #include <sys/signalvar.h>
25 #include <sys/resourcevar.h>
26 #include <sys/syscall.h>
27 #include <sys/syslog.h>
28 #include <sys/user.h>
29 #ifdef KTRACE
30 #include <sys/ktrace.h>
31 #endif
32 
33 #include <machine/psl.h>
34 #include <machine/trap.h>
35 #include <machine/cpu.h>
36 #include <machine/reg.h>
37 #include <machine/mtpr.h>
38 
39 #include <vm/vm.h>
40 #include <vm/pmap.h>
41 
42 struct	sysent	sysent[];
43 int	nsysent;
44 
45 char	*trap_type[] = {
46 	"Bus error",
47 	"Address error",
48 	"Illegal instruction",
49 	"Zero divide",
50 	"CHK instruction",
51 	"TRAPV instruction",
52 	"Privilege violation",
53 	"Trace trap",
54 	"MMU fault",
55 	"SSIR trap",
56 	"Format error",
57 	"68881 exception",
58 	"Coprocessor violation",
59 	"Async system trap"
60 };
61 #define	TRAP_TYPES	(sizeof trap_type / sizeof trap_type[0])
62 
63 /*
64  * Size of various exception stack frames (minus the standard 8 bytes)
65  */
66 short	exframesize[] = {
67 	FMT0SIZE,	/* type 0 - normal (68020/030/040) */
68 	FMT1SIZE,	/* type 1 - throwaway (68020/030/040) */
69 	FMT2SIZE,	/* type 2 - normal 6-word (68020/030/040) */
70 	FMT3SIZE,	/* type 3 - FP post-instruction (68040) */
71 	-1, -1, -1,	/* type 4-6 - undefined */
72 	FMT7SIZE,	/* type 7 - access error (68040) */
73 	58,		/* type 8 - bus fault (68010) */
74 	FMT9SIZE,	/* type 9 - coprocessor mid-instruction (68020/030) */
75 	FMTASIZE,	/* type A - short bus fault (68020/030) */
76 	FMTBSIZE,	/* type B - long bus fault (68020/030) */
77 	-1, -1, -1, -1	/* type C-F - undefined */
78 };
79 
80 #define KDFAULT(c)	(((c) & (SSW_DF|SSW_FCMASK)) == (SSW_DF|FC_SUPERD))
81 #define WRFAULT(c)	(((c) & (SSW_DF|SSW_RW)) == SSW_DF)
82 
83 #ifdef DEBUG
84 int mmudebug = 0;
85 int mmupid = -1;
86 #define MDB_FOLLOW	1
87 #define MDB_WBFOLLOW	2
88 #define MDB_WBFAILED	4
89 #define MDB_ISPID(p)	(p) == mmupid
90 #endif
91 
92 /*
93  * trap and syscall both need the following work done before returning
94  * to user mode.
95  */
96 static inline void
97 userret(p, fp, oticks, faultaddr, fromtrap)
98 	register struct proc *p;
99 	register struct frame *fp;
100 	u_quad_t oticks;
101 	u_int faultaddr;
102 	int fromtrap;
103 {
104 	int sig, s;
105 
106 	/* take pending signals */
107 	while ((sig = CURSIG(p)) != 0)
108 		psig(sig);
109 	p->p_pri = p->p_usrpri;
110 	if (want_resched) {
111 		/*
112 		 * Since we are curproc, clock will normally just change
113 		 * our priority without moving us from one queue to another
114 		 * (since the running process is not on a queue.)
115 		 * If that happened after we setrq ourselves but before we
116 		 * swtch()'ed, we might not be on the queue indicated by
117 		 * our priority.
118 		 */
119 		s = splstatclock();
120 		setrq(p);
121 		p->p_stats->p_ru.ru_nivcsw++;
122 		swtch();
123 		splx(s);
124 		while ((sig = CURSIG(p)) != 0)
125 			psig(sig);
126 	}
127 
128 	/*
129 	 * If profiling, charge system time to the trapped pc.
130 	 */
131 	if (p->p_flag & SPROFIL) {
132 		extern int psratio;
133 
134 		addupc_task(p, fp->f_pc,
135 			    (int)(p->p_sticks - oticks) * psratio);
136 	}
137 	curpri = p->p_pri;
138 }
139 
140 /*
141  * Trap is called from locore to handle most types of processor traps,
142  * including events such as simulated software interrupts/AST's.
143  * System calls are broken out for efficiency.
144  */
145 /*ARGSUSED*/
146 trap(type, code, v, frame)
147 	int type;
148 	unsigned code;
149 	register unsigned v;
150 	struct frame frame;
151 {
152 	register int i;
153 	unsigned ucode;
154 	register struct proc *p;
155 	u_quad_t sticks;
156 	unsigned ncode;
157 	extern char fswintr[];
158 
159 	cnt.v_trap++;
160 	p = curproc;
161 	ucode = 0;
162 	if (USERMODE(frame.f_sr)) {
163 		type |= T_USER;
164 		sticks = p->p_sticks;
165 		p->p_md.md_regs = frame.f_regs;
166 	}
167 	switch (type) {
168 
169 	default:
170 dopanic:
171 		printf("trap type %d, code = %x, v = %x\n", type, code, v);
172 		regdump(&frame, 128);
173 		type &= ~T_USER;
174 		if ((unsigned)type < TRAP_TYPES)
175 			panic(trap_type[type]);
176 		panic("trap");
177 
178 	case T_BUSERR:		/* kernel bus error */
179 		if (!p->p_addr->u_pcb.pcb_onfault)
180 			goto dopanic;
181 		/*
182 		 * If we have arranged to catch this fault in any of the
183 		 * copy to/from user space routines, set PC to return to
184 		 * indicated location and set flag informing buserror code
185 		 * that it may need to clean up stack frame.
186 		 */
187 copyfault:
188 		frame.f_stackadj = exframesize[frame.f_format];
189 		frame.f_format = frame.f_vector = 0;
190 		frame.f_pc = (int) p->p_addr->u_pcb.pcb_onfault;
191 		return;
192 
193 	case T_BUSERR|T_USER:	/* bus error */
194 	case T_ADDRERR|T_USER:	/* address error */
195 		ucode = v;
196 		i = SIGBUS;
197 		break;
198 
199 #ifdef FPCOPROC
200 	case T_COPERR:		/* kernel coprocessor violation */
201 #endif
202 	case T_FMTERR|T_USER:	/* do all RTE errors come in as T_USER? */
203 	case T_FMTERR:		/* ...just in case... */
204 	/*
205 	 * The user has most likely trashed the RTE or FP state info
206 	 * in the stack frame of a signal handler.
207 	 */
208 		type |= T_USER;
209 		printf("pid %d: kernel %s exception\n", p->p_pid,
210 		       type==T_COPERR ? "coprocessor" : "format");
211 		p->p_sigacts->ps_sigact[SIGILL] = SIG_DFL;
212 		i = sigmask(SIGILL);
213 		p->p_sigignore &= ~i;
214 		p->p_sigcatch &= ~i;
215 		p->p_sigmask &= ~i;
216 		i = SIGILL;
217 		ucode = frame.f_format;	/* XXX was ILL_RESAD_FAULT */
218 		break;
219 
220 #ifdef FPCOPROC
221 	case T_COPERR|T_USER:	/* user coprocessor violation */
222 	/* What is a proper response here? */
223 		ucode = 0;
224 		i = SIGFPE;
225 		break;
226 
227 	case T_FPERR|T_USER:	/* 68881 exceptions */
228 	/*
229 	 * We pass along the 68881 status register which locore stashed
230 	 * in code for us.  Note that there is a possibility that the
231 	 * bit pattern of this register will conflict with one of the
232 	 * FPE_* codes defined in signal.h.  Fortunately for us, the
233 	 * only such codes we use are all in the range 1-7 and the low
234 	 * 3 bits of the status register are defined as 0 so there is
235 	 * no clash.
236 	 */
237 		ucode = code;
238 		i = SIGFPE;
239 		break;
240 #endif
241 
242 	case T_ILLINST|T_USER:	/* illegal instruction fault */
243 	case T_PRIVINST|T_USER:	/* privileged instruction fault */
244 		ucode = frame.f_format;	/* XXX was ILL_PRIVIN_FAULT */
245 		i = SIGILL;
246 		break;
247 
248 	case T_ZERODIV|T_USER:	/* Divide by zero */
249 		ucode = frame.f_format;	/* XXX was FPE_INTDIV_TRAP */
250 		i = SIGFPE;
251 		break;
252 
253 	case T_CHKINST|T_USER:	/* CHK instruction trap */
254 		ucode = frame.f_format;	/* XXX was FPE_SUBRNG_TRAP */
255 		i = SIGFPE;
256 		break;
257 
258 	case T_TRAPVINST|T_USER:	/* TRAPV instruction trap */
259 		ucode = frame.f_format;	/* XXX was FPE_INTOVF_TRAP */
260 		i = SIGFPE;
261 		break;
262 
263 	/*
264 	 * XXX: Trace traps are a nightmare.
265 	 *
266 	 *	HP-UX uses trap #1 for breakpoints,
267 	 *	HPBSD uses trap #2,
268 	 *	SUN 3.x uses trap #15,
269 	 *	KGDB uses trap #15 (for kernel breakpoints; handled elsewhere).
270 	 *
271 	 * HPBSD and HP-UX traps both get mapped by locore.s into T_TRACE.
272 	 * SUN 3.x traps get passed through as T_TRAP15 and are not really
273 	 * supported yet.
274 	 */
275 	case T_TRACE:		/* kernel trace trap */
276 	case T_TRAP15:		/* SUN trace trap */
277 		frame.f_sr &= ~PSL_T;
278 		i = SIGTRAP;
279 		break;
280 
281 	case T_TRACE|T_USER:	/* user trace trap */
282 	case T_TRAP15|T_USER:	/* SUN user trace trap */
283 		frame.f_sr &= ~PSL_T;
284 		i = SIGTRAP;
285 		break;
286 
287 	case T_ASTFLT:		/* system async trap, cannot happen */
288 		goto dopanic;
289 
290 	case T_ASTFLT|T_USER:	/* user async trap */
291 		astpending = 0;
292 		/*
293 		 * We check for software interrupts first.  This is because
294 		 * they are at a higher level than ASTs, and on a VAX would
295 		 * interrupt the AST.  We assume that if we are processing
296 		 * an AST that we must be at IPL0 so we don't bother to
297 		 * check.  Note that we ensure that we are at least at SIR
298 		 * IPL while processing the SIR.
299 		 */
300 		spl1();
301 		/* fall into... */
302 
303 	case T_SSIR:		/* software interrupt */
304 	case T_SSIR|T_USER:
305 		if (ssir & SIR_NET) {
306 			siroff(SIR_NET);
307 			cnt.v_soft++;
308 			netintr();
309 		}
310 		if (ssir & SIR_CLOCK) {
311 			siroff(SIR_CLOCK);
312 			cnt.v_soft++;
313 			softclock();
314 		}
315 		/*
316 		 * If this was not an AST trap, we are all done.
317 		 */
318 		if (type != (T_ASTFLT|T_USER)) {
319 			cnt.v_trap--;
320 			return;
321 		}
322 		spl0();
323 		if (p->p_flag & SOWEUPC) {
324 			p->p_flag &= ~SOWEUPC;
325 			ADDUPROF(p);
326 		}
327 		goto out;
328 
329 	case T_MMUFLT:		/* kernel mode page fault */
330 		/*
331 		 * If we were doing profiling ticks or other user mode
332 		 * stuff from interrupt code, Just Say No.
333 		 */
334 		if (p->p_addr->u_pcb.pcb_onfault == fswintr)
335 			goto copyfault;
336 		/* fall into ... */
337 
338 	case T_MMUFLT|T_USER:	/* page fault */
339 	    {
340 		register vm_offset_t va;
341 		register struct vmspace *vm = p->p_vmspace;
342 		register vm_map_t map;
343 		int rv;
344 		vm_prot_t ftype;
345 		extern vm_map_t kernel_map;
346 
347 #ifdef DEBUG
348 		if ((mmudebug & MDB_WBFOLLOW) || MDB_ISPID(p->p_pid))
349 		printf("trap: T_MMUFLT pid=%d, code=%x, v=%x, pc=%x, sr=%x\n",
350 		       p->p_pid, code, v, frame.f_pc, frame.f_sr);
351 #endif
352 		/*
353 		 * It is only a kernel address space fault iff:
354 		 * 	1. (type & T_USER) == 0  and
355 		 * 	2. pcb_onfault not set or
356 		 *	3. pcb_onfault set but supervisor space data fault
357 		 * The last can occur during an exec() copyin where the
358 		 * argument space is lazy-allocated.
359 		 */
360 		if (type == T_MMUFLT &&
361 		    (!p->p_addr->u_pcb.pcb_onfault || KDFAULT(code)))
362 			map = kernel_map;
363 		else
364 			map = &vm->vm_map;
365 		if (WRFAULT(code))
366 			ftype = VM_PROT_READ | VM_PROT_WRITE;
367 		else
368 			ftype = VM_PROT_READ;
369 		va = trunc_page((vm_offset_t)v);
370 #ifdef DEBUG
371 		if (map == kernel_map && va == 0) {
372 			printf("trap: bad kernel access at %x\n", v);
373 			goto dopanic;
374 		}
375 #endif
376 		rv = vm_fault(map, va, ftype, FALSE);
377 #ifdef DEBUG
378 		if (rv && MDB_ISPID(p->p_pid))
379 			printf("vm_fault(%x, %x, %x, 0) -> %x\n",
380 			       map, va, ftype, rv);
381 #endif
382 		/*
383 		 * If this was a stack access we keep track of the maximum
384 		 * accessed stack size.  Also, if vm_fault gets a protection
385 		 * failure it is due to accessing the stack region outside
386 		 * the current limit and we need to reflect that as an access
387 		 * error.
388 		 */
389 		if ((caddr_t)va >= vm->vm_maxsaddr && map != kernel_map) {
390 			if (rv == KERN_SUCCESS) {
391 				unsigned nss;
392 
393 				nss = clrnd(btoc(USRSTACK-(unsigned)va));
394 				if (nss > vm->vm_ssize)
395 					vm->vm_ssize = nss;
396 			} else if (rv == KERN_PROTECTION_FAILURE)
397 				rv = KERN_INVALID_ADDRESS;
398 		}
399 		if (rv == KERN_SUCCESS) {
400 			if (type == T_MMUFLT) {
401 				return;
402 			}
403 			goto out;
404 		}
405 		if (type == T_MMUFLT) {
406 			if (p->p_addr->u_pcb.pcb_onfault)
407 				goto copyfault;
408 			printf("vm_fault(%x, %x, %x, 0) -> %x\n",
409 			       map, va, ftype, rv);
410 			printf("  type %x, code [mmu,,ssw]: %x\n",
411 			       type, code);
412 			goto dopanic;
413 		}
414 		ucode = v;
415 		i = (rv == KERN_PROTECTION_FAILURE) ? SIGBUS : SIGSEGV;
416 		break;
417 	    }
418 	}
419 	trapsignal(p, i, ucode);
420 	if ((type & T_USER) == 0)
421 		return;
422 out:
423 	userret(p, &frame, sticks, v, 1);
424 }
425 
426 /*
427  * Proces a system call.
428  */
429 syscall(code, frame)
430 	u_int code;
431 	struct frame frame;
432 {
433 	register caddr_t params;
434 	register struct sysent *callp;
435 	register struct proc *p;
436 	int error, opc, numsys, s;
437 	u_int argsize;
438 	struct args {
439 		int i[8];
440 	} args;
441 	int rval[2];
442 	u_quad_t sticks;
443 
444 	cnt.v_syscall++;
445 	if (!USERMODE(frame.f_sr))
446 		panic("syscall");
447 	p = curproc;
448 	sticks = p->p_sticks;
449 	p->p_md.md_regs = frame.f_regs;
450 	opc = frame.f_pc - 2;
451 	callp = sysent, numsys = nsysent;
452 	params = (caddr_t)frame.f_regs[SP] + sizeof(int);
453 	switch (code) {
454 
455 	case SYS_indir:
456 		/*
457 		 * Code is first argument, followed by actual args.
458 		 */
459 		code = fuword(params);
460 		params += sizeof(int);
461 		/*
462 		 * XXX sigreturn requires special stack manipulation
463 		 * that is only done if entered via the sigreturn
464 		 * trap.  Cannot allow it here so make sure we fail.
465 		 */
466 		if (code == SYS_sigreturn)
467 			code = numsys;
468 		break;
469 
470 	case SYS___indir:
471 		/*
472 		 * Like indir, but code is a quad, so as to maintain
473 		 * quad alignment for the rest of the arguments.
474 		 */
475 		code = fuword(params + _QUAD_LOWWORD * sizeof(int));
476 		params += sizeof(quad_t);
477 		break;
478 
479 	default:
480 		/* nothing to do by default */
481 		break;
482 	}
483 	if (code < numsys)
484 		callp += code;
485 	else
486 		callp += SYS_indir;	/* => nosys */
487 	argsize = callp->sy_narg * sizeof(int);
488 	if (argsize && (error = copyin(params, (caddr_t)&args, argsize))) {
489 #ifdef KTRACE
490 		if (KTRPOINT(p, KTR_SYSCALL))
491 			ktrsyscall(p->p_tracep, code, callp->sy_narg, args.i);
492 #endif
493 		goto bad;
494 	}
495 #ifdef KTRACE
496 	if (KTRPOINT(p, KTR_SYSCALL))
497 		ktrsyscall(p->p_tracep, code, callp->sy_narg, args.i);
498 #endif
499 	rval[0] = 0;
500 	rval[1] = frame.f_regs[D1];
501 	error = (*callp->sy_call)(p, &args, rval);
502 	switch (error) {
503 
504 	case 0:
505 		/*
506 		 * Reinitialize proc pointer `p' as it may be different
507 		 * if this is a child returning from fork syscall.
508 		 */
509 		p = curproc;
510 		frame.f_regs[D0] = rval[0];
511 		frame.f_regs[D1] = rval[1];
512 		frame.f_sr &= ~PSL_C;
513 		break;
514 
515 	case ERESTART:
516 		frame.f_pc = opc;
517 		break;
518 
519 	case EJUSTRETURN:
520 		break;		/* nothing to do */
521 
522 	default:
523 	bad:
524 		frame.f_regs[D0] = error;
525 		frame.f_sr |= PSL_C;
526 		break;
527 	}
528 
529 	userret(p, &frame, sticks, (u_int)0, 0);
530 #ifdef KTRACE
531 	if (KTRPOINT(p, KTR_SYSRET))
532 		ktrsysret(p->p_tracep, code, error, rval[0]);
533 #endif
534 }
535