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