]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/omap/trap.c
pc, pc64: warn when running out of conf.mem[] entries in meminit()
[plan9front.git] / sys / src / 9 / omap / trap.c
1 /*
2  * omap3530 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 "../port/error.h"
10
11 #include "ureg.h"
12 #include "arm.h"
13
14 enum {
15         Nirqs = 96,
16         Nvec = 8,               /* # of vectors at start of lexception.s */
17         Bi2long = BI2BY * sizeof(long),
18 };
19
20 extern int notify(Ureg*);
21
22 extern int ldrexvalid;
23
24 /* omap35x intc (aka mpu_intc) */
25 typedef struct Intrregs Intrregs;
26 struct Intrregs {
27         /*
28          * the manual inserts "INTCPS_" before each register name;
29          * we'll just assume the prefix.
30          */
31         uchar   _pad0[4*4];
32         ulong   sysconfig;
33         ulong   sysstatus;              /* ro */
34         uchar   _pad1[0x40 - 0x18];
35         ulong   sir_irq;                /* ro */
36         ulong   sir_fiq;                /* ro */
37         ulong   control;
38         ulong   protection;
39         ulong   idle;
40         uchar   _pad2[0x60 - 0x54];
41         ulong   irq_priority;
42         ulong   fiq_priority;
43         ulong   threshold;
44         uchar   _pad3[0x80 - 0x6c];
45         struct Bits {                   /* bitmaps */
46                 ulong   itr;            /* ro: pending intrs (no mask) */
47                 ulong   mir;            /* interrupt mask: 1 means masked */
48                 ulong   mir_clear;      /* wo: 1 sets the bit */
49                 ulong   mir_set;        /* wo: 1 clears the bit */
50                 ulong   isr_set;        /* software interrupts */
51                 ulong   isr_clear;      /* wo */
52                 ulong   pending_irq;    /* ro */
53                 ulong   pending_fiq;    /* ro */
54         } bits[3];                      /* 3*32 = 96 (Nirqs) */
55         ulong   ilr[Nirqs];
56 };
57
58 enum {
59         /* sysconfig bits */
60         Softreset       = 1<<1,
61
62         /* sysstatus bits */
63         Resetdone       = 1<<0,
64
65         /* sir_irq/fiq bits */
66         Activeirq       = MASK(7),
67
68         /* control bits */
69         Newirqagr       = 1<<0,
70
71         /* protection bits */
72         Protection      = 1<<0,
73
74         /* irq/fiq_priority bits */
75         Irqpriority     = MASK(6),
76
77         /* threshold bits */
78         Prioritythreshold = MASK(8),
79
80         /* ilr bits */
81         Priority        = MASK(8) - MASK(2),
82 };
83
84 typedef struct Vctl Vctl;
85 typedef struct Vctl {
86         Vctl*   next;           /* handlers on this vector */
87         char    *name;          /* of driver, xallocated */
88         void    (*f)(Ureg*, void*);     /* handler to call */
89         void*   a;              /* argument to call it with */
90 } Vctl;
91
92 static Lock vctllock;
93 static Vctl* vctl[Nirqs];
94
95 /*
96  *   Layout at virtual address 0.
97  */
98 typedef struct Vpage0 {
99         void    (*vectors[Nvec])(void);
100         u32int  vtable[Nvec];
101 } Vpage0;
102 static Vpage0 *vpage0;
103
104 uvlong ninterrupt;
105 uvlong ninterruptticks;
106 int irqtooearly = 1;
107
108 static volatile int probing, trapped;
109
110 static int
111 irqinuse(uint irq)
112 {
113         Intrregs *ip = (Intrregs *)PHYSINTC;
114
115         /*
116          * mir registers are odd: a 0 bit means intr unmasked (i.e.,
117          * we've unmasked it because it's in use).
118          */
119         return (ip->bits[irq / Bi2long].mir & (1 << (irq % Bi2long))) == 0;
120 }
121
122 static void
123 intcmask(uint irq)
124 {
125         Intrregs *ip = (Intrregs *)PHYSINTC;
126
127         ip->bits[irq / Bi2long].mir_set = 1 << (irq % Bi2long);
128         coherence();
129 }
130
131 static void
132 intcunmask(uint irq)
133 {
134         Intrregs *ip = (Intrregs *)PHYSINTC;
135
136         ip->bits[irq / Bi2long].mir_clear = 1 << (irq % Bi2long);
137         coherence();
138 }
139
140 static void
141 intcmaskall(void)
142 {
143         int i;
144         Intrregs *ip = (Intrregs *)PHYSINTC;
145
146         for (i = 0; i < 3; i++)
147                 ip->bits[i].mir_set = ~0;
148         coherence();
149 }
150
151 static void
152 intcunmaskall(void)
153 {
154         int i;
155         Intrregs *ip = (Intrregs *)PHYSINTC;
156
157         for (i = 0; i < 3; i++)
158                 ip->bits[i].mir_clear = ~0;
159         coherence();
160 }
161
162 static void
163 intcinvertall(void)
164 {
165         int i, s;
166         ulong bits;
167         Intrregs *ip = (Intrregs *)PHYSINTC;
168
169         s = splhi();
170         for (i = 0; i < 3; i++) {
171                 bits = ip->bits[i].mir;
172                 ip->bits[i].mir_set = ~0;       /* mask all */
173                 coherence();
174                 /* clearing enables only those intrs. that were disabled */
175                 ip->bits[i].mir_clear = bits;
176         }
177         coherence();
178         splx(s);
179 }
180
181 static void
182 intrsave(ulong buf[3])
183 {
184         int i;
185         Intrregs *ip = (Intrregs *)PHYSINTC;
186
187         for (i = 0; i < nelem(buf); i++)
188                 buf[i] = ip->bits[i].mir;
189         coherence();
190 }
191
192 static void
193 intrrestore(ulong buf[3])
194 {
195         int i, s;
196         Intrregs *ip = (Intrregs *)PHYSINTC;
197
198         s = splhi();
199         for (i = 0; i < nelem(buf); i++) {
200                 ip->bits[i].mir_clear = ~0;     /* unmask all */
201                 coherence();
202                 ip->bits[i].mir_set = buf[i];   /* mask previously disabled */
203         }
204         coherence();
205         splx(s);
206 }
207
208 /*
209  *  set up for exceptions
210  */
211 void
212 trapinit(void)
213 {
214         int i;
215         Intrregs *ip = (Intrregs *)PHYSINTC;
216
217         /* set up the exception vectors */
218         vpage0 = (Vpage0*)HVECTORS;
219         memmove(vpage0->vectors, vectors, sizeof(vpage0->vectors));
220         memmove(vpage0->vtable, vtable, sizeof(vpage0->vtable));
221         cacheuwbinv();
222         l2cacheuwbinv();
223
224         /* set up the stacks for the interrupt modes */
225         setr13(PsrMfiq, m->sfiq);
226         setr13(PsrMirq, m->sirq);
227         setr13(PsrMabt, m->sabt);
228         setr13(PsrMund, m->sund);
229 #ifdef HIGH_SECURITY
230         setr13(PsrMmon, m->smon);
231 #endif
232         setr13(PsrMsys, m->ssys);
233
234         intcmaskall();
235         ip->control = 0;
236         ip->threshold = Prioritythreshold;      /* disable threshold */
237         for (i = 0; i < Nirqs; i++)
238                 ip->ilr[i] = 0<<2 | 0;  /* all intrs pri 0 & to irq, not fiq */
239         irqtooearly = 0;
240         coherence();
241 }
242
243 void
244 intrsoff(void)
245 {
246         Intrregs *ip = (Intrregs *)PHYSINTC;
247
248         intcmaskall();
249         ip->control = Newirqagr;        /* dismiss interrupt */
250         coherence();
251 }
252
253 /*
254  *  enable an irq interrupt
255  */
256 int
257 irqenable(int irq, void (*f)(Ureg*, void*), void* a, char *name)
258 {
259         Vctl *v;
260
261         if(irq >= nelem(vctl) || irq < 0)
262                 panic("irqenable irq %d", irq);
263
264         if (irqtooearly) {
265                 iprint("irqenable for %d %s called too early\n", irq, name);
266                 return -1;
267         }
268         if(irqinuse(irq))
269                 print("irqenable: %s: irq %d already in use, chaining\n",
270                         name, irq);
271         v = malloc(sizeof(Vctl));
272         if (v == nil)
273                 panic("irqenable: malloc Vctl");
274         v->f = f;
275         v->a = a;
276         v->name = malloc(strlen(name)+1);
277         if (v->name == nil)
278                 panic("irqenable: malloc name");
279         strcpy(v->name, name);
280
281         lock(&vctllock);
282         v->next = vctl[irq];
283         vctl[irq] = v;
284
285         intcunmask(irq);
286         unlock(&vctllock);
287         return 0;
288 }
289
290 /*
291  *  disable an irq interrupt
292  */
293 int
294 irqdisable(int irq, void (*f)(Ureg*, void*), void* a, char *name)
295 {
296         Vctl **vp, *v;
297
298         if(irq >= nelem(vctl) || irq < 0)
299                 panic("irqdisable irq %d", irq);
300
301         lock(&vctllock);
302         for(vp = &vctl[irq]; v = *vp; vp = &v->next)
303                 if (v->f == f && v->a == a && strcmp(v->name, name) == 0){
304                         print("irqdisable: remove %s\n", name);
305                         *vp = v->next;
306                         free(v);
307                         break;
308                 }
309
310         if(v == nil)
311                 print("irqdisable: irq %d, name %s not enabled\n", irq, name);
312         if(vctl[irq] == nil){
313                 print("irqdisable: clear icmr bit %d\n", irq);
314                 intcmask(irq);
315         }
316         unlock(&vctllock);
317
318         return 0;
319 }
320
321 /*
322  *  called by trap to handle access faults
323  */
324 static void
325 faultarm(Ureg *ureg, uintptr va, int user, int read)
326 {
327         int n, insyscall;
328         char buf[ERRMAX];
329
330         if(up == nil) {
331                 dumpregs(ureg);
332                 panic("fault: nil up in faultarm, accessing %#p", va);
333         }
334         insyscall = up->insyscall;
335         up->insyscall = 1;
336         n = fault(va, ureg->pc, read);
337         if(n < 0){
338                 if(!user){
339                         dumpregs(ureg);
340                         panic("fault: kernel accessing %#p", va);
341                 }
342                 /* don't dump registers; programs suicide all the time */
343                 snprint(buf, sizeof buf, "sys: trap: fault %s va=%#p",
344                         read? "read": "write", va);
345                 postnote(up, 1, buf, NDebug);
346         }
347         up->insyscall = insyscall;
348 }
349
350 /*
351  *  called by trap to handle interrupts.
352  *  returns true iff a clock interrupt, thus maybe reschedule.
353  */
354 static int
355 irq(Ureg* ureg)
356 {
357         int clockintr;
358         uint irqno, handled, t, ticks = perfticks();
359         Intrregs *ip = (Intrregs *)PHYSINTC;
360         Vctl *v;
361         static int nesting, lastirq = -1;
362
363         handled = 0;
364         irqno = ip->sir_irq & Activeirq;
365
366         if (irqno >= 37 && irqno <= 47)         /* this is a clock intr? */
367                 m->inclockintr++;               /* yes, count nesting */
368         lastirq = irqno;
369
370         if (irqno >= nelem(vctl)) {
371                 iprint("trap: irq %d >= # vectors (%d)\n", irqno, nelem(vctl));
372                 ip->control = Newirqagr;        /* dismiss interrupt */
373                 return 0;
374         }
375
376         ++nesting;
377         for(v = vctl[irqno]; v != nil; v = v->next)
378                 if (v->f) {
379                         if (islo())
380                                 panic("trap: pl0 before trap handler for %s",
381                                         v->name);
382                         v->f(ureg, v->a);
383                         if (islo())
384                                 panic("trap: %s lowered pl", v->name);
385 //                      splhi();                /* in case v->f lowered pl */
386                         handled++;
387                 }
388         if(!handled) {
389                 iprint("unexpected interrupt: irq %d", irqno);
390                 switch (irqno) {
391                 case 56:
392                 case 57:
393                         iprint(" (I⁲C)");
394                         break;
395                 case 83:
396                 case 86:
397                 case 94:
398                         iprint(" (MMC)");
399                         break;
400                 }
401
402                 if(irqno < nelem(vctl)) {
403                         intcmask(irqno);
404                         iprint(", now masked");
405                 }
406                 iprint("\n");
407         }
408         t = perfticks();
409         ninterrupt++;
410         if(t < ticks)
411                 ninterruptticks += ticks-t;
412         else
413                 ninterruptticks += t-ticks;
414         ip->control = Newirqagr;        /* dismiss interrupt */
415         coherence();
416
417         --nesting;
418         clockintr = m->inclockintr == 1;
419         if (irqno >= 37 && irqno <= 47)
420                 m->inclockintr--;
421         return clockintr;
422 }
423
424 /*
425  *  returns 1 if the instruction writes memory, 0 otherwise
426  */
427 int
428 writetomem(ulong inst)
429 {
430         /* swap always write memory */
431         if((inst & 0x0FC00000) == 0x01000000)
432                 return 1;
433
434         /* loads and stores are distinguished by bit 20 */
435         if(inst & (1<<20))
436                 return 0;
437
438         return 1;
439 }
440
441 void    prgpmcerrs(void);
442
443 /*
444  *  here on all exceptions other than syscall (SWI)
445  */
446 void
447 trap(Ureg *ureg)
448 {
449         int clockintr, user, x, rv, rem;
450         ulong inst, fsr;
451         uintptr va;
452         char buf[ERRMAX];
453
454         splhi();                        /* paranoia */
455         if(up != nil)
456                 rem = ((char*)ureg)-up->kstack;
457         else
458                 rem = ((char*)ureg)-((char*)m+sizeof(Mach));
459         if(rem < 1024) {
460                 iprint("trap: %d stack bytes left, up %#p ureg %#p at pc %#lux\n",
461                         rem, up, ureg, ureg->pc);
462                 delay(1000);
463                 dumpstack();
464                 panic("trap: %d stack bytes left, up %#p ureg %#p at pc %#lux",
465                         rem, up, ureg, ureg->pc);
466         }
467
468         user = kenter(ureg);
469         /*
470          * All interrupts/exceptions should be resumed at ureg->pc-4,
471          * except for Data Abort which resumes at ureg->pc-8.
472          */
473         if(ureg->type == (PsrMabt+1))
474                 ureg->pc -= 8;
475         else
476                 ureg->pc -= 4;
477
478         clockintr = 0;          /* if set, may call sched() before return */
479         switch(ureg->type){
480         default:
481                 panic("unknown trap; type %#lux, psr mode %#lux", ureg->type,
482                         ureg->psr & PsrMask);
483                 break;
484         case PsrMirq:
485                 ldrexvalid = 0;
486                 clockintr = irq(ureg);
487                 m->intr++;
488                 break;
489         case PsrMabt:                   /* prefetch fault */
490                 ldrexvalid = 0;
491                 x = ifsrget();
492                 fsr = (x>>7) & 0x8 | x & 0x7;
493                 switch(fsr){
494                 case 0x02:              /* instruction debug event (BKPT) */
495                         if(user){
496                                 snprint(buf, sizeof buf, "sys: breakpoint");
497                                 postnote(up, 1, buf, NDebug);
498                         }else{
499                                 iprint("kernel bkpt: pc %#lux inst %#ux\n",
500                                         ureg->pc, *(u32int*)ureg->pc);
501                                 panic("kernel bkpt");
502                         }
503                         break;
504                 default:
505                         faultarm(ureg, ureg->pc, user, 1);
506                         break;
507                 }
508                 break;
509         case PsrMabt+1:                 /* data fault */
510                 ldrexvalid = 0;
511                 va = farget();
512                 inst = *(ulong*)(ureg->pc);
513                 /* bits 12 and 10 have to be concatenated with status */
514                 x = fsrget();
515                 fsr = (x>>7) & 0x20 | (x>>6) & 0x10 | x & 0xf;
516                 if (probing && !user) {
517                         if (trapped++ > 0)
518                                 panic("trap: recursive probe %#lux", va);
519                         ureg->pc += 4;  /* continue at next instruction */
520                         break;
521                 }
522                 switch(fsr){
523                 default:
524                 case 0xa:               /* ? was under external abort */
525                         panic("unknown data fault, 6b fsr %#lux", fsr);
526                         break;
527                 case 0x0:
528                         panic("vector exception at %#lux", ureg->pc);
529                         break;
530                 case 0x1:               /* alignment fault */
531                 case 0x3:               /* access flag fault (section) */
532                         if(user){
533                                 snprint(buf, sizeof buf,
534                                         "sys: alignment: pc %#lux va %#p\n",
535                                         ureg->pc, va);
536                                 postnote(up, 1, buf, NDebug);
537                         } else
538                                 panic("kernel alignment: pc %#lux va %#p", ureg->pc, va);
539                         break;
540                 case 0x2:
541                         panic("terminal exception at %#lux", ureg->pc);
542                         break;
543                 case 0x4:               /* icache maint fault */
544                 case 0x6:               /* access flag fault (page) */
545                 case 0x8:               /* precise external abort, non-xlat'n */
546                 case 0x28:
547                 case 0xc:               /* l1 translation, precise ext. abort */
548                 case 0x2c:
549                 case 0xe:               /* l2 translation, precise ext. abort */
550                 case 0x2e:
551                 case 0x16:              /* imprecise ext. abort, non-xlt'n */
552                 case 0x36:
553                         panic("external abort %#lux pc %#lux addr %#p",
554                                 fsr, ureg->pc, va);
555                         break;
556                 case 0x1c:              /* l1 translation, precise parity err */
557                 case 0x1e:              /* l2 translation, precise parity err */
558                 case 0x18:              /* imprecise parity or ecc err */
559                         panic("translation parity error %#lux pc %#lux addr %#p",
560                                 fsr, ureg->pc, va);
561                         break;
562                 case 0x5:               /* translation fault, no section entry */
563                 case 0x7:               /* translation fault, no page entry */
564                         faultarm(ureg, va, user, !writetomem(inst));
565                         break;
566                 case 0x9:
567                 case 0xb:
568                         /* domain fault, accessing something we shouldn't */
569                         if(user){
570                                 snprint(buf, sizeof buf,
571                                         "sys: access violation: pc %#lux va %#p\n",
572                                         ureg->pc, va);
573                                 postnote(up, 1, buf, NDebug);
574                         } else
575                                 panic("kernel access violation: pc %#lux va %#p",
576                                         ureg->pc, va);
577                         break;
578                 case 0xd:
579                 case 0xf:
580                         /* permission error, copy on write or real permission error */
581                         faultarm(ureg, va, user, !writetomem(inst));
582                         break;
583                 }
584                 break;
585         case PsrMund:                   /* undefined instruction */
586                 if(user){
587                         if(seg(up, ureg->pc, 0) != nil &&
588                            *(u32int*)ureg->pc == 0xD1200070){
589                                 snprint(buf, sizeof buf, "sys: breakpoint");
590                                 postnote(up, 1, buf, NDebug);
591                         }else{
592                                 /* look for floating point instructions to interpret */
593                                 x = spllo();
594                                 rv = fpiarm(ureg);
595                                 splx(x);
596                                 if(rv == 0){
597                                         ldrexvalid = 0;
598                                         snprint(buf, sizeof buf,
599                                                 "undefined instruction: pc %#lux\n",
600                                                 ureg->pc);
601                                         postnote(up, 1, buf, NDebug);
602                                 }
603                         }
604                 }else{
605                         if (ureg->pc & 3) {
606                                 iprint("rounding fault pc %#lux down to word\n",
607                                         ureg->pc);
608                                 ureg->pc &= ~3;
609                         }
610                         iprint("undefined instruction: pc %#lux inst %#ux\n",
611                                 ureg->pc, ((u32int*)ureg->pc)[-2]);
612                         panic("undefined instruction");
613                 }
614                 break;
615         }
616         splhi();
617
618         /* delaysched set because we held a lock or because our quantum ended */
619         if(up && up->delaysched && clockintr){
620                 ldrexvalid = 0;
621                 sched();                /* can cause more traps */
622                 splhi();
623         }
624
625         if(user){
626                 if(up->procctl || up->nnote)
627                         notify(ureg);
628                 kexit(ureg);
629         }
630 }
631
632 /*
633  * Fill in enough of Ureg to get a stack trace, and call a function.
634  * Used by debugging interface rdb.
635  */
636 void
637 callwithureg(void (*fn)(Ureg*))
638 {
639         Ureg ureg;
640
641         ureg.pc = getcallerpc(&fn);
642         ureg.sp = (uintptr)&fn;
643         fn(&ureg);
644 }
645
646 static void
647 dumpstackwithureg(Ureg *ureg)
648 {
649         int x;
650         uintptr l, v, i, estack;
651         char *s;
652
653         dumpregs(ureg);
654         if((s = getconf("*nodumpstack")) != nil && strcmp(s, "0") != 0){
655                 iprint("dumpstack disabled\n");
656                 return;
657         }
658         iprint("dumpstack\n");
659
660         x = 0;
661         x += iprint("ktrace /kernel/path %#.8lux %#.8lux %#.8lux # pc, sp, link\n",
662                 ureg->pc, ureg->sp, ureg->r14);
663         delay(20);
664         i = 0;
665         if(up
666         && (uintptr)&l >= (uintptr)up->kstack
667         && (uintptr)&l <= (uintptr)up->kstack+KSTACK)
668                 estack = (uintptr)up->kstack+KSTACK;
669         else if((uintptr)&l >= (uintptr)m->stack
670         && (uintptr)&l <= (uintptr)m+MACHSIZE)
671                 estack = (uintptr)m+MACHSIZE;
672         else
673                 return;
674         x += iprint("estackx %p\n", estack);
675
676         for(l = (uintptr)&l; l < estack; l += sizeof(uintptr)){
677                 v = *(uintptr*)l;
678                 if((KTZERO < v && v < (uintptr)etext) || estack-l < 32){
679                         x += iprint("%.8p ", v);
680                         delay(20);
681                         i++;
682                 }
683                 if(i == 8){
684                         i = 0;
685                         x += iprint("\n");
686                         delay(20);
687                 }
688         }
689         if(i)
690                 iprint("\n");
691 }
692
693 void
694 dumpstack(void)
695 {
696         callwithureg(dumpstackwithureg);
697 }
698
699 /*
700  * dump system control coprocessor registers
701  */
702 static void
703 dumpscr(void)
704 {
705         iprint("0:\t%#8.8ux id\n", cpidget());
706         iprint("\t%8.8#ux ct\n", cpctget());
707         iprint("1:\t%#8.8ux control\n", controlget());
708         iprint("2:\t%#8.8ux ttb\n", ttbget());
709         iprint("3:\t%#8.8ux dac\n", dacget());
710         iprint("4:\t(reserved)\n");
711         iprint("5:\t%#8.8ux fsr\n", fsrget());
712         iprint("6:\t%#8.8ux far\n", farget());
713         iprint("7:\twrite-only cache\n");
714         iprint("8:\twrite-only tlb\n");
715         iprint("13:\t%#8.8ux pid\n", pidget());
716         delay(10);
717 }
718
719 /*
720  * dump general registers
721  */
722 static void
723 dumpgpr(Ureg* ureg)
724 {
725         if(up != nil)
726                 iprint("cpu%d: registers for %s %lud\n",
727                         m->machno, up->text, up->pid);
728         else
729                 iprint("cpu%d: registers for kernel\n", m->machno);
730
731         delay(20);
732         iprint("%#8.8lux\tr0\n", ureg->r0);
733         iprint("%#8.8lux\tr1\n", ureg->r1);
734         iprint("%#8.8lux\tr2\n", ureg->r2);
735         delay(20);
736         iprint("%#8.8lux\tr3\n", ureg->r3);
737         iprint("%#8.8lux\tr4\n", ureg->r4);
738         iprint("%#8.8lux\tr5\n", ureg->r5);
739         delay(20);
740         iprint("%#8.8lux\tr6\n", ureg->r6);
741         iprint("%#8.8lux\tr7\n", ureg->r7);
742         iprint("%#8.8lux\tr8\n", ureg->r8);
743         delay(20);
744         iprint("%#8.8lux\tr9 (up)\n", ureg->r9);
745         iprint("%#8.8lux\tr10 (m)\n", ureg->r10);
746         iprint("%#8.8lux\tr11 (loader temporary)\n", ureg->r11);
747         iprint("%#8.8lux\tr12 (SB)\n", ureg->r12);
748         delay(20);
749         iprint("%#8.8lux\tr13 (sp)\n", ureg->r13);
750         iprint("%#8.8lux\tr14 (link)\n", ureg->r14);
751         iprint("%#8.8lux\tr15 (pc)\n", ureg->pc);
752         delay(20);
753         iprint("%10.10lud\ttype\n", ureg->type);
754         iprint("%#8.8lux\tpsr\n", ureg->psr);
755         delay(20);
756 }
757
758 void
759 dumpregs(Ureg* ureg)
760 {
761         dumpgpr(ureg);
762         dumpscr();
763 }
764
765 vlong
766 probeaddr(uintptr addr)
767 {
768         vlong v;
769         static Lock fltlck;
770
771         ilock(&fltlck);
772         trapped = 0;
773         probing = 1;
774         coherence();
775
776         v = *(ulong *)addr;     /* this may cause a fault */
777         USED(probing);
778         coherence();
779
780         probing = 0;
781         coherence();
782         if (trapped)
783                 v = -1;
784         iunlock(&fltlck);
785         return v;
786 }