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