]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/kw/trap.c
ndb/dns: lookup *all* entries in dblookup(), v4 and v6 queries in parallel, remove...
[plan9front.git] / sys / src / 9 / kw / trap.c
1 /*
2  * sheevaplug traps, exceptions, interrupts, system calls.
3  */
4 #include "u.h"
5 #include "../port/lib.h"
6 #include "mem.h"
7 #include "dat.h"
8 #include "fns.h"
9 #include "io.h"
10 #include "ureg.h"
11 #include "../port/error.h"
12
13 #include "arm.h"
14
15 enum {
16         Ntimevec = 20,                  /* # of time buckets for each intr */
17         Nvecs = 256,
18 };
19
20 extern int notify(Ureg*);
21
22 extern int ldrexvalid;
23
24 typedef struct Vctl Vctl;
25 typedef struct Vctl {
26         Vctl*   next;           /* handlers on this vector */
27         char    *name;          /* of driver, xallocated */
28         void    (*f)(Ureg*, void*);     /* handler to call */
29         void*   a;              /* argument to call it with */
30 } Vctl;
31
32 static Lock vctllock;
33 static Vctl* vctl[32];
34
35 uvlong ninterrupt;
36 uvlong ninterruptticks;
37 ulong intrtimes[Nvecs][Ntimevec];
38
39 typedef struct Handler Handler;
40 struct Handler {
41         void    (*r)(Ureg*, void*);
42         void    *a;
43         char    name[KNAMELEN];
44 };
45
46 static Handler irqlo[32];
47 static Handler irqhi[32];
48 static Handler irqbridge[32];
49 static Lock irqlock;
50 static int probing, trapped;
51
52 typedef struct Irq Irq;
53 struct Irq {
54         ulong   *irq;
55         ulong   *irqmask;
56         Handler *irqvec;
57         int     nirqvec;
58         char    *name;
59 };
60 /* irq and irqmask are filled in by trapinit */
61 static Irq irqs[] = {
62 [Irqlo]         {nil, nil, irqlo,       nelem(irqlo),   "lo"},
63 [Irqhi]         {nil, nil, irqhi,       nelem(irqhi),   "hi"},
64 [Irqbridge]     {nil, nil, irqbridge,   nelem(irqbridge), "bridge"},
65 };
66
67 /*
68  *  keep histogram of interrupt service times
69  */
70 void
71 intrtime(Mach*, int vno)
72 {
73         ulong diff, x;
74
75         if (m == nil)
76                 return;
77         x = perfticks();
78         diff = x - m->perf.intrts;
79         m->perf.intrts = x;
80
81         m->perf.inintr += diff;
82         if(up == nil && m->perf.inidle > diff)
83                 m->perf.inidle -= diff;
84
85         if (m->cpuhz == 0)                      /* not set yet? */
86                 return;
87         diff /= (m->cpuhz/1000000)*100;         /* quantum = 100µsec */
88         if(diff >= Ntimevec)
89                 diff = Ntimevec-1;
90         assert(vno >= 0 && vno < Nvecs);
91         intrtimes[vno][diff]++;
92 }
93
94 void
95 intrfmtcounts(char *s, char *se)
96 {
97         USED(s, se);
98 }
99
100 static void
101 dumpcounts(void)
102 {
103 }
104
105 void
106 intrclear(int sort, int v)
107 {
108         *irqs[sort].irq = ~(1 << v);
109 }
110
111 void
112 intrmask(int sort, int v)
113 {
114         *irqs[sort].irqmask &= ~(1 << v);
115 }
116
117 void
118 intrunmask(int sort, int v)
119 {
120         *irqs[sort].irqmask |= 1 << v;
121 }
122
123 static void
124 maskallints(void)
125 {
126         CpucsReg *cpu = (CpucsReg *)soc.cpu;
127         IntrReg *intr;
128
129         /* no fiq or ep in use */
130         intr = (IntrReg *)soc.intr;
131         intr->lo.irqmask = 0;
132         intr->hi.irqmask = 0;
133         cpu->irqmask = 0;
134         coherence();
135 }
136
137 void
138 intrset(Handler *h, void (*f)(Ureg*, void*), void *a, char *name)
139 {
140         if(h->r != nil) {
141 //              iprint("duplicate irq: %s (%#p)\n", h->name, h->r);
142                 return;
143         }
144         h->r = f;
145         h->a = a;
146         strncpy(h->name, name, KNAMELEN-1);
147         h->name[KNAMELEN-1] = 0;
148 }
149
150 void
151 intrunset(Handler *h)
152 {
153         h->r = nil;
154         h->a = nil;
155         h->name[0] = 0;
156 }
157
158 void
159 intrdel(Handler *h, void (*f)(Ureg*, void*), void *a, char *name)
160 {
161         if(h->r != f || h->a != a || strcmp(h->name, name) != 0)
162                 return;
163         intrunset(h);
164 }
165
166 void
167 intrenable(int sort, int v, void (*f)(Ureg*, void*), void *a, char *name)
168 {
169 //iprint("enabling intr %d vec %d for %s\n", sort, v, name);
170         ilock(&irqlock);
171         intrset(&irqs[sort].irqvec[v], f, a, name);
172         intrunmask(sort, v);
173         iunlock(&irqlock);
174 }
175
176 void
177 intrdisable(int sort, int v, void (*f)(Ureg*, void*), void* a, char *name)
178 {
179         ilock(&irqlock);
180         intrdel(&irqs[sort].irqvec[v], f, a, name);
181         intrmask(sort, v);
182         iunlock(&irqlock);
183 }
184
185 /*
186  *  called by trap to handle interrupts
187  */
188 static void
189 intrs(Ureg *ur, int sort)
190 {
191         int i, s;
192         ulong ibits;
193         Handler *h;
194         Irq irq;
195
196         assert(sort >= 0 && sort < nelem(irqs));
197         irq = irqs[sort];
198         ibits = *irq.irq;
199         ibits &= *irq.irqmask;
200
201         for(i = 0; i < irq.nirqvec && ibits; i++)
202                 if(ibits & (1<<i)){
203                         h = &irq.irqvec[i];
204                         if(h->r != nil){
205                                 h->r(ur, h->a);
206                                 splhi();
207                                 intrtime(m, sort*32 + i);
208                                 if (sort == Irqbridge && i == IRQcputimer0)
209                                         m->inclockintr = 1;
210                                 ibits &= ~(1<<i);
211                         }
212                 }
213         if(ibits != 0) {
214                 iprint("spurious irq%s interrupt: %8.8lux\n", irq.name, ibits);
215                 s = splfhi();
216                 *irq.irq &= ibits;
217                 *irq.irqmask &= ~ibits;
218                 splx(s);
219         }
220 }
221
222 void
223 intrhi(Ureg *ureg, void*)
224 {
225         intrs(ureg, Irqhi);
226 }
227
228 void
229 intrbridge(Ureg *ureg, void*)
230 {
231         intrs(ureg, Irqbridge);
232         intrclear(Irqlo, IRQ0bridge);
233 }
234
235 void
236 trapinit(void)
237 {
238         int i;
239         CpucsReg *cpu;
240         IntrReg *intr;
241         Vectorpage *page0 = (Vectorpage*)HVECTORS;
242
243         intr = (IntrReg *)soc.intr;
244         cpu = (CpucsReg *)soc.cpu;
245         irqs[Irqlo].irq = &intr->lo.irq;
246         irqs[Irqlo].irqmask = &intr->lo.irqmask;
247         irqs[Irqhi].irq = &intr->hi.irq;
248         irqs[Irqhi].irqmask = &intr->hi.irqmask;
249         irqs[Irqbridge].irq = &cpu->irq;
250         irqs[Irqbridge].irqmask = &cpu->irqmask;
251         coherence();
252
253         setr13(PsrMfiq, m->fiqstack + nelem(m->fiqstack));
254         setr13(PsrMirq, m->irqstack + nelem(m->irqstack));
255         setr13(PsrMabt, m->abtstack + nelem(m->abtstack));
256         setr13(PsrMund, m->undstack + nelem(m->undstack));
257
258         memmove(page0->vectors, vectors, sizeof page0->vectors);
259         memmove(page0->vtable,  vtable,  sizeof page0->vtable);
260         cacheuwbinv();
261         l2cacheuwbinv();
262
263         cpu->cpucfg &= ~Cfgvecinithi;
264
265         for(i = 0; i < nelem(irqlo); i++)
266                 intrunset(&irqlo[i]);
267         for(i = 0; i < nelem(irqhi); i++)
268                 intrunset(&irqhi[i]);
269         for(i = 0; i < nelem(irqbridge); i++)
270                 intrunset(&irqbridge[i]);
271
272         /* disable all interrupts */
273         intr->lo.fiqmask = intr->hi.fiqmask = 0;
274         intr->lo.irqmask = intr->hi.irqmask = 0;
275         intr->lo.epmask =  intr->hi.epmask = 0;
276         cpu->irqmask = 0;
277         coherence();
278
279         /* clear interrupts */
280         intr->lo.irq = intr->hi.irq = ~0;
281         cpu->irq = ~0;
282         coherence();
283
284         intrenable(Irqlo, IRQ0hisum, intrhi, nil, "hi");
285         intrenable(Irqlo, IRQ0bridge, intrbridge, nil, "bridge");
286
287         /* enable watchdog & access-error interrupts */
288         cpu->irqmask |= 1 << IRQcputimerwd | 1 << IRQaccesserr;
289         coherence();
290 }
291
292 static char *trapnames[PsrMask+1] = {
293         [ PsrMusr ] "user mode",
294         [ PsrMfiq ] "fiq interrupt",
295         [ PsrMirq ] "irq interrupt",
296         [ PsrMsvc ] "svc/swi exception",
297         [ PsrMabt ] "prefetch abort/data abort",
298         [ PsrMabt+1 ] "data abort",
299         [ PsrMund ] "undefined instruction",
300         [ PsrMsys ] "sys trap",
301 };
302
303 static char *
304 trapname(int psr)
305 {
306         char *s;
307
308         s = trapnames[psr & PsrMask];
309         if(s == nil)
310                 s = "unknown trap number in psr";
311         return s;
312 }
313
314 /*
315  *  called by trap to handle access faults
316  */
317 static void
318 faultarm(Ureg *ureg, uintptr va, int user, int read)
319 {
320         int n, insyscall;
321         char buf[ERRMAX];
322         static int cnt, lastpid;
323         static ulong lastva;
324
325         if(up == nil) {
326                 dumpregs(ureg);
327                 panic("fault: nil up in faultarm, accessing %#p", va);
328         }
329         insyscall = up->insyscall;
330         up->insyscall = 1;
331
332         /* this is quite helpful during mmu and cache debugging */
333         if(va == lastva && up->pid == lastpid) {
334                 ++cnt;
335                 if (cnt >= 2)
336                         /* fault() isn't fixing the underlying cause */
337                         panic("fault: %d consecutive faults for va %#lux",
338                                 cnt+1, va);
339         } else {
340                 cnt = 0;
341                 lastva = va;
342                 lastpid = up->pid;
343         }
344
345         n = fault(va, read);
346         if(n < 0){
347                 if(!user){
348                         dumpregs(ureg);
349                         panic("fault: kernel accessing %#p", va);
350                 }
351                 /* don't dump registers; programs suicide all the time */
352                 snprint(buf, sizeof buf, "sys: trap: fault %s va=%#p",
353                         read? "read": "write", va);
354                 postnote(up, 1, buf, NDebug);
355         }
356         up->insyscall = insyscall;
357 }
358
359 /*
360  *  returns 1 if the instruction writes memory, 0 otherwise
361  */
362 int
363 writetomem(ulong inst)
364 {
365         /* swap always write memory */
366         if((inst & 0x0FC00000) == 0x01000000)
367                 return 1;
368
369         /* loads and stores are distinguished by bit 20 */
370         if(inst & (1<<20))
371                 return 0;
372
373         return 1;
374 }
375
376 void
377 trap(Ureg *ureg)
378 {
379         int user, x, rv, rem;
380         ulong inst;
381         u32int fsr;
382         uintptr va;
383         char buf[ERRMAX];
384
385         if(up != nil)
386                 rem = (char*)ureg - up->kstack;
387         else
388                 rem = (char*)ureg - ((char*)m + sizeof(Mach));
389         if(rem < 256) {
390                 dumpstack();
391                 panic("trap %d bytes remaining, up %#p ureg %#p at pc %#lux",
392                         rem, up, ureg, ureg->pc);
393         }
394
395         user = (ureg->psr & PsrMask) == PsrMusr;
396         if(user){
397                 up->dbgreg = ureg;
398                 cycles(&up->kentry);
399         }
400
401         if(ureg->type == PsrMabt+1)
402                 ureg->pc -= 8;
403         else
404                 ureg->pc -= 4;
405
406         m->inclockintr = 0;
407         switch(ureg->type) {
408         default:
409                 panic("unknown trap %ld", ureg->type);
410                 break;
411         case PsrMirq:
412                 ldrexvalid = 0;
413                 // splflo();            /* allow fast interrupts */
414                 intrs(ureg, Irqlo);
415                 m->intr++;
416                 break;
417         case PsrMabt:                   /* prefetch fault */
418                 ldrexvalid = 0;
419                 faultarm(ureg, ureg->pc, user, 1);
420                 if(up->nnote == 0 &&
421                    (*(u32int*)ureg->pc & ~(0xF<<28)) == 0x01200070)
422                         postnote(up, 1, "sys: breakpoint", NDebug);
423                 break;
424         case PsrMabt+1:                 /* data fault */
425                 ldrexvalid = 0;
426                 va = farget();
427                 inst = *(ulong*)(ureg->pc);
428                 fsr = fsrget() & 0xf;
429                 if (probing && !user) {
430                         if (trapped++ > 0)
431                                 panic("trap: recursive probe %#lux", va);
432                         ureg->pc += 4;  /* continue at next instruction */
433                         break;
434                 }
435                 switch(fsr){
436                 case 0x0:
437                         panic("vector exception at %#lux", ureg->pc);
438                         break;
439                 case 0x1:
440                 case 0x3:
441                         if(user){
442                                 snprint(buf, sizeof buf,
443                                         "sys: alignment: pc %#lux va %#p\n",
444                                         ureg->pc, va);
445                                 postnote(up, 1, buf, NDebug);
446                         } else
447                                 panic("kernel alignment: pc %#lux va %#p", ureg->pc, va);
448                         break;
449                 case 0x2:
450                         panic("terminal exception at %#lux", ureg->pc);
451                         break;
452                 case 0x4:
453                 case 0x6:
454                 case 0x8:
455                 case 0xa:
456                 case 0xc:
457                 case 0xe:
458                         panic("external abort %#ux pc %#lux addr %#px",
459                                 fsr, ureg->pc, va);
460                         break;
461                 case 0x5:               /* translation fault, no section entry */
462                 case 0x7:               /* translation fault, no page entry */
463                         faultarm(ureg, va, user, !writetomem(inst));
464                         break;
465                 case 0x9:
466                 case 0xb:
467                         /* domain fault, accessing something we shouldn't */
468                         if(user){
469                                 snprint(buf, sizeof buf,
470                                         "sys: access violation: pc %#lux va %#p\n",
471                                         ureg->pc, va);
472                                 postnote(up, 1, buf, NDebug);
473                         } else
474                                 panic("kernel access violation: pc %#lux va %#p",
475                                         ureg->pc, va);
476                         break;
477                 case 0xd:
478                 case 0xf:
479                         /* permission error, copy on write or real permission error */
480                         faultarm(ureg, va, user, !writetomem(inst));
481                         break;
482                 }
483                 break;
484         case PsrMund:   /* undefined instruction */
485                 if(user){
486                         if(seg(up, ureg->pc, 0) != nil &&
487                            (*(u32int*)ureg->pc & ~(0xF<<28)) == 0x01200070)
488                                 postnote(up, 1, "sys: breakpoint", NDebug);
489                         else{
490                                 /* look for floating point instructions to interpret */
491                                 x = spllo();
492                                 rv = fpiarm(ureg);
493                                 splx(x);
494                                 if(rv == 0){
495                                         ldrexvalid = 0;
496                                         snprint(buf, sizeof buf,
497                                                 "undefined instruction: pc %#lux",
498                                                 ureg->pc);
499                                         postnote(up, 1, buf, NDebug);
500                                 }
501                         }
502                 }else{
503                         iprint("undefined instruction: pc %#lux inst %#ux\n",
504                                 ureg->pc, ((u32int*)ureg->pc)[-2]);
505                         panic("undefined instruction");
506                 }
507                 break;
508         }
509         splhi();
510
511         /* delaysched set because we held a lock or because our quantum ended */
512         if(up && up->delaysched && m->inclockintr){
513                 ldrexvalid = 0;
514                 sched();
515                 splhi();
516         }
517
518         if(user){
519                 if(up->procctl || up->nnote)
520                         notify(ureg);
521                 kexit(ureg);
522         }
523 }
524
525 int
526 isvalidaddr(void *v)
527 {
528         return (uintptr)v >= KZERO;
529 }
530
531 void
532 dumplongs(char *msg, ulong *v, int n)
533 {
534         int i, l;
535
536         l = 0;
537         iprint("%s at %.8p: ", msg, v);
538         for(i=0; i<n; i++){
539                 if(l >= 4){
540                         iprint("\n    %.8p: ", v);
541                         l = 0;
542                 }
543                 if(isvalidaddr(v)){
544                         iprint(" %.8lux", *v++);
545                         l++;
546                 }else{
547                         iprint(" invalid");
548                         break;
549                 }
550         }
551         iprint("\n");
552 }
553
554 static void
555 dumpstackwithureg(Ureg *ureg)
556 {
557         uintptr l, i, v, estack;
558         u32int *p;
559
560         iprint("ktrace /kernel/path %#.8lux %#.8lux %#.8lux # pc, sp, link\n",
561                 ureg->pc, ureg->sp, ureg->r14);
562         delay(2000);
563         i = 0;
564         if(up != nil && (uintptr)&l <= (uintptr)up->kstack+KSTACK)
565                 estack = (uintptr)up->kstack+KSTACK;
566         else if((uintptr)&l >= (uintptr)m->stack
567              && (uintptr)&l <= (uintptr)m+MACHSIZE)
568                 estack = (uintptr)m+MACHSIZE;
569         else{
570                 if(up != nil)
571                         iprint("&up->kstack %#p &l %#p\n", up->kstack, &l);
572                 else
573                         iprint("&m %#p &l %#p\n", m, &l);
574                 return;
575         }
576         for(l = (uintptr)&l; l < estack; l += sizeof(uintptr)){
577                 v = *(uintptr*)l;
578                 if(KTZERO < v && v < (uintptr)etext && !(v & 3)){
579                         v -= sizeof(u32int);            /* back up an instr */
580                         p = (u32int*)v;
581                         if((*p & 0x0f000000) == 0x0b000000){    /* BL instr? */
582                                 iprint("%#8.8lux=%#8.8lux ", l, v);
583                                 i++;
584                         }
585                 }
586                 if(i == 4){
587                         i = 0;
588                         iprint("\n");
589                 }
590         }
591         if(i)
592                 iprint("\n");
593 }
594
595 /*
596  * Fill in enough of Ureg to get a stack trace, and call a function.
597  * Used by debugging interface rdb.
598  */
599 void
600 callwithureg(void (*fn)(Ureg*))
601 {
602         Ureg ureg;
603
604         ureg.pc = getcallerpc(&fn);
605         ureg.sp = PTR2UINT(&fn);
606         fn(&ureg);
607 }
608
609 void
610 dumpstack(void)
611 {
612         callwithureg(dumpstackwithureg);
613 }
614
615 void
616 dumpregs(Ureg* ureg)
617 {
618         int s;
619
620         if (ureg == nil) {
621                 iprint("trap: no user process\n");
622                 return;
623         }
624         s = splhi();
625         iprint("trap: %s", trapname(ureg->type));
626         if(ureg != nil && (ureg->psr & PsrMask) != PsrMsvc)
627                 iprint(" in %s", trapname(ureg->psr));
628         iprint("\n");
629         iprint("psr %8.8lux type %2.2lux pc %8.8lux link %8.8lux\n",
630                 ureg->psr, ureg->type, ureg->pc, ureg->link);
631         iprint("R14 %8.8lux R13 %8.8lux R12 %8.8lux R11 %8.8lux R10 %8.8lux\n",
632                 ureg->r14, ureg->r13, ureg->r12, ureg->r11, ureg->r10);
633         iprint("R9  %8.8lux R8  %8.8lux R7  %8.8lux R6  %8.8lux R5  %8.8lux\n",
634                 ureg->r9, ureg->r8, ureg->r7, ureg->r6, ureg->r5);
635         iprint("R4  %8.8lux R3  %8.8lux R2  %8.8lux R1  %8.8lux R0  %8.8lux\n",
636                 ureg->r4, ureg->r3, ureg->r2, ureg->r1, ureg->r0);
637         iprint("stack is at %#p\n", ureg);
638         iprint("pc %#lux link %#lux\n", ureg->pc, ureg->link);
639
640         if(up)
641                 iprint("user stack: %#p-%#p\n", up->kstack, up->kstack+KSTACK-4);
642         else
643                 iprint("kernel stack: %8.8lux-%8.8lux\n",
644                         (ulong)(m+1), (ulong)m+BY2PG-4);
645         dumplongs("stack", (ulong *)(ureg + 1), 16);
646         delay(2000);
647         dumpstack();
648         splx(s);
649 }
650
651 void
652 idlehands(void)
653 {
654         extern void _idlehands(void);
655
656         _idlehands();
657 }
658
659 vlong
660 probeaddr(uintptr addr)
661 {
662         vlong v;
663         static Lock fltlck;
664
665         ilock(&fltlck);
666         trapped = 0;
667         probing = 1;
668         coherence();
669
670         v = *(ulong *)addr;     /* this may cause a fault */
671         USED(probing);
672         coherence();
673
674         probing = 0;
675         coherence();
676         if (trapped)
677                 v = -1;
678         iunlock(&fltlck);
679         return v;
680 }