xref: /plan9-contrib/sys/src/9/kw/trap.c (revision 6bbfed0d85c6d7248503ef0614d0f1e40438b735)
1154abd99SDavid du Colombier /*
2154abd99SDavid du Colombier  * sheevaplug traps, exceptions, interrupts, system calls.
3154abd99SDavid du Colombier  */
4154abd99SDavid du Colombier #include "u.h"
5154abd99SDavid du Colombier #include "../port/lib.h"
6154abd99SDavid du Colombier #include "mem.h"
7154abd99SDavid du Colombier #include "dat.h"
8154abd99SDavid du Colombier #include "fns.h"
9154abd99SDavid du Colombier #include "io.h"
10154abd99SDavid du Colombier #include "ureg.h"
11154abd99SDavid du Colombier #include "../port/error.h"
12154abd99SDavid du Colombier 
13154abd99SDavid du Colombier #include "arm.h"
14154abd99SDavid du Colombier 
15154abd99SDavid du Colombier enum {
168153b942SDavid du Colombier 	Debug = 0,
178153b942SDavid du Colombier 
18304cb050SDavid du Colombier 	Ntimevec = 20,			/* # of time buckets for each intr */
19304cb050SDavid du Colombier 	Nvecs = 256,
20154abd99SDavid du Colombier };
21154abd99SDavid du Colombier 
22154abd99SDavid du Colombier extern int notify(Ureg*);
23154abd99SDavid du Colombier 
24154abd99SDavid du Colombier extern int ldrexvalid;
25154abd99SDavid du Colombier 
26154abd99SDavid du Colombier typedef struct Vctl Vctl;
27154abd99SDavid du Colombier typedef struct Vctl {
28154abd99SDavid du Colombier 	Vctl*	next;		/* handlers on this vector */
29154abd99SDavid du Colombier 	char	*name;		/* of driver, xallocated */
30154abd99SDavid du Colombier 	void	(*f)(Ureg*, void*);	/* handler to call */
31154abd99SDavid du Colombier 	void*	a;		/* argument to call it with */
32154abd99SDavid du Colombier } Vctl;
33154abd99SDavid du Colombier 
34154abd99SDavid du Colombier static Lock vctllock;
35154abd99SDavid du Colombier static Vctl* vctl[32];
36154abd99SDavid du Colombier 
37154abd99SDavid du Colombier uvlong ninterrupt;
38154abd99SDavid du Colombier uvlong ninterruptticks;
39304cb050SDavid du Colombier ulong intrtimes[Nvecs][Ntimevec];
40154abd99SDavid du Colombier 
41154abd99SDavid du Colombier typedef struct Handler Handler;
42154abd99SDavid du Colombier struct Handler {
43154abd99SDavid du Colombier 	void	(*r)(Ureg*, void*);
44154abd99SDavid du Colombier 	void	*a;
45154abd99SDavid du Colombier 	char	name[KNAMELEN];
46154abd99SDavid du Colombier };
47154abd99SDavid du Colombier 
48154abd99SDavid du Colombier static Handler irqlo[32];
49154abd99SDavid du Colombier static Handler irqhi[32];
50154abd99SDavid du Colombier static Handler irqbridge[32];
51154abd99SDavid du Colombier static Lock irqlock;
52154abd99SDavid du Colombier static int probing, trapped;
53154abd99SDavid du Colombier 
54154abd99SDavid du Colombier typedef struct Irq Irq;
55154abd99SDavid du Colombier struct Irq {
56154abd99SDavid du Colombier 	ulong	*irq;
57154abd99SDavid du Colombier 	ulong	*irqmask;
58154abd99SDavid du Colombier 	Handler	*irqvec;
59154abd99SDavid du Colombier 	int	nirqvec;
60154abd99SDavid du Colombier 	char	*name;
61154abd99SDavid du Colombier };
627365b686SDavid du Colombier /* irq and irqmask are filled in by trapinit */
63154abd99SDavid du Colombier static Irq irqs[] = {
647365b686SDavid du Colombier [Irqlo]		{nil, nil, irqlo,	nelem(irqlo),	"lo"},
657365b686SDavid du Colombier [Irqhi]		{nil, nil, irqhi,	nelem(irqhi),	"hi"},
667365b686SDavid du Colombier [Irqbridge]	{nil, nil, irqbridge,	nelem(irqbridge), "bridge"},
67154abd99SDavid du Colombier };
68154abd99SDavid du Colombier 
69154abd99SDavid du Colombier /*
70154abd99SDavid du Colombier  *  keep histogram of interrupt service times
71154abd99SDavid du Colombier  */
72154abd99SDavid du Colombier void
intrtime(Mach *,int vno)73154abd99SDavid du Colombier intrtime(Mach*, int vno)
74154abd99SDavid du Colombier {
75154abd99SDavid du Colombier 	ulong diff, x;
76154abd99SDavid du Colombier 
77154abd99SDavid du Colombier 	if (m == nil)
78154abd99SDavid du Colombier 		return;
79154abd99SDavid du Colombier 	x = perfticks();
80154abd99SDavid du Colombier 	diff = x - m->perf.intrts;
81154abd99SDavid du Colombier 	m->perf.intrts = x;
82154abd99SDavid du Colombier 
83154abd99SDavid du Colombier 	m->perf.inintr += diff;
84154abd99SDavid du Colombier 	if(up == nil && m->perf.inidle > diff)
85154abd99SDavid du Colombier 		m->perf.inidle -= diff;
86154abd99SDavid du Colombier 
87154abd99SDavid du Colombier 	if (m->cpuhz == 0)			/* not set yet? */
88154abd99SDavid du Colombier 		return;
89154abd99SDavid du Colombier 	diff /= (m->cpuhz/1000000)*100;		/* quantum = 100µsec */
90154abd99SDavid du Colombier 	if(diff >= Ntimevec)
91154abd99SDavid du Colombier 		diff = Ntimevec-1;
92304cb050SDavid du Colombier 	assert(vno >= 0 && vno < Nvecs);
93154abd99SDavid du Colombier 	intrtimes[vno][diff]++;
94154abd99SDavid du Colombier }
95154abd99SDavid du Colombier 
96154abd99SDavid du Colombier void
intrfmtcounts(char * s,char * se)97154abd99SDavid du Colombier intrfmtcounts(char *s, char *se)
98154abd99SDavid du Colombier {
99154abd99SDavid du Colombier 	USED(s, se);
100154abd99SDavid du Colombier }
101154abd99SDavid du Colombier 
102154abd99SDavid du Colombier static void
dumpcounts(void)103154abd99SDavid du Colombier dumpcounts(void)
104154abd99SDavid du Colombier {
105154abd99SDavid du Colombier }
106154abd99SDavid du Colombier 
107154abd99SDavid du Colombier void
intrclear(int sort,int v)108154abd99SDavid du Colombier intrclear(int sort, int v)
109154abd99SDavid du Colombier {
110154abd99SDavid du Colombier 	*irqs[sort].irq = ~(1 << v);
111154abd99SDavid du Colombier }
112154abd99SDavid du Colombier 
113154abd99SDavid du Colombier void
intrmask(int sort,int v)114154abd99SDavid du Colombier intrmask(int sort, int v)
115154abd99SDavid du Colombier {
116154abd99SDavid du Colombier 	*irqs[sort].irqmask &= ~(1 << v);
117154abd99SDavid du Colombier }
118154abd99SDavid du Colombier 
119154abd99SDavid du Colombier void
intrunmask(int sort,int v)120154abd99SDavid du Colombier intrunmask(int sort, int v)
121154abd99SDavid du Colombier {
122154abd99SDavid du Colombier 	*irqs[sort].irqmask |= 1 << v;
123154abd99SDavid du Colombier }
124154abd99SDavid du Colombier 
125154abd99SDavid du Colombier static void
maskallints(void)126154abd99SDavid du Colombier maskallints(void)
127154abd99SDavid du Colombier {
1287365b686SDavid du Colombier 	CpucsReg *cpu = (CpucsReg *)soc.cpu;
1297365b686SDavid du Colombier 	IntrReg *intr;
1307365b686SDavid du Colombier 
131154abd99SDavid du Colombier 	/* no fiq or ep in use */
1327365b686SDavid du Colombier 	intr = (IntrReg *)soc.intr;
1337365b686SDavid du Colombier 	intr->lo.irqmask = 0;
1347365b686SDavid du Colombier 	intr->hi.irqmask = 0;
1357365b686SDavid du Colombier 	cpu->irqmask = 0;
136a7a38e3eSDavid du Colombier 	coherence();
137154abd99SDavid du Colombier }
138154abd99SDavid du Colombier 
139154abd99SDavid du Colombier void
intrset(Handler * h,void (* f)(Ureg *,void *),void * a,char * name)140154abd99SDavid du Colombier intrset(Handler *h, void (*f)(Ureg*, void*), void *a, char *name)
141154abd99SDavid du Colombier {
142154abd99SDavid du Colombier 	if(h->r != nil) {
143154abd99SDavid du Colombier //		iprint("duplicate irq: %s (%#p)\n", h->name, h->r);
144154abd99SDavid du Colombier 		return;
145154abd99SDavid du Colombier 	}
146154abd99SDavid du Colombier 	h->r = f;
147154abd99SDavid du Colombier 	h->a = a;
148154abd99SDavid du Colombier 	strncpy(h->name, name, KNAMELEN-1);
149154abd99SDavid du Colombier 	h->name[KNAMELEN-1] = 0;
150154abd99SDavid du Colombier }
151154abd99SDavid du Colombier 
152154abd99SDavid du Colombier void
intrunset(Handler * h)153154abd99SDavid du Colombier intrunset(Handler *h)
154154abd99SDavid du Colombier {
155154abd99SDavid du Colombier 	h->r = nil;
156154abd99SDavid du Colombier 	h->a = nil;
157154abd99SDavid du Colombier 	h->name[0] = 0;
158154abd99SDavid du Colombier }
159154abd99SDavid du Colombier 
160154abd99SDavid du Colombier void
intrdel(Handler * h,void (* f)(Ureg *,void *),void * a,char * name)161154abd99SDavid du Colombier intrdel(Handler *h, void (*f)(Ureg*, void*), void *a, char *name)
162154abd99SDavid du Colombier {
163154abd99SDavid du Colombier 	if(h->r != f || h->a != a || strcmp(h->name, name) != 0)
164154abd99SDavid du Colombier 		return;
165154abd99SDavid du Colombier 	intrunset(h);
166154abd99SDavid du Colombier }
167154abd99SDavid du Colombier 
168154abd99SDavid du Colombier void
intrenable(int sort,int v,void (* f)(Ureg *,void *),void * a,char * name)169154abd99SDavid du Colombier intrenable(int sort, int v, void (*f)(Ureg*, void*), void *a, char *name)
170154abd99SDavid du Colombier {
171154abd99SDavid du Colombier //iprint("enabling intr %d vec %d for %s\n", sort, v, name);
172154abd99SDavid du Colombier 	ilock(&irqlock);
173154abd99SDavid du Colombier 	intrset(&irqs[sort].irqvec[v], f, a, name);
174154abd99SDavid du Colombier 	intrunmask(sort, v);
175154abd99SDavid du Colombier 	iunlock(&irqlock);
176154abd99SDavid du Colombier }
177154abd99SDavid du Colombier 
178154abd99SDavid du Colombier void
intrdisable(int sort,int v,void (* f)(Ureg *,void *),void * a,char * name)179154abd99SDavid du Colombier intrdisable(int sort, int v, void (*f)(Ureg*, void*), void* a, char *name)
180154abd99SDavid du Colombier {
181154abd99SDavid du Colombier 	ilock(&irqlock);
182154abd99SDavid du Colombier 	intrdel(&irqs[sort].irqvec[v], f, a, name);
183154abd99SDavid du Colombier 	intrmask(sort, v);
184154abd99SDavid du Colombier 	iunlock(&irqlock);
185154abd99SDavid du Colombier }
186154abd99SDavid du Colombier 
187154abd99SDavid du Colombier /*
188154abd99SDavid du Colombier  *  called by trap to handle interrupts
189154abd99SDavid du Colombier  */
190154abd99SDavid du Colombier static void
intrs(Ureg * ur,int sort)191154abd99SDavid du Colombier intrs(Ureg *ur, int sort)
192154abd99SDavid du Colombier {
193154abd99SDavid du Colombier 	int i, s;
194154abd99SDavid du Colombier 	ulong ibits;
195154abd99SDavid du Colombier 	Handler *h;
196154abd99SDavid du Colombier 	Irq irq;
197154abd99SDavid du Colombier 
198304cb050SDavid du Colombier 	assert(sort >= 0 && sort < nelem(irqs));
199154abd99SDavid du Colombier 	irq = irqs[sort];
200154abd99SDavid du Colombier 	ibits = *irq.irq;
201154abd99SDavid du Colombier 	ibits &= *irq.irqmask;
202154abd99SDavid du Colombier 
203154abd99SDavid du Colombier 	for(i = 0; i < irq.nirqvec && ibits; i++)
204154abd99SDavid du Colombier 		if(ibits & (1<<i)){
205154abd99SDavid du Colombier 			h = &irq.irqvec[i];
206154abd99SDavid du Colombier 			if(h->r != nil){
207154abd99SDavid du Colombier 				h->r(ur, h->a);
208154abd99SDavid du Colombier 				splhi();
209154abd99SDavid du Colombier 				intrtime(m, sort*32 + i);
210154abd99SDavid du Colombier 				if (sort == Irqbridge && i == IRQcputimer0)
211154abd99SDavid du Colombier 					m->inclockintr = 1;
212154abd99SDavid du Colombier 				ibits &= ~(1<<i);
213154abd99SDavid du Colombier 			}
214154abd99SDavid du Colombier 		}
215154abd99SDavid du Colombier 	if(ibits != 0) {
216154abd99SDavid du Colombier 		iprint("spurious irq%s interrupt: %8.8lux\n", irq.name, ibits);
217154abd99SDavid du Colombier 		s = splfhi();
218154abd99SDavid du Colombier 		*irq.irq &= ibits;
219a4b9e815SDavid du Colombier 		*irq.irqmask &= ~ibits;
220154abd99SDavid du Colombier 		splx(s);
221154abd99SDavid du Colombier 	}
222154abd99SDavid du Colombier }
223154abd99SDavid du Colombier 
224154abd99SDavid du Colombier void
intrhi(Ureg * ureg,void *)225154abd99SDavid du Colombier intrhi(Ureg *ureg, void*)
226154abd99SDavid du Colombier {
227154abd99SDavid du Colombier 	intrs(ureg, Irqhi);
228154abd99SDavid du Colombier }
229154abd99SDavid du Colombier 
230154abd99SDavid du Colombier void
intrbridge(Ureg * ureg,void *)231154abd99SDavid du Colombier intrbridge(Ureg *ureg, void*)
232154abd99SDavid du Colombier {
233154abd99SDavid du Colombier 	intrs(ureg, Irqbridge);
234154abd99SDavid du Colombier 	intrclear(Irqlo, IRQ0bridge);
235154abd99SDavid du Colombier }
236154abd99SDavid du Colombier 
237154abd99SDavid du Colombier void
trapinit(void)238154abd99SDavid du Colombier trapinit(void)
239154abd99SDavid du Colombier {
240154abd99SDavid du Colombier 	int i;
241154abd99SDavid du Colombier 	CpucsReg *cpu;
242154abd99SDavid du Colombier 	IntrReg *intr;
243154abd99SDavid du Colombier 	Vectorpage *page0 = (Vectorpage*)HVECTORS;
244154abd99SDavid du Colombier 
2457365b686SDavid du Colombier 	intr = (IntrReg *)soc.intr;
2467365b686SDavid du Colombier 	cpu = (CpucsReg *)soc.cpu;
2477365b686SDavid du Colombier 	irqs[Irqlo].irq = &intr->lo.irq;
2487365b686SDavid du Colombier 	irqs[Irqlo].irqmask = &intr->lo.irqmask;
2497365b686SDavid du Colombier 	irqs[Irqhi].irq = &intr->hi.irq;
2507365b686SDavid du Colombier 	irqs[Irqhi].irqmask = &intr->hi.irqmask;
2517365b686SDavid du Colombier 	irqs[Irqbridge].irq = &cpu->irq;
2527365b686SDavid du Colombier 	irqs[Irqbridge].irqmask = &cpu->irqmask;
2537365b686SDavid du Colombier 	coherence();
2547365b686SDavid du Colombier 
255154abd99SDavid du Colombier 	setr13(PsrMfiq, m->fiqstack + nelem(m->fiqstack));
256154abd99SDavid du Colombier 	setr13(PsrMirq, m->irqstack + nelem(m->irqstack));
257154abd99SDavid du Colombier 	setr13(PsrMabt, m->abtstack + nelem(m->abtstack));
258154abd99SDavid du Colombier 	setr13(PsrMund, m->undstack + nelem(m->undstack));
259154abd99SDavid du Colombier 
260154abd99SDavid du Colombier 	memmove(page0->vectors, vectors, sizeof page0->vectors);
261154abd99SDavid du Colombier 	memmove(page0->vtable,  vtable,  sizeof page0->vtable);
262154abd99SDavid du Colombier 	cacheuwbinv();
263a7a38e3eSDavid du Colombier 	l2cacheuwbinv();
264154abd99SDavid du Colombier 
265154abd99SDavid du Colombier 	cpu->cpucfg &= ~Cfgvecinithi;
266154abd99SDavid du Colombier 
267154abd99SDavid du Colombier 	for(i = 0; i < nelem(irqlo); i++)
268154abd99SDavid du Colombier 		intrunset(&irqlo[i]);
269154abd99SDavid du Colombier 	for(i = 0; i < nelem(irqhi); i++)
270154abd99SDavid du Colombier 		intrunset(&irqhi[i]);
271154abd99SDavid du Colombier 	for(i = 0; i < nelem(irqbridge); i++)
272154abd99SDavid du Colombier 		intrunset(&irqbridge[i]);
273154abd99SDavid du Colombier 
274154abd99SDavid du Colombier 	/* disable all interrupts */
275154abd99SDavid du Colombier 	intr->lo.fiqmask = intr->hi.fiqmask = 0;
276154abd99SDavid du Colombier 	intr->lo.irqmask = intr->hi.irqmask = 0;
277154abd99SDavid du Colombier 	intr->lo.epmask =  intr->hi.epmask = 0;
278154abd99SDavid du Colombier 	cpu->irqmask = 0;
279a7a38e3eSDavid du Colombier 	coherence();
280154abd99SDavid du Colombier 
281154abd99SDavid du Colombier 	/* clear interrupts */
282154abd99SDavid du Colombier 	intr->lo.irq = intr->hi.irq = ~0;
283154abd99SDavid du Colombier 	cpu->irq = ~0;
284a7a38e3eSDavid du Colombier 	coherence();
285154abd99SDavid du Colombier 
286154abd99SDavid du Colombier 	intrenable(Irqlo, IRQ0hisum, intrhi, nil, "hi");
287154abd99SDavid du Colombier 	intrenable(Irqlo, IRQ0bridge, intrbridge, nil, "bridge");
288304cb050SDavid du Colombier 
289304cb050SDavid du Colombier 	/* enable watchdog & access-error interrupts */
290a7a38e3eSDavid du Colombier 	cpu->irqmask |= 1 << IRQcputimerwd | 1 << IRQaccesserr;
291a7a38e3eSDavid du Colombier 	coherence();
292154abd99SDavid du Colombier }
293154abd99SDavid du Colombier 
294154abd99SDavid du Colombier static char *trapnames[PsrMask+1] = {
295154abd99SDavid du Colombier 	[ PsrMusr ] "user mode",
296154abd99SDavid du Colombier 	[ PsrMfiq ] "fiq interrupt",
297154abd99SDavid du Colombier 	[ PsrMirq ] "irq interrupt",
298154abd99SDavid du Colombier 	[ PsrMsvc ] "svc/swi exception",
299154abd99SDavid du Colombier 	[ PsrMabt ] "prefetch abort/data abort",
300154abd99SDavid du Colombier 	[ PsrMabt+1 ] "data abort",
301154abd99SDavid du Colombier 	[ PsrMund ] "undefined instruction",
302154abd99SDavid du Colombier 	[ PsrMsys ] "sys trap",
303154abd99SDavid du Colombier };
304154abd99SDavid du Colombier 
305154abd99SDavid du Colombier static char *
trapname(int psr)306154abd99SDavid du Colombier trapname(int psr)
307154abd99SDavid du Colombier {
308154abd99SDavid du Colombier 	char *s;
309154abd99SDavid du Colombier 
310154abd99SDavid du Colombier 	s = trapnames[psr & PsrMask];
311154abd99SDavid du Colombier 	if(s == nil)
312154abd99SDavid du Colombier 		s = "unknown trap number in psr";
313154abd99SDavid du Colombier 	return s;
314154abd99SDavid du Colombier }
315154abd99SDavid du Colombier 
3168153b942SDavid du Colombier /* this is quite helpful during mmu and cache debugging */
3178153b942SDavid du Colombier static void
ckfaultstuck(uintptr va)3188153b942SDavid du Colombier ckfaultstuck(uintptr va)
3198153b942SDavid du Colombier {
3208153b942SDavid du Colombier 	static int cnt, lastpid;
3218153b942SDavid du Colombier 	static uintptr lastva;
3228153b942SDavid du Colombier 
3238153b942SDavid du Colombier 	if (va == lastva && up->pid == lastpid) {
3248153b942SDavid du Colombier 		++cnt;
3258153b942SDavid du Colombier 		if (cnt >= 2)
3268153b942SDavid du Colombier 			/* fault() isn't fixing the underlying cause */
3278153b942SDavid du Colombier 			panic("fault: %d consecutive faults for va %#p",
3288153b942SDavid du Colombier 				cnt+1, va);
3298153b942SDavid du Colombier 	} else {
3308153b942SDavid du Colombier 		cnt = 0;
3318153b942SDavid du Colombier 		lastva = va;
3328153b942SDavid du Colombier 		lastpid = up->pid;
3338153b942SDavid du Colombier 	}
3348153b942SDavid du Colombier }
3358153b942SDavid du Colombier 
336154abd99SDavid du Colombier /*
337154abd99SDavid du Colombier  *  called by trap to handle access faults
338154abd99SDavid du Colombier  */
339154abd99SDavid du Colombier static void
faultarm(Ureg * ureg,uintptr va,int user,int read)340154abd99SDavid du Colombier faultarm(Ureg *ureg, uintptr va, int user, int read)
341154abd99SDavid du Colombier {
342154abd99SDavid du Colombier 	int n, insyscall;
343154abd99SDavid du Colombier 	char buf[ERRMAX];
344a7a38e3eSDavid du Colombier 	static int cnt, lastpid;
345a7a38e3eSDavid du Colombier 	static ulong lastva;
346154abd99SDavid du Colombier 
347154abd99SDavid du Colombier 	if(up == nil) {
348154abd99SDavid du Colombier 		dumpregs(ureg);
349154abd99SDavid du Colombier 		panic("fault: nil up in faultarm, accessing %#p", va);
350154abd99SDavid du Colombier 	}
351154abd99SDavid du Colombier 	insyscall = up->insyscall;
352154abd99SDavid du Colombier 	up->insyscall = 1;
3538153b942SDavid du Colombier 	if (Debug)
3548153b942SDavid du Colombier 		ckfaultstuck(va);
355a7a38e3eSDavid du Colombier 
356154abd99SDavid du Colombier 	n = fault(va, read);
357154abd99SDavid du Colombier 	if(n < 0){
358154abd99SDavid du Colombier 		if(!user){
359154abd99SDavid du Colombier 			dumpregs(ureg);
360154abd99SDavid du Colombier 			panic("fault: kernel accessing %#p", va);
361154abd99SDavid du Colombier 		}
362154abd99SDavid du Colombier 		/* don't dump registers; programs suicide all the time */
363154abd99SDavid du Colombier 		snprint(buf, sizeof buf, "sys: trap: fault %s va=%#p",
364154abd99SDavid du Colombier 			read? "read": "write", va);
365154abd99SDavid du Colombier 		postnote(up, 1, buf, NDebug);
366154abd99SDavid du Colombier 	}
367154abd99SDavid du Colombier 	up->insyscall = insyscall;
368154abd99SDavid du Colombier }
369154abd99SDavid du Colombier 
370154abd99SDavid du Colombier /*
371154abd99SDavid du Colombier  *  returns 1 if the instruction writes memory, 0 otherwise
372154abd99SDavid du Colombier  */
373154abd99SDavid du Colombier int
writetomem(ulong inst)374154abd99SDavid du Colombier writetomem(ulong inst)
375154abd99SDavid du Colombier {
376154abd99SDavid du Colombier 	/* swap always write memory */
377154abd99SDavid du Colombier 	if((inst & 0x0FC00000) == 0x01000000)
378154abd99SDavid du Colombier 		return 1;
379154abd99SDavid du Colombier 
380154abd99SDavid du Colombier 	/* loads and stores are distinguished by bit 20 */
381154abd99SDavid du Colombier 	if(inst & (1<<20))
382154abd99SDavid du Colombier 		return 0;
383154abd99SDavid du Colombier 
384154abd99SDavid du Colombier 	return 1;
385154abd99SDavid du Colombier }
386154abd99SDavid du Colombier 
387154abd99SDavid du Colombier void
trap(Ureg * ureg)388154abd99SDavid du Colombier trap(Ureg *ureg)
389154abd99SDavid du Colombier {
390154abd99SDavid du Colombier 	int user, x, rv, rem;
391154abd99SDavid du Colombier 	ulong inst;
392154abd99SDavid du Colombier 	u32int fsr;
393154abd99SDavid du Colombier 	uintptr va;
394154abd99SDavid du Colombier 	char buf[ERRMAX];
395154abd99SDavid du Colombier 
396154abd99SDavid du Colombier 	if(up != nil)
397154abd99SDavid du Colombier 		rem = (char*)ureg - up->kstack;
398154abd99SDavid du Colombier 	else
399154abd99SDavid du Colombier 		rem = (char*)ureg - ((char*)m + sizeof(Mach));
400154abd99SDavid du Colombier 	if(rem < 256) {
401154abd99SDavid du Colombier 		dumpstack();
4027bb09086SDavid du Colombier 		panic("trap %d bytes remaining, up %#p ureg %#p at pc %#lux",
403154abd99SDavid du Colombier 			rem, up, ureg, ureg->pc);
404154abd99SDavid du Colombier 	}
405154abd99SDavid du Colombier 
406154abd99SDavid du Colombier 	user = (ureg->psr & PsrMask) == PsrMusr;
407ab6ce076SDavid du Colombier 	if(user){
408ab6ce076SDavid du Colombier 		up->dbgreg = ureg;
409ab6ce076SDavid du Colombier 		cycles(&up->kentry);
410ab6ce076SDavid du Colombier 	}
411154abd99SDavid du Colombier 
412154abd99SDavid du Colombier 	if(ureg->type == PsrMabt+1)
413154abd99SDavid du Colombier 		ureg->pc -= 8;
414154abd99SDavid du Colombier 	else
415154abd99SDavid du Colombier 		ureg->pc -= 4;
416154abd99SDavid du Colombier 
417154abd99SDavid du Colombier 	m->inclockintr = 0;
418154abd99SDavid du Colombier 	switch(ureg->type) {
419154abd99SDavid du Colombier 	default:
4207bb09086SDavid du Colombier 		panic("unknown trap %ld", ureg->type);
421154abd99SDavid du Colombier 		break;
422154abd99SDavid du Colombier 	case PsrMirq:
423154abd99SDavid du Colombier 		ldrexvalid = 0;
424154abd99SDavid du Colombier 		// splflo();		/* allow fast interrupts */
425154abd99SDavid du Colombier 		intrs(ureg, Irqlo);
426154abd99SDavid du Colombier 		m->intr++;
427154abd99SDavid du Colombier 		break;
428154abd99SDavid du Colombier 	case PsrMabt:			/* prefetch fault */
429154abd99SDavid du Colombier 		ldrexvalid = 0;
430154abd99SDavid du Colombier 		faultarm(ureg, ureg->pc, user, 1);
431*6bbfed0dSDavid du Colombier 		if(up->nnote == 0 &&
432*6bbfed0dSDavid du Colombier 		   (*(u32int*)ureg->pc & ~(0xF<<28)) == 0x01200070)
433*6bbfed0dSDavid du Colombier 			postnote(up, 1, "sys: breakpoint", NDebug);
434154abd99SDavid du Colombier 		break;
435154abd99SDavid du Colombier 	case PsrMabt+1:			/* data fault */
436154abd99SDavid du Colombier 		ldrexvalid = 0;
437154abd99SDavid du Colombier 		va = farget();
438154abd99SDavid du Colombier 		inst = *(ulong*)(ureg->pc);
439154abd99SDavid du Colombier 		fsr = fsrget() & 0xf;
440154abd99SDavid du Colombier 		if (probing && !user) {
441154abd99SDavid du Colombier 			if (trapped++ > 0)
442154abd99SDavid du Colombier 				panic("trap: recursive probe %#lux", va);
443154abd99SDavid du Colombier 			ureg->pc += 4;	/* continue at next instruction */
444154abd99SDavid du Colombier 			break;
445154abd99SDavid du Colombier 		}
446154abd99SDavid du Colombier 		switch(fsr){
447154abd99SDavid du Colombier 		case 0x0:
4487bb09086SDavid du Colombier 			panic("vector exception at %#lux", ureg->pc);
449154abd99SDavid du Colombier 			break;
450154abd99SDavid du Colombier 		case 0x1:
451154abd99SDavid du Colombier 		case 0x3:
452154abd99SDavid du Colombier 			if(user){
453154abd99SDavid du Colombier 				snprint(buf, sizeof buf,
4547bb09086SDavid du Colombier 					"sys: alignment: pc %#lux va %#p\n",
455154abd99SDavid du Colombier 					ureg->pc, va);
456154abd99SDavid du Colombier 				postnote(up, 1, buf, NDebug);
457154abd99SDavid du Colombier 			} else
4587bb09086SDavid du Colombier 				panic("kernel alignment: pc %#lux va %#p", ureg->pc, va);
459154abd99SDavid du Colombier 			break;
460154abd99SDavid du Colombier 		case 0x2:
4617bb09086SDavid du Colombier 			panic("terminal exception at %#lux", ureg->pc);
462154abd99SDavid du Colombier 			break;
463154abd99SDavid du Colombier 		case 0x4:
464154abd99SDavid du Colombier 		case 0x6:
465154abd99SDavid du Colombier 		case 0x8:
466154abd99SDavid du Colombier 		case 0xa:
467154abd99SDavid du Colombier 		case 0xc:
468154abd99SDavid du Colombier 		case 0xe:
4697bb09086SDavid du Colombier 			panic("external abort %#ux pc %#lux addr %#px",
470154abd99SDavid du Colombier 				fsr, ureg->pc, va);
471154abd99SDavid du Colombier 			break;
472154abd99SDavid du Colombier 		case 0x5:		/* translation fault, no section entry */
473154abd99SDavid du Colombier 		case 0x7:		/* translation fault, no page entry */
474154abd99SDavid du Colombier 			faultarm(ureg, va, user, !writetomem(inst));
475154abd99SDavid du Colombier 			break;
476154abd99SDavid du Colombier 		case 0x9:
477154abd99SDavid du Colombier 		case 0xb:
478154abd99SDavid du Colombier 			/* domain fault, accessing something we shouldn't */
479154abd99SDavid du Colombier 			if(user){
480154abd99SDavid du Colombier 				snprint(buf, sizeof buf,
4817bb09086SDavid du Colombier 					"sys: access violation: pc %#lux va %#p\n",
482154abd99SDavid du Colombier 					ureg->pc, va);
483154abd99SDavid du Colombier 				postnote(up, 1, buf, NDebug);
484154abd99SDavid du Colombier 			} else
4857bb09086SDavid du Colombier 				panic("kernel access violation: pc %#lux va %#p",
486154abd99SDavid du Colombier 					ureg->pc, va);
487154abd99SDavid du Colombier 			break;
488154abd99SDavid du Colombier 		case 0xd:
489154abd99SDavid du Colombier 		case 0xf:
490154abd99SDavid du Colombier 			/* permission error, copy on write or real permission error */
491154abd99SDavid du Colombier 			faultarm(ureg, va, user, !writetomem(inst));
492154abd99SDavid du Colombier 			break;
493154abd99SDavid du Colombier 		}
494154abd99SDavid du Colombier 		break;
495154abd99SDavid du Colombier 	case PsrMund:	/* undefined instruction */
496154abd99SDavid du Colombier 		if(user){
497a4b9e815SDavid du Colombier 			if(seg(up, ureg->pc, 0) != nil &&
498*6bbfed0dSDavid du Colombier 			   (*(u32int*)ureg->pc & ~(0xF<<28)) == 0x01200070)
499*6bbfed0dSDavid du Colombier 				postnote(up, 1, "sys: breakpoint", NDebug);
500*6bbfed0dSDavid du Colombier 			else{
501154abd99SDavid du Colombier 				/* look for floating point instructions to interpret */
502154abd99SDavid du Colombier 				x = spllo();
503154abd99SDavid du Colombier 				rv = fpiarm(ureg);
504154abd99SDavid du Colombier 				splx(x);
505154abd99SDavid du Colombier 				if(rv == 0){
506154abd99SDavid du Colombier 					ldrexvalid = 0;
507154abd99SDavid du Colombier 					snprint(buf, sizeof buf,
5087bb09086SDavid du Colombier 						"undefined instruction: pc %#lux",
509154abd99SDavid du Colombier 						ureg->pc);
510154abd99SDavid du Colombier 					postnote(up, 1, buf, NDebug);
511154abd99SDavid du Colombier 				}
512a4b9e815SDavid du Colombier 			}
513154abd99SDavid du Colombier 		}else{
5147bb09086SDavid du Colombier 			iprint("undefined instruction: pc %#lux inst %#ux\n",
515154abd99SDavid du Colombier 				ureg->pc, ((u32int*)ureg->pc)[-2]);
516154abd99SDavid du Colombier 			panic("undefined instruction");
517154abd99SDavid du Colombier 		}
518154abd99SDavid du Colombier 		break;
519154abd99SDavid du Colombier 	}
520154abd99SDavid du Colombier 	splhi();
521154abd99SDavid du Colombier 
522154abd99SDavid du Colombier 	/* delaysched set because we held a lock or because our quantum ended */
523154abd99SDavid du Colombier 	if(up && up->delaysched && m->inclockintr){
524154abd99SDavid du Colombier 		ldrexvalid = 0;
525154abd99SDavid du Colombier 		sched();
526154abd99SDavid du Colombier 		splhi();
527154abd99SDavid du Colombier 	}
528154abd99SDavid du Colombier 
529154abd99SDavid du Colombier 	if(user){
530154abd99SDavid du Colombier 		if(up->procctl || up->nnote)
531154abd99SDavid du Colombier 			notify(ureg);
532154abd99SDavid du Colombier 		kexit(ureg);
533154abd99SDavid du Colombier 	}
534154abd99SDavid du Colombier }
535154abd99SDavid du Colombier 
536154abd99SDavid du Colombier int
isvalidaddr(void * v)537154abd99SDavid du Colombier isvalidaddr(void *v)
538154abd99SDavid du Colombier {
539154abd99SDavid du Colombier 	return (uintptr)v >= KZERO;
540154abd99SDavid du Colombier }
541154abd99SDavid du Colombier 
542154abd99SDavid du Colombier void
dumplongs(char * msg,ulong * v,int n)543154abd99SDavid du Colombier dumplongs(char *msg, ulong *v, int n)
544154abd99SDavid du Colombier {
545154abd99SDavid du Colombier 	int i, l;
546154abd99SDavid du Colombier 
547154abd99SDavid du Colombier 	l = 0;
548154abd99SDavid du Colombier 	iprint("%s at %.8p: ", msg, v);
549154abd99SDavid du Colombier 	for(i=0; i<n; i++){
550154abd99SDavid du Colombier 		if(l >= 4){
551154abd99SDavid du Colombier 			iprint("\n    %.8p: ", v);
552154abd99SDavid du Colombier 			l = 0;
553154abd99SDavid du Colombier 		}
554154abd99SDavid du Colombier 		if(isvalidaddr(v)){
555154abd99SDavid du Colombier 			iprint(" %.8lux", *v++);
556154abd99SDavid du Colombier 			l++;
557154abd99SDavid du Colombier 		}else{
558154abd99SDavid du Colombier 			iprint(" invalid");
559154abd99SDavid du Colombier 			break;
560154abd99SDavid du Colombier 		}
561154abd99SDavid du Colombier 	}
562154abd99SDavid du Colombier 	iprint("\n");
563154abd99SDavid du Colombier }
564154abd99SDavid du Colombier 
565154abd99SDavid du Colombier static void
dumpstackwithureg(Ureg * ureg)566154abd99SDavid du Colombier dumpstackwithureg(Ureg *ureg)
567154abd99SDavid du Colombier {
568154abd99SDavid du Colombier 	uintptr l, i, v, estack;
569154abd99SDavid du Colombier 	u32int *p;
570154abd99SDavid du Colombier 
5717365b686SDavid du Colombier 	iprint("ktrace /kernel/path %#.8lux %#.8lux %#.8lux # pc, sp, link\n",
5727365b686SDavid du Colombier 		ureg->pc, ureg->sp, ureg->r14);
5737365b686SDavid du Colombier 	delay(2000);
574154abd99SDavid du Colombier 	i = 0;
575154abd99SDavid du Colombier 	if(up != nil && (uintptr)&l <= (uintptr)up->kstack+KSTACK)
576154abd99SDavid du Colombier 		estack = (uintptr)up->kstack+KSTACK;
577154abd99SDavid du Colombier 	else if((uintptr)&l >= (uintptr)m->stack
578154abd99SDavid du Colombier 	     && (uintptr)&l <= (uintptr)m+MACHSIZE)
579154abd99SDavid du Colombier 		estack = (uintptr)m+MACHSIZE;
580154abd99SDavid du Colombier 	else{
581154abd99SDavid du Colombier 		if(up != nil)
582154abd99SDavid du Colombier 			iprint("&up->kstack %#p &l %#p\n", up->kstack, &l);
583154abd99SDavid du Colombier 		else
584154abd99SDavid du Colombier 			iprint("&m %#p &l %#p\n", m, &l);
585154abd99SDavid du Colombier 		return;
586154abd99SDavid du Colombier 	}
587154abd99SDavid du Colombier 	for(l = (uintptr)&l; l < estack; l += sizeof(uintptr)){
588154abd99SDavid du Colombier 		v = *(uintptr*)l;
589154abd99SDavid du Colombier 		if(KTZERO < v && v < (uintptr)etext && !(v & 3)){
5907365b686SDavid du Colombier 			v -= sizeof(u32int);		/* back up an instr */
591154abd99SDavid du Colombier 			p = (u32int*)v;
5927365b686SDavid du Colombier 			if((*p & 0x0f000000) == 0x0b000000){	/* BL instr? */
593154abd99SDavid du Colombier 				iprint("%#8.8lux=%#8.8lux ", l, v);
594154abd99SDavid du Colombier 				i++;
595154abd99SDavid du Colombier 			}
596154abd99SDavid du Colombier 		}
597154abd99SDavid du Colombier 		if(i == 4){
598154abd99SDavid du Colombier 			i = 0;
599154abd99SDavid du Colombier 			iprint("\n");
600154abd99SDavid du Colombier 		}
601154abd99SDavid du Colombier 	}
602154abd99SDavid du Colombier 	if(i)
603154abd99SDavid du Colombier 		iprint("\n");
604154abd99SDavid du Colombier }
605154abd99SDavid du Colombier 
606154abd99SDavid du Colombier /*
607154abd99SDavid du Colombier  * Fill in enough of Ureg to get a stack trace, and call a function.
608154abd99SDavid du Colombier  * Used by debugging interface rdb.
609154abd99SDavid du Colombier  */
610154abd99SDavid du Colombier void
callwithureg(void (* fn)(Ureg *))611154abd99SDavid du Colombier callwithureg(void (*fn)(Ureg*))
612154abd99SDavid du Colombier {
613154abd99SDavid du Colombier 	Ureg ureg;
614154abd99SDavid du Colombier 
615154abd99SDavid du Colombier 	ureg.pc = getcallerpc(&fn);
616154abd99SDavid du Colombier 	ureg.sp = PTR2UINT(&fn);
617154abd99SDavid du Colombier 	fn(&ureg);
618154abd99SDavid du Colombier }
619154abd99SDavid du Colombier 
620154abd99SDavid du Colombier void
dumpstack(void)621154abd99SDavid du Colombier dumpstack(void)
622154abd99SDavid du Colombier {
623154abd99SDavid du Colombier 	callwithureg(dumpstackwithureg);
624154abd99SDavid du Colombier }
625154abd99SDavid du Colombier 
626154abd99SDavid du Colombier void
dumpregs(Ureg * ureg)627154abd99SDavid du Colombier dumpregs(Ureg* ureg)
628154abd99SDavid du Colombier {
629154abd99SDavid du Colombier 	int s;
630154abd99SDavid du Colombier 
631154abd99SDavid du Colombier 	if (ureg == nil) {
632154abd99SDavid du Colombier 		iprint("trap: no user process\n");
633154abd99SDavid du Colombier 		return;
634154abd99SDavid du Colombier 	}
635154abd99SDavid du Colombier 	s = splhi();
636154abd99SDavid du Colombier 	iprint("trap: %s", trapname(ureg->type));
637154abd99SDavid du Colombier 	if(ureg != nil && (ureg->psr & PsrMask) != PsrMsvc)
638154abd99SDavid du Colombier 		iprint(" in %s", trapname(ureg->psr));
639154abd99SDavid du Colombier 	iprint("\n");
6407bb09086SDavid du Colombier 	iprint("psr %8.8lux type %2.2lux pc %8.8lux link %8.8lux\n",
641154abd99SDavid du Colombier 		ureg->psr, ureg->type, ureg->pc, ureg->link);
6427bb09086SDavid du Colombier 	iprint("R14 %8.8lux R13 %8.8lux R12 %8.8lux R11 %8.8lux R10 %8.8lux\n",
643154abd99SDavid du Colombier 		ureg->r14, ureg->r13, ureg->r12, ureg->r11, ureg->r10);
6447bb09086SDavid du Colombier 	iprint("R9  %8.8lux R8  %8.8lux R7  %8.8lux R6  %8.8lux R5  %8.8lux\n",
645154abd99SDavid du Colombier 		ureg->r9, ureg->r8, ureg->r7, ureg->r6, ureg->r5);
6467bb09086SDavid du Colombier 	iprint("R4  %8.8lux R3  %8.8lux R2  %8.8lux R1  %8.8lux R0  %8.8lux\n",
647154abd99SDavid du Colombier 		ureg->r4, ureg->r3, ureg->r2, ureg->r1, ureg->r0);
648154abd99SDavid du Colombier 	iprint("stack is at %#p\n", ureg);
6497bb09086SDavid du Colombier 	iprint("pc %#lux link %#lux\n", ureg->pc, ureg->link);
650154abd99SDavid du Colombier 
651154abd99SDavid du Colombier 	if(up)
652154abd99SDavid du Colombier 		iprint("user stack: %#p-%#p\n", up->kstack, up->kstack+KSTACK-4);
653154abd99SDavid du Colombier 	else
654154abd99SDavid du Colombier 		iprint("kernel stack: %8.8lux-%8.8lux\n",
655154abd99SDavid du Colombier 			(ulong)(m+1), (ulong)m+BY2PG-4);
656154abd99SDavid du Colombier 	dumplongs("stack", (ulong *)(ureg + 1), 16);
657154abd99SDavid du Colombier 	delay(2000);
658154abd99SDavid du Colombier 	dumpstack();
659154abd99SDavid du Colombier 	splx(s);
660154abd99SDavid du Colombier }
661154abd99SDavid du Colombier 
662154abd99SDavid du Colombier void
idlehands(void)663154abd99SDavid du Colombier idlehands(void)
664154abd99SDavid du Colombier {
665154abd99SDavid du Colombier 	extern void _idlehands(void);
666154abd99SDavid du Colombier 
667154abd99SDavid du Colombier 	_idlehands();
668154abd99SDavid du Colombier }
669154abd99SDavid du Colombier 
670b649930dSDavid du Colombier /* assumes that addr is already mapped suitable (e.g., by mmuidmap) */
671154abd99SDavid du Colombier vlong
probeaddr(uintptr addr)672154abd99SDavid du Colombier probeaddr(uintptr addr)
673154abd99SDavid du Colombier {
674154abd99SDavid du Colombier 	vlong v;
675154abd99SDavid du Colombier 	static Lock fltlck;
676154abd99SDavid du Colombier 
677154abd99SDavid du Colombier 	ilock(&fltlck);
678154abd99SDavid du Colombier 	trapped = 0;
679154abd99SDavid du Colombier 	probing = 1;
680154abd99SDavid du Colombier 	coherence();
681154abd99SDavid du Colombier 
6827ae8f453SDavid du Colombier 	v = *(ulong *)addr;	/* this may cause a fault (okay under ilock) */
683154abd99SDavid du Colombier 	USED(probing);
684154abd99SDavid du Colombier 	coherence();
685154abd99SDavid du Colombier 
686154abd99SDavid du Colombier 	probing = 0;
687154abd99SDavid du Colombier 	coherence();
688154abd99SDavid du Colombier 	if (trapped)
689154abd99SDavid du Colombier 		v = -1;
690154abd99SDavid du Colombier 	iunlock(&fltlck);
691154abd99SDavid du Colombier 	return v;
692154abd99SDavid du Colombier }
693