xref: /original-bsd/sys/hp300/hp300/trap.c (revision 1edfe155)
1 /*
2  * Copyright (c) 1988 University of Utah.
3  * Copyright (c) 1982, 1986, 1990 The Regents of the University of California.
4  * All rights reserved.
5  *
6  * This code is derived from software contributed to Berkeley by
7  * the Systems Programming Group of the University of Utah Computer
8  * Science Department.
9  *
10  * %sccs.include.redist.c%
11  *
12  * from: Utah $Hdr: trap.c 1.28 89/09/25$
13  *
14  *	@(#)trap.c	7.6 (Berkeley) 06/24/90
15  */
16 
17 #include "cpu.h"
18 #include "psl.h"
19 #include "reg.h"
20 #include "pte.h"
21 #include "mtpr.h"
22 
23 #include "param.h"
24 #include "systm.h"
25 #include "user.h"
26 #include "proc.h"
27 #include "seg.h"
28 #include "trap.h"
29 #include "acct.h"
30 #include "kernel.h"
31 #include "vm.h"
32 #include "cmap.h"
33 #include "syslog.h"
34 #ifdef KTRACE
35 #include "ktrace.h"
36 #endif
37 
38 #ifdef HPUXCOMPAT
39 #include "../hpux/hpux.h"
40 #endif
41 
42 #define	USER	040		/* user-mode flag added to type */
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 #ifdef DEBUG
66 int mmudebug = 0;
67 #endif
68 
69 /*
70  * Called from the trap handler when a processor trap occurs.
71  */
72 /*ARGSUSED*/
73 trap(type, code, v, frame)
74 	int type;
75 	unsigned code;
76 	register unsigned v;
77 	struct frame frame;
78 {
79 	register int i;
80 	unsigned ucode = 0;
81 	register struct proc *p = u.u_procp;
82 	struct timeval syst;
83 	unsigned ncode;
84 
85 	cnt.v_trap++;
86 	syst = u.u_ru.ru_stime;
87 	if (USERMODE(frame.f_sr)) {
88 		type |= USER;
89 		u.u_ar0 = frame.f_regs;
90 	}
91 	switch (type) {
92 
93 	default:
94 dopanic:
95 #ifdef KGDB
96 		if (!panicstr && kgdb_trap(type, code, v, &frame))
97 			return;
98 #endif
99 		printf("trap type %d, code = %x, v = %x\n", type, code, v);
100 		regdump(frame.f_regs, 128);
101 		type &= ~USER;
102 		if ((unsigned)type < TRAP_TYPES)
103 			panic(trap_type[type]);
104 		panic("trap");
105 
106 	case T_BUSERR:		/* kernel bus error */
107 		if (!u.u_pcb.pcb_onfault)
108 			goto dopanic;
109 		/*
110 		 * If we have arranged to catch this fault in any of the
111 		 * copy to/from user space routines, set PC to return to
112 		 * indicated location and set flag informing buserror code
113 		 * that it may need to clean up stack frame.
114 		 */
115 copyfault:
116 		frame.f_pc = (int) u.u_pcb.pcb_onfault;
117 		frame.f_stackadj = -1;
118 		return;
119 
120 	case T_BUSERR+USER:	/* bus error */
121 	case T_ADDRERR+USER:	/* address error */
122 		i = SIGBUS;
123 		break;
124 
125 #ifdef FPCOPROC
126 	case T_COPERR:		/* kernel coprocessor violation */
127 #endif
128 	case T_FMTERR:		/* kernel format error */
129 	/*
130 	 * The user has most likely trashed the RTE or FP state info
131 	 * in the stack frame of a signal handler.
132 	 */
133 		type |= USER;
134 		printf("pid %d: kernel %s exception\n", u.u_procp->p_pid,
135 		       type==T_COPERR ? "coprocessor" : "format");
136 		u.u_signal[SIGILL] = SIG_DFL;
137 		i = sigmask(SIGILL);
138 		p->p_sigignore &= ~i;
139 		p->p_sigcatch &= ~i;
140 		p->p_sigmask &= ~i;
141 		i = SIGILL;
142 		ucode = frame.f_format;	/* XXX was ILL_RESAD_FAULT */
143 		break;
144 
145 #ifdef FPCOPROC
146 	case T_COPERR+USER:	/* user coprocessor violation */
147 	/* What is a proper response here? */
148 		ucode = 0;
149 		i = SIGFPE;
150 		break;
151 
152 	case T_FPERR+USER:		/* 68881 exceptions */
153 	/*
154 	 * We pass along the 68881 status register which locore stashed
155 	 * in code for us.  Note that there is a possibility that the
156 	 * bit pattern of this register will conflict with one of the
157 	 * FPE_* codes defined in signal.h.  Fortunately for us, the
158 	 * only such codes we use are all in the range 1-7 and the low
159 	 * 3 bits of the status register are defined as 0 so there is
160 	 * no clash.
161 	 */
162 		ucode = code;
163 		i = SIGFPE;
164 		break;
165 #endif
166 
167 	case T_ILLINST+USER:	/* illegal instruction fault */
168 #ifdef HPUXCOMPAT
169 		if (u.u_procp->p_flag & SHPUX) {
170 			ucode = HPUX_ILL_ILLINST_TRAP;
171 			i = SIGILL;
172 			break;
173 		}
174 		/* fall through */
175 #endif
176 	case T_PRIVINST+USER:	/* privileged instruction fault */
177 #ifdef HPUXCOMPAT
178 		if (u.u_procp->p_flag & SHPUX)
179 			ucode = HPUX_ILL_PRIV_TRAP;
180 		else
181 #endif
182 		ucode = frame.f_format;	/* XXX was ILL_PRIVIN_FAULT */
183 		i = SIGILL;
184 		break;
185 
186 	case T_ZERODIV+USER:	/* Divide by zero */
187 #ifdef HPUXCOMPAT
188 		if (u.u_procp->p_flag & SHPUX)
189 			ucode = HPUX_FPE_INTDIV_TRAP;
190 		else
191 #endif
192 		ucode = frame.f_format;	/* XXX was FPE_INTDIV_TRAP */
193 		i = SIGFPE;
194 		break;
195 
196 	case T_CHKINST+USER:	/* CHK instruction trap */
197 #ifdef HPUXCOMPAT
198 		if (u.u_procp->p_flag & SHPUX) {
199 			/* handled differently under hp-ux */
200 			i = SIGILL;
201 			ucode = HPUX_ILL_CHK_TRAP;
202 			break;
203 		}
204 #endif
205 		ucode = frame.f_format;	/* XXX was FPE_SUBRNG_TRAP */
206 		i = SIGFPE;
207 		break;
208 
209 	case T_TRAPVINST+USER:	/* TRAPV instruction trap */
210 #ifdef HPUXCOMPAT
211 		if (u.u_procp->p_flag & SHPUX) {
212 			/* handled differently under hp-ux */
213 			i = SIGILL;
214 			ucode = HPUX_ILL_TRAPV_TRAP;
215 			break;
216 		}
217 #endif
218 		ucode = frame.f_format;	/* XXX was FPE_INTOVF_TRAP */
219 		i = SIGFPE;
220 		break;
221 
222 	/*
223 	 * XXX: Trace traps are a nightmare.
224 	 *
225 	 *	HP-UX uses trap #1 for breakpoints,
226 	 *	HPBSD uses trap #2,
227 	 *	SUN 3.x uses trap #15,
228 	 *	KGDB uses trap #15 (for kernel breakpoints).
229 	 *
230 	 * HPBSD and HP-UX traps both get mapped by locore.s into T_TRACE.
231 	 * SUN 3.x traps get passed through as T_TRAP15 and are not really
232 	 * supported yet.  KGDB traps are also passed through as T_TRAP15
233 	 * and are not used yet.
234 	 */
235 	case T_TRACE:		/* kernel trace trap */
236 	case T_TRAP15:		/* SUN (or KGDB) kernel trace trap */
237 #ifdef KGDB
238 		if (kgdb_trap(type, code, v, &frame))
239 			return;
240 #endif
241 		frame.f_sr &= ~PSL_T;
242 		i = SIGTRAP;
243 		break;
244 
245 	case T_TRACE+USER:	/* user trace trap */
246 	case T_TRAP15+USER:	/* SUN user trace trap */
247 		frame.f_sr &= ~PSL_T;
248 		i = SIGTRAP;
249 		break;
250 
251 	case T_ASTFLT:		/* system async trap, cannot happen */
252 		goto dopanic;
253 
254 	case T_ASTFLT+USER:	/* user async trap */
255 		astoff();
256 		/*
257 		 * We check for software interrupts first.  This is because
258 		 * they are at a higher level than ASTs, and on a VAX would
259 		 * interrupt the AST.  We assume that if we are processing
260 		 * an AST that we must be at IPL0 so we don't bother to
261 		 * check.  Note that we ensure that we are at least at SIR
262 		 * IPL while processing the SIR.
263 		 */
264 		spl1();
265 		/* fall into... */
266 
267 	case T_SSIR:		/* software interrupt */
268 	case T_SSIR+USER:
269 		if (ssir & SIR_NET) {
270 			siroff(SIR_NET);
271 			cnt.v_soft++;
272 			netintr();
273 		}
274 		if (ssir & SIR_CLOCK) {
275 			siroff(SIR_CLOCK);
276 			cnt.v_soft++;
277 			softclock((caddr_t)frame.f_pc, (int)frame.f_sr);
278 		}
279 		/*
280 		 * If this was not an AST trap, we are all done.
281 		 */
282 		if (type != T_ASTFLT+USER) {
283 			cnt.v_trap--;
284 			return;
285 		}
286 		spl0();
287 #ifndef PROFTIMER
288 		if ((u.u_procp->p_flag&SOWEUPC) && u.u_prof.pr_scale) {
289 			addupc(frame.f_pc, &u.u_prof, 1);
290 			u.u_procp->p_flag &= ~SOWEUPC;
291 		}
292 #endif
293 		goto out;
294 
295 	case T_MMUFLT:		/* kernel mode page fault */
296 		/*
297 		 * Could be caused by a page fault in one of the copy to/from
298 		 * user space routines.  If so, we will have a catch address.
299 		 */
300 		if (!u.u_pcb.pcb_onfault)
301 			goto dopanic;
302 		/* fall into ... */
303 
304 	case T_MMUFLT+USER:	/* page fault */
305 /*
306 		printf("trap: T_MMUFLT pid %d, code %x, v %x, pc %x, ps %x\n",
307 		       p->p_pid, code, v, frame.f_pc, frame.f_sr);
308 */
309 		if (v >= USRSTACK) {
310 			if (type == T_MMUFLT)
311 				goto copyfault;
312 			i = SIGSEGV;
313 			break;
314 		}
315 		ncode = code >> 16;
316 #if defined(HP330) || defined(HP360) || defined(HP370)
317 		/*
318 		 * Crudely map PMMU faults into HP MMU faults.
319 		 */
320 		if (mmutype != MMU_HP) {
321 			int ocode = ncode;
322 			ncode = 0;
323 			if (ocode & PMMU_WP)
324 				ncode |= MMU_WPF;
325 			else if (ocode & PMMU_INV) {
326 				if ((ocode & PMMU_LVLMASK) == 2)
327 					ncode |= MMU_PF;
328 				else
329 					ncode |= MMU_PTF;
330 			}
331 			/*
332 			 * RMW cycle, must load ATC by hand
333 			 */
334 			else if ((code & (SSW_DF|SSW_RM)) == (SSW_DF|SSW_RM)) {
335 #ifdef DEBUG
336 				log(LOG_WARNING,
337 				    "RMW fault at %x: MMUSR %x SSW %x\n",
338 				    v, ocode, code & 0xFFFF);
339 #endif
340 				ploadw((caddr_t)v);
341 				return;
342 			}
343 			/*
344 			 * Fault with no fault bits, should indicate bad
345 			 * hardware but we see this on 340s using starbase
346 			 * sometimes (faults accessing catseye registers)
347 			 */
348 			else {
349 				log(LOG_WARNING,
350 				    "Bad PMMU fault at %x: MMUSR %x SSW %x\n",
351 				    v, ocode, code & 0xFFFF);
352 				return;
353 			}
354 #ifdef DEBUG
355 			if (mmudebug && mmudebug == p->p_pid)
356 				printf("MMU %d: v%x, os%x, ns%x\n",
357 				       p->p_pid, v, ocode, ncode);
358 #endif
359 		}
360 #endif
361 #ifdef DEBUG
362 		if ((ncode & (MMU_PTF|MMU_PF|MMU_WPF|MMU_FPE)) == 0) {
363 			printf("T_MMUFLT with no fault bits\n");
364 			goto dopanic;
365 		}
366 #endif
367 		if (ncode & MMU_PTF) {
368 #ifdef DEBUG
369 			/*
370 			 * NOTE: we use a u_int instead of an ste since the
371 			 * current compiler generates bogus code for some
372 			 * bitfield operations (i.e. attempts to access last
373 			 * word of a page as a longword causing fault).
374 			 */
375 			extern struct ste *vtoste();
376 			u_int *ste = (u_int *)vtoste(p, v);
377 
378 			if (*ste & SG_V) {
379 				if (ncode & MMU_WPF) {
380 					printf("PTF|WPF...\n");
381 					if (type == T_MMUFLT)
382 						goto copyfault;
383 					i = SIGBUS;
384 					break;
385 				}
386 				printf("MMU_PTF with sg_v, ste@%x = %x\n",
387 				       ste, *ste);
388 				goto dopanic;
389 			}
390 #endif
391 #ifdef HPUXCOMPAT
392 			if (ISHPMMADDR(v)) {
393 				extern struct ste *vtoste();
394 				u_int *bste, *nste;
395 
396 				bste = (u_int *)vtoste(p, HPMMBASEADDR(v));
397 				nste = (u_int *)vtoste(p, v);
398 				if ((*bste & SG_V) && *nste == SG_NV) {
399 					*nste = *bste;
400 					TBIAU();
401 					return;
402 				}
403 			}
404 #endif
405 		growit:
406 			if (type == T_MMUFLT)
407 				goto copyfault;
408 			if (grow((unsigned)frame.f_regs[SP]) || grow(v))
409 				goto out;
410 			i = SIGSEGV;
411 			break;
412 		}
413 #ifdef HPUXCOMPAT
414 		if (ISHPMMADDR(v)) {
415 			TBIS(v);
416 			v = HPMMBASEADDR(v);
417 		}
418 #endif
419 		/*
420 		 * NOTE: WPF without PG_V is possible
421 		 * (e.g. attempt to write shared text which is paged out)
422 		 */
423 		if (ncode & MMU_WPF) {
424 #ifdef DEBUG
425 			extern struct ste *vtoste();
426 			u_int *ste = (u_int *)vtoste(p, v);
427 
428 			if (!(*ste & SG_V)) {
429 				printf("MMU_WPF without sg_v, ste@%x = %x\n",
430 				       ste, *ste);
431 				goto dopanic;
432 			}
433 #endif
434 			if (type == T_MMUFLT)
435 				goto copyfault;
436 			i = SIGBUS;
437 			break;
438 		}
439 		if (ncode & MMU_PF) {
440 			register u_int vp;
441 #ifdef DEBUG
442 			extern struct ste *vtoste();
443 			u_int *ste = (u_int *)vtoste(p, v);
444 			struct pte *pte;
445 
446 			if (!(*ste & SG_V)) {
447 				printf("MMU_PF without sg_v, ste@%x = %x\n",
448 				       ste, *ste);
449 				goto dopanic;
450 			}
451 #endif
452 			vp = btop(v);
453 			if (vp >= dptov(p, p->p_dsize) &&
454 			    vp < sptov(p, p->p_ssize-1))
455 				goto growit;
456 #ifdef DEBUG
457 			pte = vtopte(p, vp);
458 			if (*(u_int *)pte & PG_V) {
459 				printf("MMU_PF with pg_v, pte = %x\n",
460 				       *(u_int *)pte);
461 				goto dopanic;
462 			}
463 #endif
464 			pagein(v, 0);
465 			if (type == T_MMUFLT)
466 				return;
467 			goto out;
468 		}
469 #ifdef DEBUG
470 		printf("T_MMUFLT: unrecognized scenerio\n");
471 		goto dopanic;
472 #endif
473 	}
474 	trapsignal(i, ucode);
475 	if ((type & USER) == 0)
476 		return;
477 out:
478 	p = u.u_procp;
479 	if (i = CURSIG(p))
480 		psig(i);
481 	p->p_pri = p->p_usrpri;
482 	if (runrun) {
483 		/*
484 		 * Since we are u.u_procp, clock will normally just change
485 		 * our priority without moving us from one queue to another
486 		 * (since the running process is not on a queue.)
487 		 * If that happened after we setrq ourselves but before we
488 		 * swtch()'ed, we might not be on the queue indicated by
489 		 * our priority.
490 		 */
491 		(void) splclock();
492 		setrq(p);
493 		u.u_ru.ru_nivcsw++;
494 		swtch();
495 		if (i = CURSIG(p))
496 			psig(i);
497 	}
498 	if (u.u_prof.pr_scale) {
499 		int ticks;
500 		struct timeval *tv = &u.u_ru.ru_stime;
501 
502 		ticks = ((tv->tv_sec - syst.tv_sec) * 1000 +
503 			(tv->tv_usec - syst.tv_usec) / 1000) / (tick / 1000);
504 		if (ticks) {
505 #ifdef PROFTIMER
506 			extern int profscale;
507 			addupc(frame.f_pc, &u.u_prof, ticks * profscale);
508 #else
509 			addupc(frame.f_pc, &u.u_prof, ticks);
510 #endif
511 		}
512 	}
513 	curpri = p->p_pri;
514 }
515 
516 /*
517  * Called from the trap handler when a system call occurs
518  */
519 /*ARGSUSED*/
520 syscall(code, frame)
521 	volatile int code;
522 	struct frame frame;
523 {
524 	register caddr_t params;
525 	register int i;
526 	register struct sysent *callp;
527 	register struct proc *p = u.u_procp;
528 	int error, opc, numsys;
529 	int args[8], rval[2];
530 	struct timeval syst;
531 	struct sysent *systab;
532 #ifdef HPUXCOMPAT
533 	extern struct sysent hpuxsysent[];
534 	extern int hpuxnsysent, notimp();
535 #endif
536 
537 	cnt.v_syscall++;
538 	syst = u.u_ru.ru_stime;
539 	if (!USERMODE(frame.f_sr))
540 		panic("syscall");
541 	u.u_ar0 = frame.f_regs;
542 	opc = frame.f_pc - 2;
543 	systab = sysent;
544 	numsys = nsysent;
545 #ifdef HPUXCOMPAT
546 	if (p->p_flag & SHPUX) {
547 		systab = hpuxsysent;
548 		numsys = hpuxnsysent;
549 	}
550 #endif
551 	params = (caddr_t)frame.f_regs[SP] + NBPW;
552 	if (code == 0) {			/* indir */
553 		code = fuword(params);
554 		params += NBPW;
555 	}
556 	if (code >= numsys)
557 		callp = &systab[0];		/* indir (illegal) */
558 	else
559 		callp = &systab[code];
560 	if ((i = callp->sy_narg * sizeof (int)) &&
561 	    (error = copyin(params, (caddr_t)args, (u_int)i))) {
562 #ifdef HPUXCOMPAT
563 		if (p->p_flag & SHPUX)
564 			error = bsdtohpuxerrno(error);
565 #endif
566 		frame.f_regs[D0] = (u_char) error;
567 		frame.f_sr |= PSL_C;	/* carry bit */
568 #ifdef KTRACE
569 		if (KTRPOINT(p, KTR_SYSCALL))
570 			ktrsyscall(p->p_tracep, code, callp->sy_narg, args);
571 #endif
572 		goto done;
573 	}
574 #ifdef KTRACE
575 	if (KTRPOINT(p, KTR_SYSCALL))
576 		ktrsyscall(p->p_tracep, code, callp->sy_narg, args);
577 #endif
578 	rval[0] = 0;
579 	rval[1] = frame.f_regs[D1];
580 #ifdef HPUXCOMPAT
581 	/* debug kludge */
582 	if (callp->sy_call == notimp)
583 		error = notimp(u.u_procp, args, rval, code, callp->sy_narg);
584 	else
585 #endif
586 	error = (*callp->sy_call)(u.u_procp, args, rval);
587 	if (error == ERESTART)
588 		frame.f_pc = opc;
589 	else if (error != EJUSTRETURN) {
590 		if (error) {
591 #ifdef HPUXCOMPAT
592 			if (p->p_flag & SHPUX)
593 				error = bsdtohpuxerrno(error);
594 #endif
595 			frame.f_regs[D0] = (u_char) error;
596 			frame.f_sr |= PSL_C;	/* carry bit */
597 		} else {
598 			frame.f_regs[D0] = rval[0];
599 			frame.f_regs[D1] = rval[1];
600 			frame.f_sr &= ~PSL_C;
601 		}
602 	}
603 	/* else if (error == EJUSTRETURN) */
604 		/* nothing to do */
605 
606 done:
607 	/*
608 	 * Reinitialize proc pointer `p' as it may be different
609 	 * if this is a child returning from fork syscall.
610 	 */
611 	p = u.u_procp;
612 	/*
613 	 * XXX the check for sigreturn ensures that we don't
614 	 * attempt to set up a call to a signal handler (sendsig) before
615 	 * we have cleaned up the stack from the last call (sigreturn).
616 	 * Allowing this seems to lock up the machine in certain scenarios.
617 	 * What should really be done is to clean up the signal handling
618 	 * so that this is not a problem.
619 	 */
620 #include "syscall.h"
621 	if (code != SYS_sigreturn && (i = CURSIG(p)))
622 		psig(i);
623 	p->p_pri = p->p_usrpri;
624 	if (runrun) {
625 		/*
626 		 * Since we are u.u_procp, clock will normally just change
627 		 * our priority without moving us from one queue to another
628 		 * (since the running process is not on a queue.)
629 		 * If that happened after we setrq ourselves but before we
630 		 * swtch()'ed, we might not be on the queue indicated by
631 		 * our priority.
632 		 */
633 		(void) splclock();
634 		setrq(p);
635 		u.u_ru.ru_nivcsw++;
636 		swtch();
637 		if (code != SYS_sigreturn && (i = CURSIG(p)))
638 			psig(i);
639 	}
640 	if (u.u_prof.pr_scale) {
641 		int ticks;
642 		struct timeval *tv = &u.u_ru.ru_stime;
643 
644 		ticks = ((tv->tv_sec - syst.tv_sec) * 1000 +
645 			(tv->tv_usec - syst.tv_usec) / 1000) / (tick / 1000);
646 		if (ticks) {
647 #ifdef PROFTIMER
648 			extern int profscale;
649 			addupc(frame.f_pc, &u.u_prof, ticks * profscale);
650 #else
651 			addupc(frame.f_pc, &u.u_prof, ticks);
652 #endif
653 		}
654 	}
655 	curpri = p->p_pri;
656 #ifdef KTRACE
657 	if (KTRPOINT(p, KTR_SYSRET))
658 		ktrsysret(p->p_tracep, code, error, rval[0]);
659 #endif
660 }
661