xref: /plan9-contrib/sys/src/9/bcm/trap.c (revision 5c47fe09a0cc86dfb02c0ea4a2b6aec7eda2361f)
15d9de2d3SDavid du Colombier /*
25d9de2d3SDavid du Colombier  * traps, exceptions, interrupts, system calls.
35d9de2d3SDavid du Colombier  */
45d9de2d3SDavid du Colombier #include "u.h"
55d9de2d3SDavid du Colombier #include "../port/lib.h"
65d9de2d3SDavid du Colombier #include "mem.h"
75d9de2d3SDavid du Colombier #include "dat.h"
85d9de2d3SDavid du Colombier #include "fns.h"
95d9de2d3SDavid du Colombier #include "io.h"
105d9de2d3SDavid du Colombier #include "ureg.h"
115d9de2d3SDavid du Colombier #include "../port/error.h"
125d9de2d3SDavid du Colombier 
135d9de2d3SDavid du Colombier #include "arm.h"
145d9de2d3SDavid du Colombier 
155d9de2d3SDavid du Colombier #define INTREGS		(VIRTIO+0xB200)
16*5c47fe09SDavid du Colombier #define	LOCALREGS	(VIRTIO+IOSIZE)
175d9de2d3SDavid du Colombier 
185d9de2d3SDavid du Colombier typedef struct Intregs Intregs;
195d9de2d3SDavid du Colombier typedef struct Vctl Vctl;
205d9de2d3SDavid du Colombier 
215d9de2d3SDavid du Colombier enum {
228153b942SDavid du Colombier 	Debug = 0,
238153b942SDavid du Colombier 
245d9de2d3SDavid du Colombier 	Nvec = 8,		/* # of vectors at start of lexception.s */
255d9de2d3SDavid du Colombier 	Fiqenable = 1<<7,
26*5c47fe09SDavid du Colombier 
27*5c47fe09SDavid du Colombier 	Localtimerint	= 0x40,
28*5c47fe09SDavid du Colombier 	Localmboxint	= 0x50,
29*5c47fe09SDavid du Colombier 	Localintpending	= 0x60,
305d9de2d3SDavid du Colombier };
315d9de2d3SDavid du Colombier 
325d9de2d3SDavid du Colombier /*
335d9de2d3SDavid du Colombier  *   Layout at virtual address KZERO (double mapped at HVECTORS).
345d9de2d3SDavid du Colombier  */
355d9de2d3SDavid du Colombier typedef struct Vpage0 {
365d9de2d3SDavid du Colombier 	void	(*vectors[Nvec])(void);
375d9de2d3SDavid du Colombier 	u32int	vtable[Nvec];
385d9de2d3SDavid du Colombier } Vpage0;
395d9de2d3SDavid du Colombier 
405d9de2d3SDavid du Colombier /*
415d9de2d3SDavid du Colombier  * interrupt control registers
425d9de2d3SDavid du Colombier  */
435d9de2d3SDavid du Colombier struct Intregs {
445d9de2d3SDavid du Colombier 	u32int	ARMpending;
455d9de2d3SDavid du Colombier 	u32int	GPUpending[2];
465d9de2d3SDavid du Colombier 	u32int	FIQctl;
475d9de2d3SDavid du Colombier 	u32int	GPUenable[2];
485d9de2d3SDavid du Colombier 	u32int	ARMenable;
495d9de2d3SDavid du Colombier 	u32int	GPUdisable[2];
505d9de2d3SDavid du Colombier 	u32int	ARMdisable;
515d9de2d3SDavid du Colombier };
525d9de2d3SDavid du Colombier 
535d9de2d3SDavid du Colombier struct Vctl {
545d9de2d3SDavid du Colombier 	Vctl	*next;
555d9de2d3SDavid du Colombier 	int	irq;
56*5c47fe09SDavid du Colombier 	int	cpu;
575d9de2d3SDavid du Colombier 	u32int	*reg;
585d9de2d3SDavid du Colombier 	u32int	mask;
595d9de2d3SDavid du Colombier 	void	(*f)(Ureg*, void*);
605d9de2d3SDavid du Colombier 	void	*a;
615d9de2d3SDavid du Colombier };
625d9de2d3SDavid du Colombier 
63*5c47fe09SDavid du Colombier static Lock vctllock;
645d9de2d3SDavid du Colombier static Vctl *vctl, *vfiq;
655d9de2d3SDavid du Colombier 
665d9de2d3SDavid du Colombier static char *trapnames[PsrMask+1] = {
675d9de2d3SDavid du Colombier 	[ PsrMusr ] "user mode",
685d9de2d3SDavid du Colombier 	[ PsrMfiq ] "fiq interrupt",
695d9de2d3SDavid du Colombier 	[ PsrMirq ] "irq interrupt",
705d9de2d3SDavid du Colombier 	[ PsrMsvc ] "svc/swi exception",
715d9de2d3SDavid du Colombier 	[ PsrMabt ] "prefetch abort/data abort",
725d9de2d3SDavid du Colombier 	[ PsrMabt+1 ] "data abort",
735d9de2d3SDavid du Colombier 	[ PsrMund ] "undefined instruction",
745d9de2d3SDavid du Colombier 	[ PsrMsys ] "sys trap",
755d9de2d3SDavid du Colombier };
765d9de2d3SDavid du Colombier 
775d9de2d3SDavid du Colombier extern int notify(Ureg*);
785d9de2d3SDavid du Colombier 
795d9de2d3SDavid du Colombier /*
805d9de2d3SDavid du Colombier  *  set up for exceptions
815d9de2d3SDavid du Colombier  */
825d9de2d3SDavid du Colombier void
trapinit(void)835d9de2d3SDavid du Colombier trapinit(void)
845d9de2d3SDavid du Colombier {
855d9de2d3SDavid du Colombier 	Vpage0 *vpage0;
865d9de2d3SDavid du Colombier 
87*5c47fe09SDavid du Colombier 	if (m->machno == 0) {
885d9de2d3SDavid du Colombier 		/* disable everything */
895d9de2d3SDavid du Colombier 		intrsoff();
905d9de2d3SDavid du Colombier 		/* set up the exception vectors */
915d9de2d3SDavid du Colombier 		vpage0 = (Vpage0*)HVECTORS;
925d9de2d3SDavid du Colombier 		memmove(vpage0->vectors, vectors, sizeof(vpage0->vectors));
935d9de2d3SDavid du Colombier 		memmove(vpage0->vtable, vtable, sizeof(vpage0->vtable));
945d9de2d3SDavid du Colombier 		cacheuwbinv();
95*5c47fe09SDavid du Colombier 		l2cacheuwbinv();
96*5c47fe09SDavid du Colombier 	}
975d9de2d3SDavid du Colombier 
985d9de2d3SDavid du Colombier 	/* set up the stacks for the interrupt modes */
995d9de2d3SDavid du Colombier 	setr13(PsrMfiq, (u32int*)(FIQSTKTOP));
1005d9de2d3SDavid du Colombier 	setr13(PsrMirq, m->sirq);
1015d9de2d3SDavid du Colombier 	setr13(PsrMabt, m->sabt);
1025d9de2d3SDavid du Colombier 	setr13(PsrMund, m->sund);
1035d9de2d3SDavid du Colombier 	setr13(PsrMsys, m->ssys);
1045d9de2d3SDavid du Colombier 
1055d9de2d3SDavid du Colombier 	coherence();
1065d9de2d3SDavid du Colombier }
1075d9de2d3SDavid du Colombier 
1085d9de2d3SDavid du Colombier void
intrcpushutdown(void)109*5c47fe09SDavid du Colombier intrcpushutdown(void)
110*5c47fe09SDavid du Colombier {
111*5c47fe09SDavid du Colombier 	u32int *enable;
112*5c47fe09SDavid du Colombier 
113*5c47fe09SDavid du Colombier 	if(soc.armlocal == 0)
114*5c47fe09SDavid du Colombier 		return;
115*5c47fe09SDavid du Colombier 	enable = (u32int*)(LOCALREGS + Localtimerint) + m->machno;
116*5c47fe09SDavid du Colombier 	*enable = 0;
117*5c47fe09SDavid du Colombier 	if(m->machno){
118*5c47fe09SDavid du Colombier 		enable = (u32int*)(LOCALREGS + Localmboxint) + m->machno;
119*5c47fe09SDavid du Colombier 		*enable = 1;
120*5c47fe09SDavid du Colombier 	}
121*5c47fe09SDavid du Colombier }
122*5c47fe09SDavid du Colombier 
123*5c47fe09SDavid du Colombier void
intrsoff(void)1245d9de2d3SDavid du Colombier intrsoff(void)
1255d9de2d3SDavid du Colombier {
1265d9de2d3SDavid du Colombier 	Intregs *ip;
1275d9de2d3SDavid du Colombier 	int disable;
1285d9de2d3SDavid du Colombier 
1295d9de2d3SDavid du Colombier 	ip = (Intregs*)INTREGS;
1305d9de2d3SDavid du Colombier 	disable = ~0;
1315d9de2d3SDavid du Colombier 	ip->GPUdisable[0] = disable;
1325d9de2d3SDavid du Colombier 	ip->GPUdisable[1] = disable;
1335d9de2d3SDavid du Colombier 	ip->ARMdisable = disable;
1345d9de2d3SDavid du Colombier 	ip->FIQctl = 0;
1355d9de2d3SDavid du Colombier }
1365d9de2d3SDavid du Colombier 
137*5c47fe09SDavid du Colombier /* called from cpu0 after other cpus are shutdown */
138*5c47fe09SDavid du Colombier void
intrshutdown(void)139*5c47fe09SDavid du Colombier intrshutdown(void)
140*5c47fe09SDavid du Colombier {
141*5c47fe09SDavid du Colombier 	intrsoff();
142*5c47fe09SDavid du Colombier 	intrcpushutdown();
143*5c47fe09SDavid du Colombier }
144*5c47fe09SDavid du Colombier 
145*5c47fe09SDavid du Colombier static void
intrtime(void)146*5c47fe09SDavid du Colombier intrtime(void)
147*5c47fe09SDavid du Colombier {
148*5c47fe09SDavid du Colombier 	ulong diff;
149*5c47fe09SDavid du Colombier 	ulong x;
150*5c47fe09SDavid du Colombier 
151*5c47fe09SDavid du Colombier 	x = perfticks();
152*5c47fe09SDavid du Colombier 	diff = x - m->perf.intrts;
153*5c47fe09SDavid du Colombier 	m->perf.intrts = 0;
154*5c47fe09SDavid du Colombier 
155*5c47fe09SDavid du Colombier 	m->perf.inintr += diff;
156*5c47fe09SDavid du Colombier 	if(up == nil && m->perf.inidle > diff)
157*5c47fe09SDavid du Colombier 		m->perf.inidle -= diff;
158*5c47fe09SDavid du Colombier }
159*5c47fe09SDavid du Colombier 
160*5c47fe09SDavid du Colombier 
1615d9de2d3SDavid du Colombier /*
1625d9de2d3SDavid du Colombier  *  called by trap to handle irq interrupts.
1635d9de2d3SDavid du Colombier  *  returns true iff a clock interrupt, thus maybe reschedule.
1645d9de2d3SDavid du Colombier  */
1655d9de2d3SDavid du Colombier static int
irq(Ureg * ureg)1665d9de2d3SDavid du Colombier irq(Ureg* ureg)
1675d9de2d3SDavid du Colombier {
1685d9de2d3SDavid du Colombier 	Vctl *v;
1695d9de2d3SDavid du Colombier 	int clockintr;
170*5c47fe09SDavid du Colombier 	int found;
1715d9de2d3SDavid du Colombier 
172*5c47fe09SDavid du Colombier 	m->perf.intrts = perfticks();
1735d9de2d3SDavid du Colombier 	clockintr = 0;
174*5c47fe09SDavid du Colombier 	found = 0;
1755d9de2d3SDavid du Colombier 	for(v = vctl; v; v = v->next)
176*5c47fe09SDavid du Colombier 		if(v->cpu == m->machno && (*v->reg & v->mask) != 0){
177*5c47fe09SDavid du Colombier 			found = 1;
1785d9de2d3SDavid du Colombier 			coherence();
1795d9de2d3SDavid du Colombier 			v->f(ureg, v->a);
1805d9de2d3SDavid du Colombier 			coherence();
181*5c47fe09SDavid du Colombier 			if(v->irq == IRQclock || v->irq == IRQcntps || v->irq == IRQcntpns)
1825d9de2d3SDavid du Colombier 				clockintr = 1;
1835d9de2d3SDavid du Colombier 		}
184*5c47fe09SDavid du Colombier 	if(!found)
185*5c47fe09SDavid du Colombier 		m->spuriousintr++;
186*5c47fe09SDavid du Colombier 	intrtime();
1875d9de2d3SDavid du Colombier 	return clockintr;
1885d9de2d3SDavid du Colombier }
1895d9de2d3SDavid du Colombier 
1905d9de2d3SDavid du Colombier /*
1915d9de2d3SDavid du Colombier  * called direct from lexception.s to handle fiq interrupt.
1925d9de2d3SDavid du Colombier  */
1935d9de2d3SDavid du Colombier void
fiq(Ureg * ureg)1945d9de2d3SDavid du Colombier fiq(Ureg *ureg)
1955d9de2d3SDavid du Colombier {
1965d9de2d3SDavid du Colombier 	Vctl *v;
197*5c47fe09SDavid du Colombier 	int inintr;
1985d9de2d3SDavid du Colombier 
199*5c47fe09SDavid du Colombier 	if(m->perf.intrts)
200*5c47fe09SDavid du Colombier 		inintr = 1;
201*5c47fe09SDavid du Colombier 	else{
202*5c47fe09SDavid du Colombier 		inintr = 0;
203*5c47fe09SDavid du Colombier 		m->perf.intrts = perfticks();
204*5c47fe09SDavid du Colombier 	}
2055d9de2d3SDavid du Colombier 	v = vfiq;
2065d9de2d3SDavid du Colombier 	if(v == nil)
207*5c47fe09SDavid du Colombier 		panic("cpu%d: unexpected item in bagging area", m->machno);
2085d9de2d3SDavid du Colombier 	m->intr++;
2095d9de2d3SDavid du Colombier 	ureg->pc -= 4;
2105d9de2d3SDavid du Colombier 	coherence();
2115d9de2d3SDavid du Colombier 	v->f(ureg, v->a);
2125d9de2d3SDavid du Colombier 	coherence();
213*5c47fe09SDavid du Colombier 	if(!inintr)
214*5c47fe09SDavid du Colombier 		intrtime();
2155d9de2d3SDavid du Colombier }
2165d9de2d3SDavid du Colombier 
2175d9de2d3SDavid du Colombier void
irqenable(int irq,void (* f)(Ureg *,void *),void * a)2185d9de2d3SDavid du Colombier irqenable(int irq, void (*f)(Ureg*, void*), void* a)
2195d9de2d3SDavid du Colombier {
2205d9de2d3SDavid du Colombier 	Vctl *v;
2215d9de2d3SDavid du Colombier 	Intregs *ip;
2225d9de2d3SDavid du Colombier 	u32int *enable;
2235d9de2d3SDavid du Colombier 
2245d9de2d3SDavid du Colombier 	ip = (Intregs*)INTREGS;
2255d9de2d3SDavid du Colombier 	v = (Vctl*)malloc(sizeof(Vctl));
2265d9de2d3SDavid du Colombier 	if(v == nil)
2275d9de2d3SDavid du Colombier 		panic("irqenable: no mem");
2285d9de2d3SDavid du Colombier 	v->irq = irq;
229*5c47fe09SDavid du Colombier 	v->cpu = 0;
230*5c47fe09SDavid du Colombier 	if(irq >= IRQlocal){
231*5c47fe09SDavid du Colombier 		v->reg = (u32int*)(LOCALREGS + Localintpending) + m->machno;
232*5c47fe09SDavid du Colombier 		if(irq >= IRQmbox0)
233*5c47fe09SDavid du Colombier 			enable = (u32int*)(LOCALREGS + Localmboxint) + m->machno;
234*5c47fe09SDavid du Colombier 		else
235*5c47fe09SDavid du Colombier 			enable = (u32int*)(LOCALREGS + Localtimerint) + m->machno;
236*5c47fe09SDavid du Colombier 		v->mask = 1 << (irq - IRQlocal);
237*5c47fe09SDavid du Colombier 		v->cpu = m->machno;
238*5c47fe09SDavid du Colombier 	}else if(irq >= IRQbasic){
2395d9de2d3SDavid du Colombier 		enable = &ip->ARMenable;
2405d9de2d3SDavid du Colombier 		v->reg = &ip->ARMpending;
2415d9de2d3SDavid du Colombier 		v->mask = 1 << (irq - IRQbasic);
2425d9de2d3SDavid du Colombier 	}else{
2435d9de2d3SDavid du Colombier 		enable = &ip->GPUenable[irq/32];
2445d9de2d3SDavid du Colombier 		v->reg = &ip->GPUpending[irq/32];
2455d9de2d3SDavid du Colombier 		v->mask = 1 << (irq % 32);
2465d9de2d3SDavid du Colombier 	}
2475d9de2d3SDavid du Colombier 	v->f = f;
2485d9de2d3SDavid du Colombier 	v->a = a;
249*5c47fe09SDavid du Colombier 	lock(&vctllock);
2505d9de2d3SDavid du Colombier 	if(irq == IRQfiq){
2515d9de2d3SDavid du Colombier 		assert((ip->FIQctl & Fiqenable) == 0);
2525d9de2d3SDavid du Colombier 		assert((*enable & v->mask) == 0);
2535d9de2d3SDavid du Colombier 		vfiq = v;
2545d9de2d3SDavid du Colombier 		ip->FIQctl = Fiqenable | irq;
2555d9de2d3SDavid du Colombier 	}else{
2565d9de2d3SDavid du Colombier 		v->next = vctl;
2575d9de2d3SDavid du Colombier 		vctl = v;
258*5c47fe09SDavid du Colombier 		if(irq >= IRQmbox0){
259*5c47fe09SDavid du Colombier 			if(irq <= IRQmbox3)
260*5c47fe09SDavid du Colombier 				*enable |= 1 << (irq - IRQmbox0);
261*5c47fe09SDavid du Colombier 		}else if(irq >= IRQlocal)
262*5c47fe09SDavid du Colombier 			*enable |= 1 << (irq - IRQlocal);
263*5c47fe09SDavid du Colombier 		else
2645d9de2d3SDavid du Colombier 			*enable = v->mask;
2655d9de2d3SDavid du Colombier 	}
266*5c47fe09SDavid du Colombier 	unlock(&vctllock);
2675d9de2d3SDavid du Colombier }
2685d9de2d3SDavid du Colombier 
2695d9de2d3SDavid du Colombier static char *
trapname(int psr)2705d9de2d3SDavid du Colombier trapname(int psr)
2715d9de2d3SDavid du Colombier {
2725d9de2d3SDavid du Colombier 	char *s;
2735d9de2d3SDavid du Colombier 
2745d9de2d3SDavid du Colombier 	s = trapnames[psr & PsrMask];
2755d9de2d3SDavid du Colombier 	if(s == nil)
2765d9de2d3SDavid du Colombier 		s = "unknown trap number in psr";
2775d9de2d3SDavid du Colombier 	return s;
2785d9de2d3SDavid du Colombier }
2795d9de2d3SDavid du Colombier 
2808153b942SDavid du Colombier /* this is quite helpful during mmu and cache debugging */
2818153b942SDavid du Colombier static void
ckfaultstuck(uintptr va)2828153b942SDavid du Colombier ckfaultstuck(uintptr va)
2838153b942SDavid du Colombier {
2848153b942SDavid du Colombier 	static int cnt, lastpid;
2858153b942SDavid du Colombier 	static uintptr lastva;
2868153b942SDavid du Colombier 
2878153b942SDavid du Colombier 	if (va == lastva && up->pid == lastpid) {
2888153b942SDavid du Colombier 		++cnt;
2898153b942SDavid du Colombier 		if (cnt >= 2)
2908153b942SDavid du Colombier 			/* fault() isn't fixing the underlying cause */
2918153b942SDavid du Colombier 			panic("fault: %d consecutive faults for va %#p",
2928153b942SDavid du Colombier 				cnt+1, va);
2938153b942SDavid du Colombier 	} else {
2948153b942SDavid du Colombier 		cnt = 0;
2958153b942SDavid du Colombier 		lastva = va;
2968153b942SDavid du Colombier 		lastpid = up->pid;
2978153b942SDavid du Colombier 	}
2988153b942SDavid du Colombier }
2998153b942SDavid du Colombier 
3005d9de2d3SDavid du Colombier /*
3015d9de2d3SDavid du Colombier  *  called by trap to handle access faults
3025d9de2d3SDavid du Colombier  */
3035d9de2d3SDavid du Colombier static void
faultarm(Ureg * ureg,uintptr va,int user,int read)3045d9de2d3SDavid du Colombier faultarm(Ureg *ureg, uintptr va, int user, int read)
3055d9de2d3SDavid du Colombier {
3065d9de2d3SDavid du Colombier 	int n, insyscall;
3075d9de2d3SDavid du Colombier 	char buf[ERRMAX];
3085d9de2d3SDavid du Colombier 
3095d9de2d3SDavid du Colombier 	if(up == nil) {
310*5c47fe09SDavid du Colombier 		//dumpregs(ureg);
311*5c47fe09SDavid du Colombier 		panic("fault: nil up in faultarm, pc %#p accessing %#p", ureg->pc, va);
3125d9de2d3SDavid du Colombier 	}
3135d9de2d3SDavid du Colombier 	insyscall = up->insyscall;
3145d9de2d3SDavid du Colombier 	up->insyscall = 1;
3158153b942SDavid du Colombier 	if (Debug)
3168153b942SDavid du Colombier 		ckfaultstuck(va);
3175d9de2d3SDavid du Colombier 
3185d9de2d3SDavid du Colombier 	n = fault(va, read);
3195d9de2d3SDavid du Colombier 	if(n < 0){
3205d9de2d3SDavid du Colombier 		if(!user){
3215d9de2d3SDavid du Colombier 			dumpregs(ureg);
3225d9de2d3SDavid du Colombier 			panic("fault: kernel accessing %#p", va);
3235d9de2d3SDavid du Colombier 		}
3245d9de2d3SDavid du Colombier 		/* don't dump registers; programs suicide all the time */
3255d9de2d3SDavid du Colombier 		snprint(buf, sizeof buf, "sys: trap: fault %s va=%#p",
3265d9de2d3SDavid du Colombier 			read? "read": "write", va);
3275d9de2d3SDavid du Colombier 		postnote(up, 1, buf, NDebug);
3285d9de2d3SDavid du Colombier 	}
3295d9de2d3SDavid du Colombier 	up->insyscall = insyscall;
3305d9de2d3SDavid du Colombier }
3315d9de2d3SDavid du Colombier 
3325d9de2d3SDavid du Colombier /*
3335d9de2d3SDavid du Colombier  *  returns 1 if the instruction writes memory, 0 otherwise
3345d9de2d3SDavid du Colombier  */
3355d9de2d3SDavid du Colombier int
writetomem(ulong inst)3365d9de2d3SDavid du Colombier writetomem(ulong inst)
3375d9de2d3SDavid du Colombier {
3385d9de2d3SDavid du Colombier 	/* swap always write memory */
3395d9de2d3SDavid du Colombier 	if((inst & 0x0FC00000) == 0x01000000)
3405d9de2d3SDavid du Colombier 		return 1;
3415d9de2d3SDavid du Colombier 
3425d9de2d3SDavid du Colombier 	/* loads and stores are distinguished by bit 20 */
3435d9de2d3SDavid du Colombier 	if(inst & (1<<20))
3445d9de2d3SDavid du Colombier 		return 0;
3455d9de2d3SDavid du Colombier 
3465d9de2d3SDavid du Colombier 	return 1;
3475d9de2d3SDavid du Colombier }
3485d9de2d3SDavid du Colombier 
3495d9de2d3SDavid du Colombier /*
3505d9de2d3SDavid du Colombier  *  here on all exceptions other than syscall (SWI) and fiq
3515d9de2d3SDavid du Colombier  */
3525d9de2d3SDavid du Colombier void
trap(Ureg * ureg)3535d9de2d3SDavid du Colombier trap(Ureg *ureg)
3545d9de2d3SDavid du Colombier {
3555d9de2d3SDavid du Colombier 	int clockintr, user, x, rv, rem;
3565d9de2d3SDavid du Colombier 	ulong inst, fsr;
3575d9de2d3SDavid du Colombier 	uintptr va;
3585d9de2d3SDavid du Colombier 	char buf[ERRMAX];
3595d9de2d3SDavid du Colombier 
3605d9de2d3SDavid du Colombier 	assert(!islo());
3615d9de2d3SDavid du Colombier 	if(up != nil)
3625d9de2d3SDavid du Colombier 		rem = ((char*)ureg)-up->kstack;
3635d9de2d3SDavid du Colombier 	else
3645d9de2d3SDavid du Colombier 		rem = ((char*)ureg)-((char*)m+sizeof(Mach));
3655d9de2d3SDavid du Colombier 	if(rem < 256) {
3665d9de2d3SDavid du Colombier 		iprint("trap: %d stack bytes left, up %#p ureg %#p at pc %#lux\n",
3675d9de2d3SDavid du Colombier 			rem, up, ureg, ureg->pc);
3685d9de2d3SDavid du Colombier 		delay(1000);
3695d9de2d3SDavid du Colombier 		dumpstack();
3705d9de2d3SDavid du Colombier 		panic("trap: %d stack bytes left, up %#p ureg %#p at pc %#lux",
3715d9de2d3SDavid du Colombier 			rem, up, ureg, ureg->pc);
3725d9de2d3SDavid du Colombier 	}
3735d9de2d3SDavid du Colombier 
3745d9de2d3SDavid du Colombier 	user = (ureg->psr & PsrMask) == PsrMusr;
3755d9de2d3SDavid du Colombier 	if(user){
3765d9de2d3SDavid du Colombier 		up->dbgreg = ureg;
3775d9de2d3SDavid du Colombier 		cycles(&up->kentry);
3785d9de2d3SDavid du Colombier 	}
3795d9de2d3SDavid du Colombier 
3805d9de2d3SDavid du Colombier 	/*
3815d9de2d3SDavid du Colombier 	 * All interrupts/exceptions should be resumed at ureg->pc-4,
3825d9de2d3SDavid du Colombier 	 * except for Data Abort which resumes at ureg->pc-8.
3835d9de2d3SDavid du Colombier 	 */
3845d9de2d3SDavid du Colombier 	if(ureg->type == (PsrMabt+1))
3855d9de2d3SDavid du Colombier 		ureg->pc -= 8;
3865d9de2d3SDavid du Colombier 	else
3875d9de2d3SDavid du Colombier 		ureg->pc -= 4;
3885d9de2d3SDavid du Colombier 
3895d9de2d3SDavid du Colombier 	clockintr = 0;		/* if set, may call sched() before return */
3905d9de2d3SDavid du Colombier 	switch(ureg->type){
3915d9de2d3SDavid du Colombier 	default:
392*5c47fe09SDavid du Colombier 		panic("unknown trap; type %#lux, psr mode %#lux pc %lux", ureg->type,
393*5c47fe09SDavid du Colombier 			ureg->psr & PsrMask, ureg->pc);
3945d9de2d3SDavid du Colombier 		break;
3955d9de2d3SDavid du Colombier 	case PsrMirq:
3965d9de2d3SDavid du Colombier 		clockintr = irq(ureg);
3975d9de2d3SDavid du Colombier 		m->intr++;
3985d9de2d3SDavid du Colombier 		break;
3995d9de2d3SDavid du Colombier 	case PsrMabt:			/* prefetch fault */
4005d9de2d3SDavid du Colombier 		x = ifsrget();
4015d9de2d3SDavid du Colombier 		fsr = (x>>7) & 0x8 | x & 0x7;
4025d9de2d3SDavid du Colombier 		switch(fsr){
4035d9de2d3SDavid du Colombier 		case 0x02:		/* instruction debug event (BKPT) */
404*5c47fe09SDavid du Colombier 			if(user)
405*5c47fe09SDavid du Colombier 				postnote(up, 1, "sys: breakpoint", NDebug);
406*5c47fe09SDavid du Colombier 			else{
4075d9de2d3SDavid du Colombier 				iprint("kernel bkpt: pc %#lux inst %#ux\n",
4085d9de2d3SDavid du Colombier 					ureg->pc, *(u32int*)ureg->pc);
4095d9de2d3SDavid du Colombier 				panic("kernel bkpt");
4105d9de2d3SDavid du Colombier 			}
4115d9de2d3SDavid du Colombier 			break;
4125d9de2d3SDavid du Colombier 		default:
4135d9de2d3SDavid du Colombier 			faultarm(ureg, ureg->pc, user, 1);
4145d9de2d3SDavid du Colombier 			break;
4155d9de2d3SDavid du Colombier 		}
4165d9de2d3SDavid du Colombier 		break;
4175d9de2d3SDavid du Colombier 	case PsrMabt+1:			/* data fault */
4185d9de2d3SDavid du Colombier 		va = farget();
4195d9de2d3SDavid du Colombier 		inst = *(ulong*)(ureg->pc);
4205d9de2d3SDavid du Colombier 		/* bits 12 and 10 have to be concatenated with status */
4215d9de2d3SDavid du Colombier 		x = fsrget();
4225d9de2d3SDavid du Colombier 		fsr = (x>>7) & 0x20 | (x>>6) & 0x10 | x & 0xf;
4235d9de2d3SDavid du Colombier 		switch(fsr){
4245d9de2d3SDavid du Colombier 		default:
4255d9de2d3SDavid du Colombier 		case 0xa:		/* ? was under external abort */
4265d9de2d3SDavid du Colombier 			panic("unknown data fault, 6b fsr %#lux", fsr);
4275d9de2d3SDavid du Colombier 			break;
4285d9de2d3SDavid du Colombier 		case 0x0:
4295d9de2d3SDavid du Colombier 			panic("vector exception at %#lux", ureg->pc);
4305d9de2d3SDavid du Colombier 			break;
4315d9de2d3SDavid du Colombier 		case 0x1:		/* alignment fault */
4325d9de2d3SDavid du Colombier 		case 0x3:		/* access flag fault (section) */
4335d9de2d3SDavid du Colombier 			if(user){
4345d9de2d3SDavid du Colombier 				snprint(buf, sizeof buf,
435*5c47fe09SDavid du Colombier 					"sys: alignment: va %#p", va);
4365d9de2d3SDavid du Colombier 				postnote(up, 1, buf, NDebug);
4375d9de2d3SDavid du Colombier 			} else
4385d9de2d3SDavid du Colombier 				panic("kernel alignment: pc %#lux va %#p", ureg->pc, va);
4395d9de2d3SDavid du Colombier 			break;
4405d9de2d3SDavid du Colombier 		case 0x2:
4415d9de2d3SDavid du Colombier 			panic("terminal exception at %#lux", ureg->pc);
4425d9de2d3SDavid du Colombier 			break;
4435d9de2d3SDavid du Colombier 		case 0x4:		/* icache maint fault */
4445d9de2d3SDavid du Colombier 		case 0x6:		/* access flag fault (page) */
4455d9de2d3SDavid du Colombier 		case 0x8:		/* precise external abort, non-xlat'n */
4465d9de2d3SDavid du Colombier 		case 0x28:
4475d9de2d3SDavid du Colombier 		case 0xc:		/* l1 translation, precise ext. abort */
4485d9de2d3SDavid du Colombier 		case 0x2c:
4495d9de2d3SDavid du Colombier 		case 0xe:		/* l2 translation, precise ext. abort */
4505d9de2d3SDavid du Colombier 		case 0x2e:
4515d9de2d3SDavid du Colombier 		case 0x16:		/* imprecise ext. abort, non-xlt'n */
4525d9de2d3SDavid du Colombier 		case 0x36:
4535d9de2d3SDavid du Colombier 			panic("external abort %#lux pc %#lux addr %#p",
4545d9de2d3SDavid du Colombier 				fsr, ureg->pc, va);
4555d9de2d3SDavid du Colombier 			break;
4565d9de2d3SDavid du Colombier 		case 0x1c:		/* l1 translation, precise parity err */
4575d9de2d3SDavid du Colombier 		case 0x1e:		/* l2 translation, precise parity err */
4585d9de2d3SDavid du Colombier 		case 0x18:		/* imprecise parity or ecc err */
4595d9de2d3SDavid du Colombier 			panic("translation parity error %#lux pc %#lux addr %#p",
4605d9de2d3SDavid du Colombier 				fsr, ureg->pc, va);
4615d9de2d3SDavid du Colombier 			break;
4625d9de2d3SDavid du Colombier 		case 0x5:		/* translation fault, no section entry */
4635d9de2d3SDavid du Colombier 		case 0x7:		/* translation fault, no page entry */
4645d9de2d3SDavid du Colombier 			faultarm(ureg, va, user, !writetomem(inst));
4655d9de2d3SDavid du Colombier 			break;
4665d9de2d3SDavid du Colombier 		case 0x9:
4675d9de2d3SDavid du Colombier 		case 0xb:
4685d9de2d3SDavid du Colombier 			/* domain fault, accessing something we shouldn't */
4695d9de2d3SDavid du Colombier 			if(user){
4705d9de2d3SDavid du Colombier 				snprint(buf, sizeof buf,
471*5c47fe09SDavid du Colombier 					"sys: access violation: va %#p", va);
4725d9de2d3SDavid du Colombier 				postnote(up, 1, buf, NDebug);
4735d9de2d3SDavid du Colombier 			} else
4745d9de2d3SDavid du Colombier 				panic("kernel access violation: pc %#lux va %#p",
4755d9de2d3SDavid du Colombier 					ureg->pc, va);
4765d9de2d3SDavid du Colombier 			break;
4775d9de2d3SDavid du Colombier 		case 0xd:
4785d9de2d3SDavid du Colombier 		case 0xf:
4795d9de2d3SDavid du Colombier 			/* permission error, copy on write or real permission error */
4805d9de2d3SDavid du Colombier 			faultarm(ureg, va, user, !writetomem(inst));
4815d9de2d3SDavid du Colombier 			break;
4825d9de2d3SDavid du Colombier 		}
4835d9de2d3SDavid du Colombier 		break;
4845d9de2d3SDavid du Colombier 	case PsrMund:			/* undefined instruction */
4855d9de2d3SDavid du Colombier 		if(user){
4865d9de2d3SDavid du Colombier 			if(seg(up, ureg->pc, 0) != nil &&
4875d9de2d3SDavid du Colombier 			   *(u32int*)ureg->pc == 0xD1200070)
4885d9de2d3SDavid du Colombier 				postnote(up, 1, "sys: breakpoint", NDebug);
4895d9de2d3SDavid du Colombier 			else{
4905d9de2d3SDavid du Colombier 				/* look for floating point instructions to interpret */
4915d9de2d3SDavid du Colombier 				rv = fpuemu(ureg);
492*5c47fe09SDavid du Colombier 				if(rv == 0)
493*5c47fe09SDavid du Colombier 					postnote(up, 1, "sys: undefined instruction", NDebug);
4945d9de2d3SDavid du Colombier 			}
4955d9de2d3SDavid du Colombier 		}else{
4965d9de2d3SDavid du Colombier 			if (ureg->pc & 3) {
4975d9de2d3SDavid du Colombier 				iprint("rounding fault pc %#lux down to word\n",
4985d9de2d3SDavid du Colombier 					ureg->pc);
4995d9de2d3SDavid du Colombier 				ureg->pc &= ~3;
5005d9de2d3SDavid du Colombier 			}
5015d9de2d3SDavid du Colombier 			iprint("undefined instruction: pc %#lux inst %#ux\n",
5025d9de2d3SDavid du Colombier 				ureg->pc, *(u32int*)ureg->pc);
5035d9de2d3SDavid du Colombier 			panic("undefined instruction");
5045d9de2d3SDavid du Colombier 		}
5055d9de2d3SDavid du Colombier 		break;
5065d9de2d3SDavid du Colombier 	}
5075d9de2d3SDavid du Colombier 	splhi();
5085d9de2d3SDavid du Colombier 
5095d9de2d3SDavid du Colombier 	/* delaysched set because we held a lock or because our quantum ended */
5105d9de2d3SDavid du Colombier 	if(up && up->delaysched && clockintr){
5115d9de2d3SDavid du Colombier 		sched();		/* can cause more traps */
5125d9de2d3SDavid du Colombier 		splhi();
5135d9de2d3SDavid du Colombier 	}
5145d9de2d3SDavid du Colombier 
5155d9de2d3SDavid du Colombier 	if(user){
5165d9de2d3SDavid du Colombier 		if(up->procctl || up->nnote)
5175d9de2d3SDavid du Colombier 			notify(ureg);
5185d9de2d3SDavid du Colombier 		kexit(ureg);
5195d9de2d3SDavid du Colombier 	}
5205d9de2d3SDavid du Colombier }
5215d9de2d3SDavid du Colombier 
5225d9de2d3SDavid du Colombier int
isvalidaddr(void * v)5235d9de2d3SDavid du Colombier isvalidaddr(void *v)
5245d9de2d3SDavid du Colombier {
5255d9de2d3SDavid du Colombier 	return (uintptr)v >= KZERO;
5265d9de2d3SDavid du Colombier }
5275d9de2d3SDavid du Colombier 
5285d9de2d3SDavid du Colombier static void
dumplongs(char * msg,ulong * v,int n)5295d9de2d3SDavid du Colombier dumplongs(char *msg, ulong *v, int n)
5305d9de2d3SDavid du Colombier {
5315d9de2d3SDavid du Colombier 	int i, l;
5325d9de2d3SDavid du Colombier 
5335d9de2d3SDavid du Colombier 	l = 0;
5345d9de2d3SDavid du Colombier 	iprint("%s at %.8p: ", msg, v);
5355d9de2d3SDavid du Colombier 	for(i=0; i<n; i++){
5365d9de2d3SDavid du Colombier 		if(l >= 4){
5375d9de2d3SDavid du Colombier 			iprint("\n    %.8p: ", v);
5385d9de2d3SDavid du Colombier 			l = 0;
5395d9de2d3SDavid du Colombier 		}
5405d9de2d3SDavid du Colombier 		if(isvalidaddr(v)){
5415d9de2d3SDavid du Colombier 			iprint(" %.8lux", *v++);
5425d9de2d3SDavid du Colombier 			l++;
5435d9de2d3SDavid du Colombier 		}else{
5445d9de2d3SDavid du Colombier 			iprint(" invalid");
5455d9de2d3SDavid du Colombier 			break;
5465d9de2d3SDavid du Colombier 		}
5475d9de2d3SDavid du Colombier 	}
5485d9de2d3SDavid du Colombier 	iprint("\n");
5495d9de2d3SDavid du Colombier }
5505d9de2d3SDavid du Colombier 
5515d9de2d3SDavid du Colombier static void
dumpstackwithureg(Ureg * ureg)5525d9de2d3SDavid du Colombier dumpstackwithureg(Ureg *ureg)
5535d9de2d3SDavid du Colombier {
5545d9de2d3SDavid du Colombier 	uintptr l, i, v, estack;
5555d9de2d3SDavid du Colombier 	u32int *p;
5565d9de2d3SDavid du Colombier 	char *s;
5575d9de2d3SDavid du Colombier 
5585d9de2d3SDavid du Colombier 	if((s = getconf("*nodumpstack")) != nil && strcmp(s, "0") != 0){
5595d9de2d3SDavid du Colombier 		iprint("dumpstack disabled\n");
5605d9de2d3SDavid du Colombier 		return;
5615d9de2d3SDavid du Colombier 	}
5625d9de2d3SDavid du Colombier 	iprint("ktrace /kernel/path %#.8lux %#.8lux %#.8lux # pc, sp, link\n",
5635d9de2d3SDavid du Colombier 		ureg->pc, ureg->sp, ureg->r14);
5645d9de2d3SDavid du Colombier 	delay(2000);
5655d9de2d3SDavid du Colombier 	i = 0;
5665d9de2d3SDavid du Colombier 	if(up != nil && (uintptr)&l <= (uintptr)up->kstack+KSTACK)
5675d9de2d3SDavid du Colombier 		estack = (uintptr)up->kstack+KSTACK;
5685d9de2d3SDavid du Colombier 	else if((uintptr)&l >= (uintptr)m->stack
5695d9de2d3SDavid du Colombier 	     && (uintptr)&l <= (uintptr)m+MACHSIZE)
5705d9de2d3SDavid du Colombier 		estack = (uintptr)m+MACHSIZE;
5715d9de2d3SDavid du Colombier 	else{
5725d9de2d3SDavid du Colombier 		if(up != nil)
5735d9de2d3SDavid du Colombier 			iprint("&up->kstack %#p &l %#p\n", up->kstack, &l);
5745d9de2d3SDavid du Colombier 		else
5755d9de2d3SDavid du Colombier 			iprint("&m %#p &l %#p\n", m, &l);
5765d9de2d3SDavid du Colombier 		return;
5775d9de2d3SDavid du Colombier 	}
5785d9de2d3SDavid du Colombier 	for(l = (uintptr)&l; l < estack; l += sizeof(uintptr)){
5795d9de2d3SDavid du Colombier 		v = *(uintptr*)l;
5805d9de2d3SDavid du Colombier 		if(KTZERO < v && v < (uintptr)etext && !(v & 3)){
5815d9de2d3SDavid du Colombier 			v -= sizeof(u32int);		/* back up an instr */
5825d9de2d3SDavid du Colombier 			p = (u32int*)v;
5835d9de2d3SDavid du Colombier 			if((*p & 0x0f000000) == 0x0b000000){	/* BL instr? */
5845d9de2d3SDavid du Colombier 				iprint("%#8.8lux=%#8.8lux ", l, v);
5855d9de2d3SDavid du Colombier 				i++;
5865d9de2d3SDavid du Colombier 			}
5875d9de2d3SDavid du Colombier 		}
5885d9de2d3SDavid du Colombier 		if(i == 4){
5895d9de2d3SDavid du Colombier 			i = 0;
5905d9de2d3SDavid du Colombier 			iprint("\n");
5915d9de2d3SDavid du Colombier 		}
5925d9de2d3SDavid du Colombier 	}
5935d9de2d3SDavid du Colombier 	if(i)
5945d9de2d3SDavid du Colombier 		iprint("\n");
5955d9de2d3SDavid du Colombier }
5965d9de2d3SDavid du Colombier 
5975d9de2d3SDavid du Colombier /*
5985d9de2d3SDavid du Colombier  * Fill in enough of Ureg to get a stack trace, and call a function.
5995d9de2d3SDavid du Colombier  * Used by debugging interface rdb.
6005d9de2d3SDavid du Colombier  */
601*5c47fe09SDavid du Colombier 
602*5c47fe09SDavid du Colombier static void
getpcsp(ulong * pc,ulong * sp)603*5c47fe09SDavid du Colombier getpcsp(ulong *pc, ulong *sp)
604*5c47fe09SDavid du Colombier {
605*5c47fe09SDavid du Colombier 	*pc = getcallerpc(&pc);
606*5c47fe09SDavid du Colombier 	*sp = (ulong)&pc-4;
607*5c47fe09SDavid du Colombier }
608*5c47fe09SDavid du Colombier 
6095d9de2d3SDavid du Colombier void
callwithureg(void (* fn)(Ureg *))6105d9de2d3SDavid du Colombier callwithureg(void (*fn)(Ureg*))
6115d9de2d3SDavid du Colombier {
6125d9de2d3SDavid du Colombier 	Ureg ureg;
6135d9de2d3SDavid du Colombier 
614*5c47fe09SDavid du Colombier 	getpcsp((ulong*)&ureg.pc, (ulong*)&ureg.sp);
615*5c47fe09SDavid du Colombier 	ureg.r14 = getcallerpc(&fn);
6165d9de2d3SDavid du Colombier 	fn(&ureg);
6175d9de2d3SDavid du Colombier }
6185d9de2d3SDavid du Colombier 
6195d9de2d3SDavid du Colombier void
dumpstack(void)6205d9de2d3SDavid du Colombier dumpstack(void)
6215d9de2d3SDavid du Colombier {
6225d9de2d3SDavid du Colombier 	callwithureg(dumpstackwithureg);
6235d9de2d3SDavid du Colombier }
6245d9de2d3SDavid du Colombier 
6255d9de2d3SDavid du Colombier void
dumpregs(Ureg * ureg)6265d9de2d3SDavid du Colombier dumpregs(Ureg* ureg)
6275d9de2d3SDavid du Colombier {
6285d9de2d3SDavid du Colombier 	int s;
6295d9de2d3SDavid du Colombier 
6305d9de2d3SDavid du Colombier 	if (ureg == nil) {
6315d9de2d3SDavid du Colombier 		iprint("trap: no user process\n");
6325d9de2d3SDavid du Colombier 		return;
6335d9de2d3SDavid du Colombier 	}
6345d9de2d3SDavid du Colombier 	s = splhi();
6355d9de2d3SDavid du Colombier 	iprint("trap: %s", trapname(ureg->type));
6365d9de2d3SDavid du Colombier 	if(ureg != nil && (ureg->psr & PsrMask) != PsrMsvc)
6375d9de2d3SDavid du Colombier 		iprint(" in %s", trapname(ureg->psr));
6385d9de2d3SDavid du Colombier 	iprint("\n");
6395d9de2d3SDavid du Colombier 	iprint("psr %8.8lux type %2.2lux pc %8.8lux link %8.8lux\n",
6405d9de2d3SDavid du Colombier 		ureg->psr, ureg->type, ureg->pc, ureg->link);
6415d9de2d3SDavid du Colombier 	iprint("R14 %8.8lux R13 %8.8lux R12 %8.8lux R11 %8.8lux R10 %8.8lux\n",
6425d9de2d3SDavid du Colombier 		ureg->r14, ureg->r13, ureg->r12, ureg->r11, ureg->r10);
6435d9de2d3SDavid du Colombier 	iprint("R9  %8.8lux R8  %8.8lux R7  %8.8lux R6  %8.8lux R5  %8.8lux\n",
6445d9de2d3SDavid du Colombier 		ureg->r9, ureg->r8, ureg->r7, ureg->r6, ureg->r5);
6455d9de2d3SDavid du Colombier 	iprint("R4  %8.8lux R3  %8.8lux R2  %8.8lux R1  %8.8lux R0  %8.8lux\n",
6465d9de2d3SDavid du Colombier 		ureg->r4, ureg->r3, ureg->r2, ureg->r1, ureg->r0);
6475d9de2d3SDavid du Colombier 	iprint("stack is at %#p\n", ureg);
6485d9de2d3SDavid du Colombier 	iprint("pc %#lux link %#lux\n", ureg->pc, ureg->link);
6495d9de2d3SDavid du Colombier 
6505d9de2d3SDavid du Colombier 	if(up)
6515d9de2d3SDavid du Colombier 		iprint("user stack: %#p-%#p\n", up->kstack, up->kstack+KSTACK-4);
6525d9de2d3SDavid du Colombier 	else
6535d9de2d3SDavid du Colombier 		iprint("kernel stack: %8.8lux-%8.8lux\n",
6545d9de2d3SDavid du Colombier 			(ulong)(m+1), (ulong)m+BY2PG-4);
6555d9de2d3SDavid du Colombier 	dumplongs("stack", (ulong *)(ureg + 1), 16);
6565d9de2d3SDavid du Colombier 	delay(2000);
6575d9de2d3SDavid du Colombier 	dumpstack();
6585d9de2d3SDavid du Colombier 	splx(s);
6595d9de2d3SDavid du Colombier }
660