xref: /original-bsd/sys/news3400/news3400/trap.c (revision 7f897caf)
1 /*
2  * Copyright (c) 1988 University of Utah.
3  * Copyright (c) 1992 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, Ralph Campbell, Sony Corp. and Kazumasa Utashiro
9  * of Software Research Associates, Inc.
10  *
11  * %sccs.include.redist.c%
12  *
13  * from: Utah $Hdr: trap.c 1.32 91/04/06$
14  *
15  *	@(#)trap.c	7.8 (Berkeley) 04/08/93
16  */
17 
18 #include <sys/param.h>
19 #include <sys/systm.h>
20 #include <sys/proc.h>
21 #include <sys/kernel.h>
22 #include <sys/signalvar.h>
23 #include <sys/syscall.h>
24 #include <sys/user.h>
25 #include <sys/buf.h>
26 #ifdef KTRACE
27 #include <sys/ktrace.h>
28 #endif
29 #include <net/netisr.h>
30 
31 #include <machine/trap.h>
32 #include <machine/psl.h>
33 #include <machine/reg.h>
34 #include <machine/cpu.h>
35 #include <machine/pte.h>
36 #include <machine/mips_opcode.h>
37 #include <machine/adrsmap.h>
38 
39 #include <vm/vm.h>
40 #include <vm/vm_kern.h>
41 #include <vm/vm_page.h>
42 
43 #include "lp.h"
44 #include "bm.h"
45 #include "ms.h"
46 #include "en.h"
47 #include <news3400/hbdev/dmac_0448.h>
48 #include <news3400/sio/scc.h>
49 
50 struct	proc *machFPCurProcPtr;		/* pointer to last proc to use FP */
51 
52 extern void MachKernGenException();
53 extern void MachUserGenException();
54 extern void MachKernIntr();
55 extern void MachUserIntr();
56 extern void MachTLBModException();
57 extern void MachTLBMissException();
58 extern unsigned MachEmulateBranch();
59 
60 void (*machExceptionTable[])() = {
61 /*
62  * The kernel exception handlers.
63  */
64 	MachKernIntr,			/* external interrupt */
65 	MachKernGenException,		/* TLB modification */
66 	MachTLBMissException,		/* TLB miss (load or instr. fetch) */
67 	MachTLBMissException,		/* TLB miss (store) */
68 	MachKernGenException,		/* address error (load or I-fetch) */
69 	MachKernGenException,		/* address error (store) */
70 	MachKernGenException,		/* bus error (I-fetch) */
71 	MachKernGenException,		/* bus error (load or store) */
72 	MachKernGenException,		/* system call */
73 	MachKernGenException,		/* breakpoint */
74 	MachKernGenException,		/* reserved instruction */
75 	MachKernGenException,		/* coprocessor unusable */
76 	MachKernGenException,		/* arithmetic overflow */
77 	MachKernGenException,		/* reserved */
78 	MachKernGenException,		/* reserved */
79 	MachKernGenException,		/* reserved */
80 /*
81  * The user exception handlers.
82  */
83 	MachUserIntr,
84 	MachUserGenException,
85 	MachUserGenException,
86 	MachUserGenException,
87 	MachUserGenException,
88 	MachUserGenException,
89 	MachUserGenException,
90 	MachUserGenException,
91 	MachUserGenException,
92 	MachUserGenException,
93 	MachUserGenException,
94 	MachUserGenException,
95 	MachUserGenException,
96 	MachUserGenException,
97 	MachUserGenException,
98 	MachUserGenException,
99 };
100 
101 char	*trap_type[] = {
102 	"external interrupt",
103 	"TLB modification",
104 	"TLB miss (load or instr. fetch)",
105 	"TLB miss (store)",
106 	"address error (load or I-fetch)",
107 	"address error (store)",
108 	"bus error (I-fetch)",
109 	"bus error (load or store)",
110 	"system call",
111 	"breakpoint",
112 	"reserved instruction",
113 	"coprocessor unusable",
114 	"arithmetic overflow",
115 	"reserved 13",
116 	"reserved 14",
117 	"reserved 15",
118 };
119 
120 #ifdef DEBUG
121 #define TRAPSIZE	10
122 struct trapdebug {		/* trap history buffer for debugging */
123 	u_int	status;
124 	u_int	cause;
125 	u_int	vadr;
126 	u_int	pc;
127 	u_int	ra;
128 	u_int	code;
129 } trapdebug[TRAPSIZE], *trp = trapdebug;
130 #endif
131 
132 /*
133  * Handle an exception.
134  * Called from MachKernGenException() or MachUserGenException()
135  * when a processor trap occurs.
136  * In the case of a kernel trap, we return the pc where to resume if
137  * ((struct pcb *)UADDR)->pcb_onfault is set, otherwise, return old pc.
138  */
139 unsigned
140 trap(statusReg, causeReg, vadr, pc, args)
141 	unsigned statusReg;	/* status register at time of the exception */
142 	unsigned causeReg;	/* cause register at time of exception */
143 	unsigned vadr;		/* address (if any) the fault occured on */
144 	unsigned pc;		/* program counter where to continue */
145 {
146 	register int type, i;
147 	unsigned ucode = 0;
148 	register struct proc *p = curproc;
149 	u_quad_t sticks;
150 	vm_prot_t ftype;
151 	extern unsigned onfault_table[];
152 
153 #ifdef DEBUG
154 	trp->status = statusReg;
155 	trp->cause = causeReg;
156 	trp->vadr = vadr;
157 	trp->pc = pc;
158 	trp->ra = !USERMODE(statusReg) ? ((int *)&args)[19] :
159 		p->p_md.md_regs[RA];
160 	trp->code = 0;
161 	if (++trp == &trapdebug[TRAPSIZE])
162 		trp = trapdebug;
163 #endif
164 
165 	cnt.v_trap++;
166 	type = (causeReg & MACH_CR_EXC_CODE) >> MACH_CR_EXC_CODE_SHIFT;
167 	if (USERMODE(statusReg)) {
168 		type |= T_USER;
169 		sticks = p->p_sticks;
170 	}
171 
172 	/*
173 	 * Enable hardware interrupts if they were on before.
174 	 * We only respond to software interrupts when returning to user mode.
175 	 */
176 	if (statusReg & MACH_SR_INT_ENA_PREV)
177 		splx((statusReg & MACH_HARD_INT_MASK) | MACH_SR_INT_ENA_CUR);
178 
179 	switch (type) {
180 	case T_TLB_MOD:
181 		/* check for kernel address */
182 		if ((int)vadr < 0) {
183 			register pt_entry_t *pte;
184 			register unsigned entry;
185 #ifndef ATTR
186 			register vm_offset_t pa;
187 #endif
188 
189 			pte = kvtopte(vadr);
190 			entry = pte->pt_entry;
191 			if (entry & PG_RO) {
192 				/* write to read only page in the kernel */
193 				ftype = VM_PROT_WRITE;
194 				goto kernel_fault;
195 			}
196 			entry |= PG_M;
197 			pte->pt_entry = entry;
198 			vadr &= PG_FRAME;
199 			printf("trap: TLBupdate hi %x lo %x i %x\n", vadr,
200 				entry, MachTLBUpdate(vadr, entry)); /* XXX */
201 #ifdef ATTR
202 			pmap_attributes[atop(entry - KERNBASE)] |= PMAP_ATTR_MOD;
203 #else
204 			pa = entry & PG_FRAME;
205 			if (!IS_VM_PHYSADDR(pa))
206 				panic("trap: kmod");
207 			PHYS_TO_VM_PAGE(pa)->flags &= ~PG_CLEAN;
208 #endif
209 			return (pc);
210 		}
211 		/* FALLTHROUGH */
212 
213 	case T_TLB_MOD+T_USER:
214 	    {
215 		pmap_hash_t hp;
216 #ifndef ATTR
217 		vm_offset_t pa;
218 #endif
219 #ifdef DIAGNOSTIC
220 		extern pmap_hash_t zero_pmap_hash;
221 		extern pmap_t cur_pmap;
222 
223 		if (cur_pmap->pm_hash == zero_pmap_hash ||
224 		    cur_pmap->pm_hash == (pmap_hash_t)0)
225 			panic("tlbmod");
226 #endif
227 		hp = &((pmap_hash_t)PMAP_HASH_UADDR)[PMAP_HASH(vadr)];
228 		if (((hp->pmh_pte[0].high ^ vadr) & ~PGOFSET) == 0)
229 			i = 0;
230 		else if (((hp->pmh_pte[1].high ^ vadr) & ~PGOFSET) == 0)
231 			i = 1;
232 		else
233 			panic("trap: tlb umod not found");
234 		if (hp->pmh_pte[i].low & PG_RO) {
235 			ftype = VM_PROT_WRITE;
236 			goto dofault;
237 		}
238 		hp->pmh_pte[i].low |= PG_M;
239 		printf("trap: TLBupdate hi %x lo %x i %x\n",
240 			hp->pmh_pte[i].high, hp->pmh_pte[i].low,
241 			MachTLBUpdate(hp->pmh_pte[i].high, hp->pmh_pte[i].low)); /* XXX */
242 #ifdef ATTR
243 		pmap_attributes[atop(hp->pmh_pte[i].low - KERNBASE)] |=
244 			PMAP_ATTR_MOD;
245 #else
246 		pa = hp->pmh_pte[i].low & PG_FRAME;
247 		if (!IS_VM_PHYSADDR(pa))
248 			panic("trap: umod");
249 		PHYS_TO_VM_PAGE(pa)->flags &= ~PG_CLEAN;
250 #endif
251 		if (!USERMODE(statusReg))
252 			return (pc);
253 		goto out;
254 	    }
255 
256 	case T_TLB_LD_MISS:
257 	case T_TLB_ST_MISS:
258 		ftype = (type == T_TLB_ST_MISS) ? VM_PROT_WRITE : VM_PROT_READ;
259 		/* check for kernel address */
260 		if ((int)vadr < 0) {
261 			register vm_offset_t va;
262 			int rv;
263 
264 		kernel_fault:
265 			va = trunc_page((vm_offset_t)vadr);
266 			rv = vm_fault(kernel_map, va, ftype, FALSE);
267 			if (rv == KERN_SUCCESS)
268 				return (pc);
269 			if (i = ((struct pcb *)UADDR)->pcb_onfault) {
270 				((struct pcb *)UADDR)->pcb_onfault = 0;
271 				return (onfault_table[i]);
272 			}
273 			goto err;
274 		}
275 		/*
276 		 * It is an error for the kernel to access user space except
277 		 * through the copyin/copyout routines.
278 		 */
279 		if ((i = ((struct pcb *)UADDR)->pcb_onfault) == 0)
280 			goto err;
281 		/* check for fuswintr() or suswintr() getting a page fault */
282 		if (i == 4)
283 			return (onfault_table[i]);
284 		goto dofault;
285 
286 	case T_TLB_LD_MISS+T_USER:
287 		ftype = VM_PROT_READ;
288 		goto dofault;
289 
290 	case T_TLB_ST_MISS+T_USER:
291 		ftype = VM_PROT_WRITE;
292 	dofault:
293 	    {
294 		register vm_offset_t va;
295 		register struct vmspace *vm = p->p_vmspace;
296 		register vm_map_t map = &vm->vm_map;
297 		int rv;
298 
299 		va = trunc_page((vm_offset_t)vadr);
300 		rv = vm_fault(map, va, ftype, FALSE);
301 		if (rv != KERN_SUCCESS) {
302 			printf("vm_fault(%x, %x, %x, 0) -> %x ADR %x PC %x RA %x\n",
303 				map, va, ftype, rv, vadr, pc,
304 				!USERMODE(statusReg) ? ((int *)&args)[19] :
305 					p->p_md.md_regs[RA]); /* XXX */
306 			printf("\tpid %d %s PC %x RA %x\n", p->p_pid,
307 				p->p_comm, p->p_md.md_regs[PC],
308 				p->p_md.md_regs[RA]); /* XXX */
309 #ifdef DEBUG
310 			trapDump("vm_fault");
311 #endif
312 		}
313 		/*
314 		 * If this was a stack access we keep track of the maximum
315 		 * accessed stack size.  Also, if vm_fault gets a protection
316 		 * failure it is due to accessing the stack region outside
317 		 * the current limit and we need to reflect that as an access
318 		 * error.
319 		 */
320 		if ((caddr_t)va >= vm->vm_maxsaddr) {
321 			if (rv == KERN_SUCCESS) {
322 				unsigned nss;
323 
324 				nss = clrnd(btoc(USRSTACK-(unsigned)va));
325 				if (nss > vm->vm_ssize)
326 					vm->vm_ssize = nss;
327 			} else if (rv == KERN_PROTECTION_FAILURE)
328 				rv = KERN_INVALID_ADDRESS;
329 		}
330 		if (rv == KERN_SUCCESS) {
331 			if (!USERMODE(statusReg))
332 				return (pc);
333 			goto out;
334 		}
335 		if (!USERMODE(statusReg)) {
336 			if (i = ((struct pcb *)UADDR)->pcb_onfault) {
337 				((struct pcb *)UADDR)->pcb_onfault = 0;
338 				return (onfault_table[i]);
339 			}
340 			goto err;
341 		}
342 		ucode = vadr;
343 		i = (rv == KERN_PROTECTION_FAILURE) ? SIGBUS : SIGSEGV;
344 		break;
345 	    }
346 
347 	case T_ADDR_ERR_LD+T_USER:	/* misaligned or kseg access */
348 	case T_ADDR_ERR_ST+T_USER:	/* misaligned or kseg access */
349 	case T_BUS_ERR_IFETCH+T_USER:	/* BERR asserted to cpu */
350 	case T_BUS_ERR_LD_ST+T_USER:	/* BERR asserted to cpu */
351 		i = SIGSEGV;
352 		break;
353 
354 	case T_SYSCALL+T_USER:
355 	    {
356 		register int *locr0 = p->p_md.md_regs;
357 		register struct sysent *callp;
358 		unsigned int code;
359 		int numsys;
360 		struct args {
361 			int i[8];
362 		} args;
363 		int rval[2];
364 		struct sysent *systab;
365 		extern int nsysent;
366 #ifdef COMPAT_NEWSOS
367 		extern int nnewssys;
368 		extern struct sysent newssys[];
369 #endif
370 
371 		cnt.v_syscall++;
372 		/* compute next PC after syscall instruction */
373 		if ((int)causeReg < 0)
374 			locr0[PC] = MachEmulateBranch(locr0, pc, 0, 0);
375 		else
376 			locr0[PC] += 4;
377 		systab = sysent;
378 		numsys = nsysent;
379 		code = locr0[V0];
380 #ifdef COMPAT_NEWSOS
381 		if (code >= 1000) {
382 			code -= 1000;
383 			systab = newssys;
384 			numsys = nnewssys;
385 		}
386 #endif
387 		switch (code) {
388 		case SYS_indir:
389 			/*
390 			 * Code is first argument, followed by actual args.
391 			 */
392 			code = locr0[A0];
393 #ifdef COMPAT_NEWSOS
394 			if (code >= 1000) {
395 				code -= 1000;
396 				systab = newssys;
397 				numsys = nnewssys;
398 			}
399 #endif
400 			if (code >= numsys)
401 				callp = &systab[SYS_indir]; /* (illegal) */
402 			else
403 				callp = &systab[code];
404 			i = callp->sy_narg;
405 			args.i[0] = locr0[A1];
406 			args.i[1] = locr0[A2];
407 			args.i[2] = locr0[A3];
408 			if (i > 3) {
409 				i = copyin((caddr_t)(locr0[SP] +
410 						4 * sizeof(int)),
411 					(caddr_t)&args.i[3],
412 					(u_int)(i - 3) * sizeof(int));
413 				if (i) {
414 					locr0[V0] = i;
415 					locr0[A3] = 1;
416 #ifdef KTRACE
417 					if (KTRPOINT(p, KTR_SYSCALL))
418 						ktrsyscall(p->p_tracep, code,
419 							callp->sy_narg, args.i);
420 #endif
421 					goto done;
422 				}
423 			}
424 			break;
425 
426 		case SYS___indir:
427 			/*
428 			 * Like indir, but code is a quad, so as to maintain
429 			 * quad alignment for the rest of the arguments.
430 			 */
431 			code = locr0[A0 + _QUAD_LOWWORD];
432 			if (code >= numsys)
433 				callp = &systab[SYS_indir]; /* (illegal) */
434 			else
435 				callp = &systab[code];
436 			i = callp->sy_narg;
437 			args.i[0] = locr0[A2];
438 			args.i[1] = locr0[A3];
439 			if (i > 2) {
440 				i = copyin((caddr_t)(locr0[SP] +
441 						4 * sizeof(int)),
442 					(caddr_t)&args.i[2],
443 					(u_int)(i - 2) * sizeof(int));
444 				if (i) {
445 					locr0[V0] = i;
446 					locr0[A3] = 1;
447 #ifdef KTRACE
448 					if (KTRPOINT(p, KTR_SYSCALL))
449 						ktrsyscall(p->p_tracep, code,
450 							callp->sy_narg, args.i);
451 #endif
452 					goto done;
453 				}
454 			}
455 			break;
456 
457 		default:
458 			if (code >= numsys)
459 				callp = &systab[SYS_indir]; /* (illegal) */
460 			else
461 				callp = &systab[code];
462 			i = callp->sy_narg;
463 			args.i[0] = locr0[A0];
464 			args.i[1] = locr0[A1];
465 			args.i[2] = locr0[A2];
466 			args.i[3] = locr0[A3];
467 			if (i > 4) {
468 				i = copyin((caddr_t)(locr0[SP] +
469 						4 * sizeof(int)),
470 					(caddr_t)&args.i[4],
471 					(u_int)(i - 4) * sizeof(int));
472 				if (i) {
473 					locr0[V0] = i;
474 					locr0[A3] = 1;
475 #ifdef KTRACE
476 					if (KTRPOINT(p, KTR_SYSCALL))
477 						ktrsyscall(p->p_tracep, code,
478 							callp->sy_narg, args.i);
479 #endif
480 					goto done;
481 				}
482 			}
483 		}
484 #ifdef KTRACE
485 		if (KTRPOINT(p, KTR_SYSCALL))
486 			ktrsyscall(p->p_tracep, code, callp->sy_narg, args.i);
487 #endif
488 		rval[0] = 0;
489 		rval[1] = locr0[V1];
490 #ifdef DEBUG
491 		if (trp == trapdebug)
492 			trapdebug[TRAPSIZE - 1].code = code;
493 		else
494 			trp[-1].code = code;
495 #endif
496 		i = (*callp->sy_call)(p, &args, rval);
497 		/*
498 		 * Reinitialize proc pointer `p' as it may be different
499 		 * if this is a child returning from fork syscall.
500 		 */
501 		p = curproc;
502 		locr0 = p->p_md.md_regs;
503 #ifdef DEBUG
504 		{ int s;
505 		s = splhigh();
506 		trp->status = statusReg;
507 		trp->cause = causeReg;
508 		trp->vadr = locr0[SP];
509 		trp->pc = locr0[PC];
510 		trp->ra = locr0[RA];
511 		trp->code = -code;
512 		if (++trp == &trapdebug[TRAPSIZE])
513 			trp = trapdebug;
514 		splx(s);
515 		}
516 #endif
517 		switch (i) {
518 		case 0:
519 			locr0[V0] = rval[0];
520 			locr0[V1] = rval[1];
521 			locr0[A3] = 0;
522 			break;
523 
524 		case ERESTART:
525 			locr0[PC] = pc;
526 			break;
527 
528 		case EJUSTRETURN:
529 			break;	/* nothing to do */
530 
531 		default:
532 			locr0[V0] = i;
533 			locr0[A3] = 1;
534 		}
535 	done:
536 #ifdef KTRACE
537 		if (KTRPOINT(p, KTR_SYSRET))
538 			ktrsysret(p->p_tracep, code, i, rval[0]);
539 #endif
540 
541 		goto out;
542 	    }
543 
544 	case T_BREAK+T_USER:
545 	    {
546 		register unsigned va, instr;
547 
548 		/* compute address of break instruction */
549 		va = pc;
550 		if ((int)causeReg < 0)
551 			va += 4;
552 
553 		/* read break instruction */
554 		instr = fuiword((caddr_t)va);
555 #ifdef KADB
556 		if (instr == MACH_BREAK_BRKPT || instr == MACH_BREAK_SSTEP)
557 			goto err;
558 #endif
559 		if (p->p_md.md_ss_addr != va || instr != MACH_BREAK_SSTEP) {
560 			i = SIGTRAP;
561 			break;
562 		}
563 
564 		/* restore original instruction and clear BP  */
565 		i = suiword((caddr_t)va, p->p_md.md_ss_instr);
566 		if (i < 0) {
567 			vm_offset_t sa, ea;
568 			int rv;
569 
570 			sa = trunc_page((vm_offset_t)va);
571 			ea = round_page((vm_offset_t)va+sizeof(int)-1);
572 			rv = vm_map_protect(&p->p_vmspace->vm_map, sa, ea,
573 				VM_PROT_DEFAULT, FALSE);
574 			if (rv == KERN_SUCCESS) {
575 				i = suiword((caddr_t)va, p->p_md.md_ss_instr);
576 				(void) vm_map_protect(&p->p_vmspace->vm_map,
577 					sa, ea, VM_PROT_READ|VM_PROT_EXECUTE,
578 					FALSE);
579 			}
580 		}
581 		if (i < 0) {
582 			i = SIGTRAP;
583 			break;
584 		}
585 		p->p_md.md_ss_addr = 0;
586 		goto out;
587 	    }
588 
589 	case T_RES_INST+T_USER:
590 		i = SIGILL;
591 		break;
592 
593 	case T_COP_UNUSABLE+T_USER:
594 		if ((causeReg & MACH_CR_COP_ERR) != 0x10000000) {
595 			i = SIGILL;	/* only FPU instructions allowed */
596 			break;
597 		}
598 		MachSwitchFPState(machFPCurProcPtr, p->p_md.md_regs);
599 		machFPCurProcPtr = p;
600 		p->p_md.md_regs[PS] |= MACH_SR_COP_1_BIT;
601 		p->p_md.md_flags |= MDP_FPUSED;
602 		goto out;
603 
604 	case T_OVFLOW+T_USER:
605 		i = SIGFPE;
606 		break;
607 
608 	case T_ADDR_ERR_LD:	/* misaligned access */
609 	case T_ADDR_ERR_ST:	/* misaligned access */
610 	case T_BUS_ERR_LD_ST:	/* BERR asserted to cpu */
611 		if (i = ((struct pcb *)UADDR)->pcb_onfault) {
612 			((struct pcb *)UADDR)->pcb_onfault = 0;
613 			return (onfault_table[i]);
614 		}
615 		/* FALLTHROUGH */
616 
617 	default:
618 	err:
619 #ifdef KADB
620 	    {
621 		extern struct pcb kdbpcb;
622 
623 		if (USERMODE(statusReg))
624 			kdbpcb = p->p_addr->u_pcb;
625 		else {
626 			kdbpcb.pcb_regs[ZERO] = 0;
627 			kdbpcb.pcb_regs[AST] = ((int *)&args)[2];
628 			kdbpcb.pcb_regs[V0] = ((int *)&args)[3];
629 			kdbpcb.pcb_regs[V1] = ((int *)&args)[4];
630 			kdbpcb.pcb_regs[A0] = ((int *)&args)[5];
631 			kdbpcb.pcb_regs[A1] = ((int *)&args)[6];
632 			kdbpcb.pcb_regs[A2] = ((int *)&args)[7];
633 			kdbpcb.pcb_regs[A3] = ((int *)&args)[8];
634 			kdbpcb.pcb_regs[T0] = ((int *)&args)[9];
635 			kdbpcb.pcb_regs[T1] = ((int *)&args)[10];
636 			kdbpcb.pcb_regs[T2] = ((int *)&args)[11];
637 			kdbpcb.pcb_regs[T3] = ((int *)&args)[12];
638 			kdbpcb.pcb_regs[T4] = ((int *)&args)[13];
639 			kdbpcb.pcb_regs[T5] = ((int *)&args)[14];
640 			kdbpcb.pcb_regs[T6] = ((int *)&args)[15];
641 			kdbpcb.pcb_regs[T7] = ((int *)&args)[16];
642 			kdbpcb.pcb_regs[T8] = ((int *)&args)[17];
643 			kdbpcb.pcb_regs[T9] = ((int *)&args)[18];
644 			kdbpcb.pcb_regs[RA] = ((int *)&args)[19];
645 			kdbpcb.pcb_regs[MULLO] = ((int *)&args)[21];
646 			kdbpcb.pcb_regs[MULHI] = ((int *)&args)[22];
647 			kdbpcb.pcb_regs[PC] = pc;
648 			kdbpcb.pcb_regs[SR] = statusReg;
649 			bzero((caddr_t)&kdbpcb.pcb_regs[F0], 33 * sizeof(int));
650 		}
651 		if (kdb(causeReg, vadr, p, !USERMODE(statusReg)))
652 			return (kdbpcb.pcb_regs[PC]);
653 	    }
654 #else
655 #ifdef DEBUG
656 		printf("trap: pid %d %s sig %d adr %x pc %x ra %x\n", p->p_pid,
657 			p->p_comm, i, vadr, pc, p->p_md.md_regs[RA]); /* XXX */
658 		trapDump("trap");
659 #endif
660 #endif
661 		panic("trap");
662 	}
663 	printf("trap: pid %d %s sig %d adr %x pc %x ra %x\n", p->p_pid,
664 		p->p_comm, i, vadr, pc, p->p_md.md_regs[RA]); /* XXX */
665 	trapsignal(p, i, ucode);
666 out:
667 	/*
668 	 * Note: we should only get here if returning to user mode.
669 	 */
670 	/* take pending signals */
671 	while ((i = CURSIG(p)) != 0)
672 		psig(i);
673 	p->p_pri = p->p_usrpri;
674 	astpending = 0;
675 	if (want_resched) {
676 		int s;
677 
678 		/*
679 		 * Since we are curproc, clock will normally just change
680 		 * our priority without moving us from one queue to another
681 		 * (since the running process is not on a queue.)
682 		 * If that happened after we setrq ourselves but before we
683 		 * swtch()'ed, we might not be on the queue indicated by
684 		 * our priority.
685 		 */
686 		s = splstatclock();
687 		setrq(p);
688 		p->p_stats->p_ru.ru_nivcsw++;
689 		swtch();
690 		splx(s);
691 		while ((i = CURSIG(p)) != 0)
692 			psig(i);
693 	}
694 	/*
695 	 * If profiling, charge system time to the trapped pc.
696 	 */
697 	if (p->p_flag & SPROFIL) {
698 		extern int psratio;
699 
700 		addupc_task(p, pc, (int)(p->p_sticks - sticks) * psratio);
701 	}
702 	curpri = p->p_pri;
703 	return (pc);
704 }
705 
706 int	badaddr_flag;
707 
708 /*
709  * Handle an interrupt.
710  * Called from MachKernIntr() or MachUserIntr()
711  * Note: curproc might be NULL.
712  */
713 interrupt(statusReg, causeReg, pc)
714 	unsigned statusReg;	/* status register at time of the exception */
715 	unsigned causeReg;	/* cause register at time of exception */
716 	unsigned pc;		/* program counter where to continue */
717 {
718 	register unsigned mask;
719 	struct clockframe cf;
720 	int oonfault = ((struct pcb *)UADDR)->pcb_onfault;
721 
722 #ifdef DEBUG
723 	trp->status = statusReg;
724 	trp->cause = causeReg;
725 	trp->vadr = 0;
726 	trp->pc = pc;
727 	trp->ra = 0;
728 	trp->code = 0;
729 	if (++trp == &trapdebug[TRAPSIZE])
730 		trp = trapdebug;
731 #endif
732 
733 	mask = causeReg & statusReg;	/* pending interrupts & enable mask */
734 	if (mask & MACH_INT_MASK_5) {		/* level 5 interrupt */
735 		splx((MACH_SPL_MASK_8 & ~causeReg) | MACH_SR_INT_ENA_CUR);
736 		printf("level 5 interrupt: PC %x CR %x SR %x\n",
737 			pc, causeReg, statusReg);
738 		causeReg &= ~MACH_INT_MASK_5;
739 	}
740 	if (mask & MACH_INT_MASK_4) {		/* level 4 interrupt */
741 		/*
742 		 * asynchronous bus error
743 		 */
744 		splx((MACH_SPL_MASK_7 & ~causeReg) | MACH_SR_INT_ENA_CUR);
745 		*(char *)INTCLR0 = INTCLR0_BERR;
746 		causeReg &= ~MACH_INT_MASK_4;
747 #define BADADDR 1
748 		if (oonfault == BADADDR) {		/* XXX */
749 			badaddr_flag = 1;
750 		} else {
751 			printf("level 4 interrupt: PC %x CR %x SR %x\n",
752 				pc, causeReg, statusReg);
753 		}
754 	}
755 	if (mask & MACH_INT_MASK_3) {		/* level 3 interrupt */
756 		/*
757 		 * fp error
758 		 */
759 		splx((MACH_SPL_MASK_6 & ~causeReg) | MACH_SR_INT_ENA_CUR);
760 		if (!USERMODE(statusReg)) {
761 #ifdef DEBUG
762 			trapDump("fpintr");
763 #else
764 			printf("FPU interrupt: PC %x CR %x SR %x\n",
765 				pc, causeReg, statusReg);
766 #endif
767 		} else
768 			MachFPInterrupt(statusReg, causeReg, pc);
769 		causeReg &= ~MACH_INT_MASK_3;
770 	}
771 	if (mask & MACH_INT_MASK_2) {		/* level 2 interrupt */
772 		register int stat;
773 
774 		splx((MACH_SPL_MASK_5 & ~causeReg) | MACH_SR_INT_ENA_CUR);
775 		stat = *(volatile u_char *)INTST0;
776 		if (stat & INTST0_TIMINT) {	/* timer */
777 			static int led_count = 0;
778 
779 			*(volatile u_char *)INTCLR0 = INTCLR0_TIMINT;
780 			cf.pc = pc;
781 			cf.sr = statusReg;
782 			hardclock(&cf);
783 			if (++led_count > hz) {
784 				led_count = 0;
785 				*(volatile u_char *)DEBUG_PORT ^= DP_LED1;
786 			}
787 		}
788 #if NBM > 0
789 		if (stat & INTST0_KBDINT)	/* keyboard */
790 			kbm_rint(SCC_KEYBOARD);
791 #endif
792 #if NMS > 0
793 		if (stat & INTST0_MSINT)	/* mouse */
794 			kbm_rint(SCC_MOUSE);
795 #endif
796 		causeReg &= ~MACH_INT_MASK_2;
797 	}
798 	if (mask & MACH_INT_MASK_1) {		/* level 1 interrupt */
799 		splx((MACH_SPL_MASK_4 & ~causeReg) | MACH_SR_INT_ENA_CUR);
800 		level1_intr();
801 		causeReg &= ~MACH_INT_MASK_1;
802 	}
803 	if (mask & MACH_INT_MASK_0) {		/* level 0 interrupt */
804 		splx((MACH_SPL_MASK_3 & ~causeReg) | MACH_SR_INT_ENA_CUR);
805 		level0_intr();
806 		causeReg &= ~MACH_INT_MASK_0;
807 	}
808 	splx((MACH_SPL_MASK_3 & ~causeReg) | MACH_SR_INT_ENA_CUR);
809 
810 	if (mask & MACH_SOFT_INT_MASK_0) {
811 		struct clockframe cf;
812 
813 		clearsoftclock();
814 		cnt.v_soft++;
815 		cf.pc = pc;
816 		cf.sr = statusReg;
817 		softclock();
818 	}
819 	/* process network interrupt if we trapped or will very soon */
820 	if ((mask & MACH_SOFT_INT_MASK_1) ||
821 	    netisr && (statusReg & MACH_SOFT_INT_MASK_1)) {
822 		clearsoftnet();
823 		cnt.v_soft++;
824 #ifdef INET
825 		if (netisr & (1 << NETISR_ARP)) {
826 			netisr &= ~(1 << NETISR_ARP);
827 			arpintr();
828 		}
829 		if (netisr & (1 << NETISR_IP)) {
830 			netisr &= ~(1 << NETISR_IP);
831 			ipintr();
832 		}
833 #endif
834 #ifdef NS
835 		if (netisr & (1 << NETISR_NS)) {
836 			netisr &= ~(1 << NETISR_NS);
837 			nsintr();
838 		}
839 #endif
840 #ifdef ISO
841 		if (netisr & (1 << NETISR_ISO)) {
842 			netisr &= ~(1 << NETISR_ISO);
843 			clnlintr();
844 		}
845 #endif
846 	}
847 	/* restore onfault flag */
848 	((struct pcb *)UADDR)->pcb_onfault = oonfault;
849 }
850 
851 /*
852  * This is called from MachUserIntr() if astpending is set.
853  * This is very similar to the tail of trap().
854  */
855 softintr(statusReg, pc)
856 	unsigned statusReg;	/* status register at time of the exception */
857 	unsigned pc;		/* program counter where to continue */
858 {
859 	register struct proc *p = curproc;
860 	int sig;
861 
862 	cnt.v_soft++;
863 	/* take pending signals */
864 	while ((sig = CURSIG(p)) != 0)
865 		psig(sig);
866 	p->p_pri = p->p_usrpri;
867 	astpending = 0;
868 	if (p->p_flag & SOWEUPC) {
869 		p->p_flag &= ~SOWEUPC;
870 		ADDUPROF(p);
871 	}
872 	if (want_resched) {
873 		int s;
874 
875 		/*
876 		 * Since we are curproc, clock will normally just change
877 		 * our priority without moving us from one queue to another
878 		 * (since the running process is not on a queue.)
879 		 * If that happened after we setrq ourselves but before we
880 		 * swtch()'ed, we might not be on the queue indicated by
881 		 * our priority.
882 		 */
883 		s = splstatclock();
884 		setrq(p);
885 		p->p_stats->p_ru.ru_nivcsw++;
886 		swtch();
887 		splx(s);
888 		while ((sig = CURSIG(p)) != 0)
889 			psig(sig);
890 	}
891 	curpri = p->p_pri;
892 }
893 
894 #ifdef DEBUG
895 trapDump(msg)
896 	char *msg;
897 {
898 	register int i;
899 	int s;
900 
901 	s = splhigh();
902 	printf("trapDump(%s)\n", msg);
903 	for (i = 0; i < TRAPSIZE; i++) {
904 		if (trp == trapdebug)
905 			trp = &trapdebug[TRAPSIZE - 1];
906 		else
907 			trp--;
908 		if (trp->cause == 0)
909 			break;
910 		printf("%s: ADR %x PC %x CR %x SR %x\n",
911 			trap_type[(trp->cause & MACH_CR_EXC_CODE) >>
912 				MACH_CR_EXC_CODE_SHIFT],
913 			trp->vadr, trp->pc, trp->cause, trp->status);
914 		printf("   RA %x code %d\n", trp->ra, trp->code);
915 	}
916 	bzero(trapdebug, sizeof(trapdebug));
917 	trp = trapdebug;
918 	splx(s);
919 }
920 #endif
921 
922 /*
923  * Return the resulting PC as if the branch was executed.
924  */
925 unsigned
926 MachEmulateBranch(regsPtr, instPC, fpcCSR, allowNonBranch)
927 	unsigned *regsPtr;
928 	unsigned instPC;
929 	unsigned fpcCSR;
930 	int allowNonBranch;
931 {
932 	InstFmt inst;
933 	unsigned retAddr;
934 	int condition;
935 	extern unsigned GetBranchDest();
936 
937 #if 0
938 	printf("regsPtr=%x PC=%x Inst=%x fpcCsr=%x\n", regsPtr, instPC,
939 		*(unsigned *)instPC, fpcCSR);
940 #endif
941 
942 	inst = *(InstFmt *)instPC;
943 	switch ((int)inst.JType.op) {
944 	case OP_SPECIAL:
945 		switch ((int)inst.RType.func) {
946 		case OP_JR:
947 		case OP_JALR:
948 			retAddr = regsPtr[inst.RType.rs];
949 			break;
950 
951 		default:
952 			if (!allowNonBranch)
953 				panic("MachEmulateBranch: Non-branch");
954 			retAddr = instPC + 4;
955 			break;
956 		}
957 		break;
958 
959 	case OP_BCOND:
960 		switch ((int)inst.IType.rt) {
961 		case OP_BLTZ:
962 		case OP_BLTZAL:
963 			if ((int)(regsPtr[inst.RType.rs]) < 0)
964 				retAddr = GetBranchDest((InstFmt *)instPC);
965 			else
966 				retAddr = instPC + 8;
967 			break;
968 
969 		case OP_BGEZAL:
970 		case OP_BGEZ:
971 			if ((int)(regsPtr[inst.RType.rs]) >= 0)
972 				retAddr = GetBranchDest((InstFmt *)instPC);
973 			else
974 				retAddr = instPC + 8;
975 			break;
976 
977 		default:
978 			panic("MachEmulateBranch: Bad branch cond");
979 		}
980 		break;
981 
982 	case OP_J:
983 	case OP_JAL:
984 		retAddr = (inst.JType.target << 2) |
985 			((unsigned)instPC & 0xF0000000);
986 		break;
987 
988 	case OP_BEQ:
989 		if (regsPtr[inst.RType.rs] == regsPtr[inst.RType.rt])
990 			retAddr = GetBranchDest((InstFmt *)instPC);
991 		else
992 			retAddr = instPC + 8;
993 		break;
994 
995 	case OP_BNE:
996 		if (regsPtr[inst.RType.rs] != regsPtr[inst.RType.rt])
997 			retAddr = GetBranchDest((InstFmt *)instPC);
998 		else
999 			retAddr = instPC + 8;
1000 		break;
1001 
1002 	case OP_BLEZ:
1003 		if ((int)(regsPtr[inst.RType.rs]) <= 0)
1004 			retAddr = GetBranchDest((InstFmt *)instPC);
1005 		else
1006 			retAddr = instPC + 8;
1007 		break;
1008 
1009 	case OP_BGTZ:
1010 		if ((int)(regsPtr[inst.RType.rs]) > 0)
1011 			retAddr = GetBranchDest((InstFmt *)instPC);
1012 		else
1013 			retAddr = instPC + 8;
1014 		break;
1015 
1016 	case OP_COP1:
1017 		switch (inst.RType.rs) {
1018 		case OP_BCx:
1019 		case OP_BCy:
1020 			if ((inst.RType.rt & COPz_BC_TF_MASK) == COPz_BC_TRUE)
1021 				condition = fpcCSR & MACH_FPC_COND_BIT;
1022 			else
1023 				condition = !(fpcCSR & MACH_FPC_COND_BIT);
1024 			if (condition)
1025 				retAddr = GetBranchDest((InstFmt *)instPC);
1026 			else
1027 				retAddr = instPC + 8;
1028 			break;
1029 
1030 		default:
1031 			if (!allowNonBranch)
1032 				panic("MachEmulateBranch: Bad coproc branch instruction");
1033 			retAddr = instPC + 4;
1034 		}
1035 		break;
1036 
1037 	default:
1038 		if (!allowNonBranch)
1039 			panic("MachEmulateBranch: Non-branch instruction");
1040 		retAddr = instPC + 4;
1041 	}
1042 #if 0
1043 	printf("Target addr=%x\n", retAddr);
1044 #endif
1045 	return (retAddr);
1046 }
1047 
1048 unsigned
1049 GetBranchDest(InstPtr)
1050 	InstFmt *InstPtr;
1051 {
1052 	return ((unsigned)InstPtr + 4 + ((short)InstPtr->IType.imm << 2));
1053 }
1054 
1055 /*
1056  * This routine is called by procxmt() to single step one instruction.
1057  * We do this by storing a break instruction after the current instruction,
1058  * resuming execution, and then restoring the old instruction.
1059  */
1060 cpu_singlestep(p)
1061 	register struct proc *p;
1062 {
1063 	register unsigned va;
1064 	register int *locr0 = p->p_md.md_regs;
1065 	int i;
1066 
1067 	/* compute next address after current location */
1068 	va = MachEmulateBranch(locr0, locr0[PC], 0, 1);
1069 	if (p->p_md.md_ss_addr || p->p_md.md_ss_addr == va ||
1070 	    !useracc((caddr_t)va, 4, B_READ)) {
1071 		printf("SS %s (%d): breakpoint already set at %x (va %x)\n",
1072 			p->p_comm, p->p_pid, p->p_md.md_ss_addr, va); /* XXX */
1073 		return (EFAULT);
1074 	}
1075 	p->p_md.md_ss_addr = va;
1076 	p->p_md.md_ss_instr = fuiword((caddr_t)va);
1077 	i = suiword((caddr_t)va, MACH_BREAK_SSTEP);
1078 	if (i < 0) {
1079 		vm_offset_t sa, ea;
1080 		int rv;
1081 
1082 		sa = trunc_page((vm_offset_t)va);
1083 		ea = round_page((vm_offset_t)va+sizeof(int)-1);
1084 		rv = vm_map_protect(&p->p_vmspace->vm_map, sa, ea,
1085 			VM_PROT_DEFAULT, FALSE);
1086 		if (rv == KERN_SUCCESS) {
1087 			i = suiword((caddr_t)va, MACH_BREAK_SSTEP);
1088 			(void) vm_map_protect(&p->p_vmspace->vm_map,
1089 				sa, ea, VM_PROT_READ|VM_PROT_EXECUTE, FALSE);
1090 		}
1091 	}
1092 	if (i < 0)
1093 		return (EFAULT);
1094 	printf("SS %s (%d): breakpoint set at %x: %x (pc %x)\n",
1095 		p->p_comm, p->p_pid, p->p_md.md_ss_addr,
1096 		p->p_md.md_ss_instr, locr0[PC]); /* XXX */
1097 	return (0);
1098 }
1099 
1100 /*
1101  * news3400 - INT0 service routine.
1102  *
1103  * INTST0 bit	4:	dma
1104  *		3:	slot #1
1105  *		2:	slot #3
1106  *		1:	external #1
1107  *		0:	external #3
1108  */
1109 
1110 #define	LEVEL0_MASK	\
1111 	(INTST1_DMA|INTST1_SLOT1|INTST1_SLOT3|INTST1_EXT1|INTST1_EXT3)
1112 
1113 level0_intr()
1114 {
1115 	register int stat;
1116 
1117 	stat = *(volatile u_char *)INTST1 & LEVEL0_MASK;
1118 	*(u_char *)INTCLR1 = stat;
1119 
1120 	if (stat & INTST1_DMA)
1121 		dma_intr();
1122 	if (stat & INTST1_SLOT1)
1123 		exec_hb_intr2();
1124 #if NEN > 0
1125 	if (stat & INTST1_SLOT3) {
1126 		int s, t;
1127 
1128 		s = splimp();
1129 		t = lance_intr();
1130 		(void) splx(s);
1131 		if (t == 0)
1132 			exec_hb_intr4();
1133 	}
1134 #endif
1135 #if NLE > 0
1136 	if (stat & INTST1_SLOT3) {
1137 		int s;
1138 
1139 		s = splimp();
1140 		leintr(0);
1141 		(void) splx(s);
1142 	}
1143 #endif
1144 	if (stat & INTST1_EXT1)
1145 		print_int_stat("EXT #1");
1146 	if (stat & INTST1_EXT3)
1147 		print_int_stat("EXT #3");
1148 }
1149 
1150 /*
1151  * news3400 - INT1 service routine.
1152  *
1153  * INTST0 bit	1:	centro fault
1154  *		0:	centro busy
1155  * INTST1 bit	7:	beep
1156  *		6:	scc
1157  *		5:	lance
1158  */
1159 
1160 #define LEVEL1_MASK2	(INTST0_CFLT|INTST0_CBSY)
1161 #define LEVEL1_MASK1	(INTST1_BEEP|INTST1_SCC|INTST1_LANCE)
1162 
1163 level1_intr(pc)
1164 	unsigned pc;
1165 {
1166 	register int stat;
1167 	register u_int saved_inten1 = *(u_char *)INTEN1;
1168 
1169 	*(u_char *)INTEN1 = 0;		/* disable intr: beep, lance, scc */
1170 
1171 	stat = *(volatile u_char *)INTST1 & LEVEL1_MASK1;
1172 	*(u_char *)INTCLR1 = stat;
1173 
1174 	stat &= saved_inten1;
1175 
1176 	if (stat & INTST1_BEEP) {
1177 		*(volatile u_char *)INTCLR1 = INTCLR1_BEEP;
1178 		print_int_stat("BEEP");
1179 	}
1180 	if (stat & INTST1_SCC) {
1181 		scc_intr();
1182 		if (saved_inten1 & *(u_char *)INTST1 & INTST1_SCC)
1183 			scc_intr();
1184 	}
1185 #if NEN > 0
1186 	if (stat & INTST1_LANCE)
1187 		lance_intr();
1188 #endif
1189 #if NLE > 0
1190 	if (stat & INTST1_LANCE)
1191 		leintr(0);
1192 #endif
1193 
1194 	*(u_char *)INTEN1 = saved_inten1;
1195 
1196 #if NLP > 0
1197 	/*
1198 	 * The PARK2 cannot find centro interrupt correctly.
1199 	 * We must check it by reading the cause register of cpu
1200 	 * while other interrupts are disabled.
1201 	 */
1202 	{
1203 		register int causereg;
1204 		int s = splhigh();
1205 
1206 		causereg = get_causereg();
1207 		(void) splx(s);
1208 
1209 		if ((causereg & CAUSE_IP4) == 0)
1210 			return;
1211 	}
1212 #endif
1213 
1214 	stat = (int)(*(u_char *)INTST0) & LEVEL1_MASK2;
1215 	*(u_char *)INTCLR0 = stat;
1216 
1217 	if (stat & INTST0_CBSY)		/* centro busy */
1218 #if NLP > 0
1219 		lpxint(0);
1220 #else
1221 		printf("stray intr: CBSY\n");
1222 #endif
1223 }
1224 
1225 /*
1226  * DMA interrupt service routine.
1227  */
1228 dma_intr()
1229 {
1230         register volatile u_char *gsp = (u_char *)DMAC_GSTAT;
1231         register u_int gstat = *gsp;
1232         register int mrqb, i;
1233 
1234 	/*
1235 	 * when DMA intrrupt occurs there remain some untransferred data.
1236 	 * wait data transfer completion.
1237 	 */
1238 	mrqb = (gstat & (CH0_INT|CH1_INT|CH2_INT|CH3_INT)) << 1;
1239 	if (gstat & mrqb) {
1240 		/*
1241 		 * SHOULD USE DELAY()
1242 		 */
1243 		for (i = 0; i < 50; i++)
1244 			;
1245 		if (*gsp & mrqb)
1246 			printf("dma_intr: MRQ\n");
1247 	}
1248 
1249 	/* SCSI Dispatch */
1250 	if (gstat & CH_INT(CH_SCSI))
1251 		scintr();
1252 
1253 #include "fd.h"
1254 #if NFD > 0
1255         /* FDC Interrupt Dispatch */
1256 	if (gstat & CH_INT(CH_FDC))
1257 		fdc_intr(0);
1258 #endif /* NFD > 0 */
1259 
1260 #include "sb.h"
1261 #if NSB > 0
1262         /* Audio Interface Dispatch */
1263 	sbintr(0);
1264 #endif /* NSB > 0 */
1265 
1266         /* Video I/F Dispatch */
1267 	if (gstat & CH_INT(CH_VIDEO))
1268 		;
1269 }
1270 
1271 /*
1272  * SCC vector interrupt service routine.
1273  */
1274 scc_intr()
1275 {
1276 	int vec;
1277 	extern int scc_xint(), scc_sint(), scc_rint(), scc_cint();
1278 	static int (*func[])() = {
1279 		scc_xint,
1280 		scc_sint,
1281 		scc_rint,
1282 		scc_cint
1283 	};
1284 
1285 	vec = *(volatile u_char *)SCCVECT;
1286 	(*func[(vec & SCC_INT_MASK) >> 1])(vec);
1287 }
1288 
1289 print_int_stat(msg)
1290 	char *msg;
1291 {
1292 	int s0 = *(volatile u_char *)INTST0;
1293 	int s1 = *(volatile u_char *)INTST1;
1294 
1295 	if (msg)
1296 		printf("%s: ", msg);
1297 	else
1298 		printf("intr: ");
1299 	printf("INTST0=0x%x, INTST1=0x%x.\n", s0, s1);
1300 }
1301 
1302 traceback()
1303 {
1304 	u_int pc, sp;
1305 
1306 	getpcsp(&pc, &sp);
1307 	backtr(pc, sp);
1308 }
1309 
1310 #define EF_RA   	        92              /* r31: return address */
1311 #define KERN_REG_SIZE		(18 * 4)
1312 #define STAND_FRAME_SIZE	24
1313 #define EF_SIZE			STAND_FRAME_SIZE + KERN_REG_SIZE + 12
1314 
1315 extern u_int MachKernGenExceptionEnd[];
1316 extern u_int end[];
1317 #define	ENDOFTXT	(end + 1)
1318 
1319 #define VALID_TEXT(pc)	\
1320 	((u_int *)MACH_CODE_START <= (u_int *)MACH_UNCACHED_TO_CACHED(pc) && \
1321 	 (u_int *)MACH_UNCACHED_TO_CACHED(pc) <= (u_int *)ENDOFTXT)
1322 
1323 #define ExceptionHandler(x) \
1324 	((u_int*)MachKernGenException < (u_int*)MACH_UNCACHED_TO_CACHED(x) && \
1325 	 (u_int*)MACH_UNCACHED_TO_CACHED(x) < (u_int*)MachKernGenExceptionEnd)
1326 
1327 backtr(pc, sp)
1328 	register u_int *pc;
1329 	register caddr_t sp;
1330 {
1331 	int fsize;
1332 	u_int *getra();
1333 	extern int _gp[];
1334 
1335 	printf("start trace back pc=%x, sp=%x, pid=%d[%s]\n",
1336 		pc, sp, curproc->p_pid, curproc->p_comm);
1337 
1338 	while (VALID_TEXT(pc)) {
1339 		if (sp >= (caddr_t)KERNELSTACK || sp < (caddr_t)UADDR) {
1340 			printf("stack exhausted (sp=0x%x)\n", sp);
1341 			break;
1342 		}
1343 		if (ExceptionHandler(pc)) {
1344 			pc = (u_int *)(*((u_int *)&sp[EF_RA]));
1345 			sp += EF_SIZE;
1346 			printf("trapped from pc=%x, sp=%x\n", pc, sp);
1347 		} else {
1348 			pc = getra(pc, sp, &fsize);
1349 			sp += fsize;
1350 			printf("called from pc=%x, sp=%x\n", pc, sp);
1351 		}
1352 	}
1353 	printf("trace back END. pid=%d[%s]\n", curproc->p_pid, curproc->p_comm);
1354 }
1355 
1356 #define	NPCSTOCK	128
1357 
1358 u_int *
1359 getra(pc, sp, fsize)
1360 	register int *pc;
1361 	register caddr_t sp;
1362 	int *fsize;
1363 {
1364 	u_int regs[32];
1365 	int *opcs[NPCSTOCK];
1366 	register int i, nbpc = 0;
1367 	int printed = 0;
1368 	InstFmt I;
1369 
1370 	*fsize = 0;
1371 	for (i = 0; i < 32; i++) regs[i] = 0;
1372 	for (; (u_int*)MACH_UNCACHED_TO_CACHED(pc) < (u_int*)ENDOFTXT; pc++) {
1373 		I.word = *pc;
1374 		switch (I.IType.op) {
1375 
1376 		case OP_ADDIU:
1377 			/* sp += fsize */
1378 			if (I.IType.rs == SP && I.IType.rt == SP)
1379 				*fsize = (u_short)I.IType.imm;
1380 			break;
1381 
1382 		case OP_LW:
1383 			if (I.IType.rs != SP)
1384 				break;
1385 			regs[I.IType.rt] = *(u_int *)&sp[(short)I.IType.imm];
1386 			break;
1387 
1388 		case OP_BEQ:
1389 			if (I.IType.rs != ZERO || I.IType.rt != ZERO)
1390 				break;
1391 			for (i = 0; i < nbpc; i++)
1392 				if (pc == opcs[i]) {
1393 					/*
1394 					 * Brach constructs infinite loop.
1395 					 */
1396 					if (!printed) {
1397 						printf("branch loop\n");
1398 						printed = 1;
1399 					}
1400 					break;
1401 				}
1402 			if (i == nbpc) {
1403 				opcs[nbpc] = pc;
1404 				nbpc = imin(nbpc + 1, NPCSTOCK);
1405 				pc = pc + (short)I.IType.imm;
1406 			}
1407 			break;
1408 
1409 		default:
1410 			break;
1411 		}
1412 
1413 		I.word = *(pc - 1);
1414 		if (I.RType.op == OP_SPECIAL && I.RType.func == OP_JR)
1415 			return ((int *)regs[I.RType.rs]);
1416 	}
1417 	printf("pc run out of TEXT\n");
1418 	return (0);
1419 }
1420