xref: /original-bsd/sys/hp300/hp300/trap.c (revision abe165e9)
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.5 (Berkeley) 06/22/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 			i = u.u_error;
465 			pagein(v, 0);
466 			u.u_error = i;
467 			if (type == T_MMUFLT)
468 				return;
469 			goto out;
470 		}
471 #ifdef DEBUG
472 		printf("T_MMUFLT: unrecognized scenerio\n");
473 		goto dopanic;
474 #endif
475 	}
476 	trapsignal(i, ucode);
477 	if ((type & USER) == 0)
478 		return;
479 out:
480 	p = u.u_procp;
481 	if (i = CURSIG(p))
482 		psig(i);
483 	p->p_pri = p->p_usrpri;
484 	if (runrun) {
485 		/*
486 		 * Since we are u.u_procp, clock will normally just change
487 		 * our priority without moving us from one queue to another
488 		 * (since the running process is not on a queue.)
489 		 * If that happened after we setrq ourselves but before we
490 		 * swtch()'ed, we might not be on the queue indicated by
491 		 * our priority.
492 		 */
493 		(void) splclock();
494 		setrq(p);
495 		u.u_ru.ru_nivcsw++;
496 		swtch();
497 		if (i = CURSIG(p))
498 			psig(i);
499 	}
500 	if (u.u_prof.pr_scale) {
501 		int ticks;
502 		struct timeval *tv = &u.u_ru.ru_stime;
503 
504 		ticks = ((tv->tv_sec - syst.tv_sec) * 1000 +
505 			(tv->tv_usec - syst.tv_usec) / 1000) / (tick / 1000);
506 		if (ticks) {
507 #ifdef PROFTIMER
508 			extern int profscale;
509 			addupc(frame.f_pc, &u.u_prof, ticks * profscale);
510 #else
511 			addupc(frame.f_pc, &u.u_prof, ticks);
512 #endif
513 		}
514 	}
515 	curpri = p->p_pri;
516 }
517 
518 /*
519  * Called from the trap handler when a system call occurs
520  */
521 /*ARGSUSED*/
522 syscall(code, frame)
523 	volatile int code;
524 	struct frame frame;
525 {
526 	register caddr_t params;
527 	register int i;
528 	register struct sysent *callp;
529 	register struct proc *p = u.u_procp;
530 	int error, opc, numsys;
531 	struct timeval syst;
532 	struct sysent *systab;
533 #ifdef HPUXCOMPAT
534 	extern struct sysent hpuxsysent[];
535 	extern int hpuxnsysent, notimp();
536 #endif
537 
538 	cnt.v_syscall++;
539 	syst = u.u_ru.ru_stime;
540 	if (!USERMODE(frame.f_sr))
541 		panic("syscall");
542 	u.u_ar0 = frame.f_regs;
543 	u.u_error = 0;
544 	opc = frame.f_pc - 2;
545 	systab = sysent;
546 	numsys = nsysent;
547 #ifdef HPUXCOMPAT
548 	if (p->p_flag & SHPUX) {
549 		systab = hpuxsysent;
550 		numsys = hpuxnsysent;
551 	}
552 #endif
553 	params = (caddr_t)frame.f_regs[SP] + NBPW;
554 	if (code == 0) {			/* indir */
555 		code = fuword(params);
556 		params += NBPW;
557 	}
558 	if (code >= numsys)
559 		callp = &systab[0];		/* indir (illegal) */
560 	else
561 		callp = &systab[code];
562 	if ((i = callp->sy_narg * sizeof (int)) &&
563 	    (error = copyin(params, (caddr_t)u.u_arg, (u_int)i))) {
564 #ifdef HPUXCOMPAT
565 		if (p->p_flag & SHPUX)
566 			error = bsdtohpuxerrno(error);
567 #endif
568 		frame.f_regs[D0] = (u_char) error;
569 		frame.f_sr |= PSL_C;	/* carry bit */
570 #ifdef KTRACE
571                 if (KTRPOINT(p, KTR_SYSCALL))
572                         ktrsyscall(p->p_tracep, code, callp->sy_narg);
573 #endif
574 		goto done;
575 	}
576 #ifdef KTRACE
577         if (KTRPOINT(p, KTR_SYSCALL))
578                 ktrsyscall(p->p_tracep, code, callp->sy_narg);
579 #endif
580 	u.u_r.r_val1 = 0;
581 	u.u_r.r_val2 = frame.f_regs[D0];
582 #ifdef HPUXCOMPAT
583 	/* debug kludge */
584 	if (callp->sy_call == notimp)
585 		error = notimp(u.u_procp, u.u_ap, &u.u_r.r_val1,
586 			       code, callp->sy_narg);
587 	else
588 #endif
589 	error = (*callp->sy_call)(u.u_procp, u.u_ap, &u.u_r.r_val1);
590 	error = u.u_error;		/* XXX */
591 	if (error == ERESTART)
592 		frame.f_pc = opc;
593 	else if (error != EJUSTRETURN) {
594 		if (error) {
595 #ifdef HPUXCOMPAT
596 			if (p->p_flag & SHPUX)
597 				error = bsdtohpuxerrno(error);
598 #endif
599 			frame.f_regs[D0] = (u_char) error;
600 			frame.f_sr |= PSL_C;	/* carry bit */
601 		} else {
602 			frame.f_regs[D0] = u.u_r.r_val1;
603 			frame.f_regs[D1] = u.u_r.r_val2;
604 			frame.f_sr &= ~PSL_C;
605 		}
606 	}
607 	/* else if (error == EJUSTRETURN) */
608 		/* nothing to do */
609 
610 done:
611 	/*
612 	 * Reinitialize proc pointer `p' as it may be different
613 	 * if this is a child returning from fork syscall.
614 	 */
615 	p = u.u_procp;
616 	/*
617 	 * XXX the check for sigreturn ensures that we don't
618 	 * attempt to set up a call to a signal handler (sendsig) before
619 	 * we have cleaned up the stack from the last call (sigreturn).
620 	 * Allowing this seems to lock up the machine in certain scenarios.
621 	 * What should really be done is to clean up the signal handling
622 	 * so that this is not a problem.
623 	 */
624 #include "syscall.h"
625 	if (code != SYS_sigreturn && (i = CURSIG(p)))
626 		psig(i);
627 	p->p_pri = p->p_usrpri;
628 	if (runrun) {
629 		/*
630 		 * Since we are u.u_procp, clock will normally just change
631 		 * our priority without moving us from one queue to another
632 		 * (since the running process is not on a queue.)
633 		 * If that happened after we setrq ourselves but before we
634 		 * swtch()'ed, we might not be on the queue indicated by
635 		 * our priority.
636 		 */
637 		(void) splclock();
638 		setrq(p);
639 		u.u_ru.ru_nivcsw++;
640 		swtch();
641 		if (code != SYS_sigreturn && (i = CURSIG(p)))
642 			psig(i);
643 	}
644 	if (u.u_prof.pr_scale) {
645 		int ticks;
646 		struct timeval *tv = &u.u_ru.ru_stime;
647 
648 		ticks = ((tv->tv_sec - syst.tv_sec) * 1000 +
649 			(tv->tv_usec - syst.tv_usec) / 1000) / (tick / 1000);
650 		if (ticks) {
651 #ifdef PROFTIMER
652 			extern int profscale;
653 			addupc(frame.f_pc, &u.u_prof, ticks * profscale);
654 #else
655 			addupc(frame.f_pc, &u.u_prof, ticks);
656 #endif
657 		}
658 	}
659 	curpri = p->p_pri;
660 #ifdef KTRACE
661         if (KTRPOINT(p, KTR_SYSRET))
662                 ktrsysret(p->p_tracep, code);
663 #endif
664 }
665