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