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
irqinuse(uint irq)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
intcmask(uint irq)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
intcunmask(uint irq)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
intcmaskall(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
intcunmaskall(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
intcinvertall(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
intrsave(ulong buf[3])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
intrrestore(ulong buf[3])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
trapinit(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
intrsoff(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
irqenable(int irq,void (* f)(Ureg *,void *),void * a,char * name)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
irqdisable(int irq,void (* f)(Ureg *,void *),void * a,char * name)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
faultarm(Ureg * ureg,uintptr va,int user,int read)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, 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
irq(Ureg * ureg)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(" (IC)");
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
writetomem(ulong inst)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
trap(Ureg * ureg)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 = (ureg->psr & PsrMask) == PsrMusr;
469 if(user){
470 up->dbgreg = ureg;
471 cycles(&up->kentry);
472 }
473
474 /*
475 * All interrupts/exceptions should be resumed at ureg->pc-4,
476 * except for Data Abort which resumes at ureg->pc-8.
477 */
478 if(ureg->type == (PsrMabt+1))
479 ureg->pc -= 8;
480 else
481 ureg->pc -= 4;
482
483 clockintr = 0; /* if set, may call sched() before return */
484 switch(ureg->type){
485 default:
486 panic("unknown trap; type %#lux, psr mode %#lux", ureg->type,
487 ureg->psr & PsrMask);
488 break;
489 case PsrMirq:
490 ldrexvalid = 0;
491 clockintr = irq(ureg);
492 m->intr++;
493 break;
494 case PsrMabt: /* prefetch fault */
495 ldrexvalid = 0;
496 x = ifsrget();
497 fsr = (x>>7) & 0x8 | x & 0x7;
498 switch(fsr){
499 case 0x02: /* instruction debug event (BKPT) */
500 if(user){
501 snprint(buf, sizeof buf, "sys: breakpoint");
502 postnote(up, 1, buf, NDebug);
503 }else{
504 iprint("kernel bkpt: pc %#lux inst %#ux\n",
505 ureg->pc, *(u32int*)ureg->pc);
506 panic("kernel bkpt");
507 }
508 break;
509 default:
510 faultarm(ureg, ureg->pc, user, 1);
511 break;
512 }
513 break;
514 case PsrMabt+1: /* data fault */
515 ldrexvalid = 0;
516 va = farget();
517 inst = *(ulong*)(ureg->pc);
518 /* bits 12 and 10 have to be concatenated with status */
519 x = fsrget();
520 fsr = (x>>7) & 0x20 | (x>>6) & 0x10 | x & 0xf;
521 if (probing && !user) {
522 if (trapped++ > 0)
523 panic("trap: recursive probe %#lux", va);
524 ureg->pc += 4; /* continue at next instruction */
525 break;
526 }
527 switch(fsr){
528 default:
529 case 0xa: /* ? was under external abort */
530 panic("unknown data fault, 6b fsr %#lux", fsr);
531 break;
532 case 0x0:
533 panic("vector exception at %#lux", ureg->pc);
534 break;
535 case 0x1: /* alignment fault */
536 case 0x3: /* access flag fault (section) */
537 if(user){
538 snprint(buf, sizeof buf,
539 "sys: alignment: pc %#lux va %#p\n",
540 ureg->pc, va);
541 postnote(up, 1, buf, NDebug);
542 } else
543 panic("kernel alignment: pc %#lux va %#p", ureg->pc, va);
544 break;
545 case 0x2:
546 panic("terminal exception at %#lux", ureg->pc);
547 break;
548 case 0x4: /* icache maint fault */
549 case 0x6: /* access flag fault (page) */
550 case 0x8: /* precise external abort, non-xlat'n */
551 case 0x28:
552 case 0xc: /* l1 translation, precise ext. abort */
553 case 0x2c:
554 case 0xe: /* l2 translation, precise ext. abort */
555 case 0x2e:
556 case 0x16: /* imprecise ext. abort, non-xlt'n */
557 case 0x36:
558 panic("external abort %#lux pc %#lux addr %#p",
559 fsr, ureg->pc, va);
560 break;
561 case 0x1c: /* l1 translation, precise parity err */
562 case 0x1e: /* l2 translation, precise parity err */
563 case 0x18: /* imprecise parity or ecc err */
564 panic("translation parity error %#lux pc %#lux addr %#p",
565 fsr, ureg->pc, va);
566 break;
567 case 0x5: /* translation fault, no section entry */
568 case 0x7: /* translation fault, no page entry */
569 faultarm(ureg, va, user, !writetomem(inst));
570 break;
571 case 0x9:
572 case 0xb:
573 /* domain fault, accessing something we shouldn't */
574 if(user){
575 snprint(buf, sizeof buf,
576 "sys: access violation: pc %#lux va %#p\n",
577 ureg->pc, va);
578 postnote(up, 1, buf, NDebug);
579 } else
580 panic("kernel access violation: pc %#lux va %#p",
581 ureg->pc, va);
582 break;
583 case 0xd:
584 case 0xf:
585 /* permission error, copy on write or real permission error */
586 faultarm(ureg, va, user, !writetomem(inst));
587 break;
588 }
589 break;
590 case PsrMund: /* undefined instruction */
591 if(user){
592 if(seg(up, ureg->pc, 0) != nil &&
593 *(u32int*)ureg->pc == 0xD1200070){
594 snprint(buf, sizeof buf, "sys: breakpoint");
595 postnote(up, 1, buf, NDebug);
596 }else{
597 /* look for floating point instructions to interpret */
598 x = spllo();
599 rv = fpiarm(ureg);
600 splx(x);
601 if(rv == 0){
602 ldrexvalid = 0;
603 snprint(buf, sizeof buf,
604 "undefined instruction: pc %#lux\n",
605 ureg->pc);
606 postnote(up, 1, buf, NDebug);
607 }
608 }
609 }else{
610 if (ureg->pc & 3) {
611 iprint("rounding fault pc %#lux down to word\n",
612 ureg->pc);
613 ureg->pc &= ~3;
614 }
615 iprint("undefined instruction: pc %#lux inst %#ux\n",
616 ureg->pc, ((u32int*)ureg->pc)[-2]);
617 panic("undefined instruction");
618 }
619 break;
620 }
621 splhi();
622
623 /* delaysched set because we held a lock or because our quantum ended */
624 if(up && up->delaysched && clockintr){
625 ldrexvalid = 0;
626 sched(); /* can cause more traps */
627 splhi();
628 }
629
630 if(user){
631 if(up->procctl || up->nnote)
632 notify(ureg);
633 kexit(ureg);
634 }
635 }
636
637 /*
638 * Fill in enough of Ureg to get a stack trace, and call a function.
639 * Used by debugging interface rdb.
640 */
641 void
callwithureg(void (* fn)(Ureg *))642 callwithureg(void (*fn)(Ureg*))
643 {
644 Ureg ureg;
645
646 ureg.pc = getcallerpc(&fn);
647 ureg.sp = PTR2UINT(&fn);
648 fn(&ureg);
649 }
650
651 static void
dumpstackwithureg(Ureg * ureg)652 dumpstackwithureg(Ureg *ureg)
653 {
654 int x;
655 uintptr l, v, i, estack;
656 char *s;
657
658 dumpregs(ureg);
659 if((s = getconf("*nodumpstack")) != nil && strcmp(s, "0") != 0){
660 iprint("dumpstack disabled\n");
661 return;
662 }
663 iprint("dumpstack\n");
664
665 x = 0;
666 x += iprint("ktrace /kernel/path %#.8lux %#.8lux %#.8lux # pc, sp, link\n",
667 ureg->pc, ureg->sp, ureg->r14);
668 delay(20);
669 i = 0;
670 if(up
671 && (uintptr)&l >= (uintptr)up->kstack
672 && (uintptr)&l <= (uintptr)up->kstack+KSTACK)
673 estack = (uintptr)up->kstack+KSTACK;
674 else if((uintptr)&l >= (uintptr)m->stack
675 && (uintptr)&l <= (uintptr)m+MACHSIZE)
676 estack = (uintptr)m+MACHSIZE;
677 else
678 return;
679 x += iprint("estackx %p\n", estack);
680
681 for(l = (uintptr)&l; l < estack; l += sizeof(uintptr)){
682 v = *(uintptr*)l;
683 if((KTZERO < v && v < (uintptr)etext) || estack-l < 32){
684 x += iprint("%.8p ", v);
685 delay(20);
686 i++;
687 }
688 if(i == 8){
689 i = 0;
690 x += iprint("\n");
691 delay(20);
692 }
693 }
694 if(i)
695 iprint("\n");
696 }
697
698 void
dumpstack(void)699 dumpstack(void)
700 {
701 callwithureg(dumpstackwithureg);
702 }
703
704 /*
705 * dump system control coprocessor registers
706 */
707 static void
dumpscr(void)708 dumpscr(void)
709 {
710 iprint("0:\t%#8.8ux id\n", cpidget());
711 iprint("\t%8.8#ux ct\n", cpctget());
712 iprint("1:\t%#8.8ux control\n", controlget());
713 iprint("2:\t%#8.8ux ttb\n", ttbget());
714 iprint("3:\t%#8.8ux dac\n", dacget());
715 iprint("4:\t(reserved)\n");
716 iprint("5:\t%#8.8ux fsr\n", fsrget());
717 iprint("6:\t%#8.8ux far\n", farget());
718 iprint("7:\twrite-only cache\n");
719 iprint("8:\twrite-only tlb\n");
720 iprint("13:\t%#8.8ux pid\n", pidget());
721 delay(10);
722 }
723
724 /*
725 * dump general registers
726 */
727 static void
dumpgpr(Ureg * ureg)728 dumpgpr(Ureg* ureg)
729 {
730 if(up != nil)
731 iprint("cpu%d: registers for %s %lud\n",
732 m->machno, up->text, up->pid);
733 else
734 iprint("cpu%d: registers for kernel\n", m->machno);
735
736 delay(20);
737 iprint("%#8.8lux\tr0\n", ureg->r0);
738 iprint("%#8.8lux\tr1\n", ureg->r1);
739 iprint("%#8.8lux\tr2\n", ureg->r2);
740 delay(20);
741 iprint("%#8.8lux\tr3\n", ureg->r3);
742 iprint("%#8.8lux\tr4\n", ureg->r4);
743 iprint("%#8.8lux\tr5\n", ureg->r5);
744 delay(20);
745 iprint("%#8.8lux\tr6\n", ureg->r6);
746 iprint("%#8.8lux\tr7\n", ureg->r7);
747 iprint("%#8.8lux\tr8\n", ureg->r8);
748 delay(20);
749 iprint("%#8.8lux\tr9 (up)\n", ureg->r9);
750 iprint("%#8.8lux\tr10 (m)\n", ureg->r10);
751 iprint("%#8.8lux\tr11 (loader temporary)\n", ureg->r11);
752 iprint("%#8.8lux\tr12 (SB)\n", ureg->r12);
753 delay(20);
754 iprint("%#8.8lux\tr13 (sp)\n", ureg->r13);
755 iprint("%#8.8lux\tr14 (link)\n", ureg->r14);
756 iprint("%#8.8lux\tr15 (pc)\n", ureg->pc);
757 delay(20);
758 iprint("%10.10lud\ttype\n", ureg->type);
759 iprint("%#8.8lux\tpsr\n", ureg->psr);
760 delay(20);
761 }
762
763 void
dumpregs(Ureg * ureg)764 dumpregs(Ureg* ureg)
765 {
766 dumpgpr(ureg);
767 dumpscr();
768 }
769
770 vlong
probeaddr(uintptr addr)771 probeaddr(uintptr addr)
772 {
773 vlong v;
774 static Lock fltlck;
775
776 ilock(&fltlck);
777 trapped = 0;
778 probing = 1;
779 coherence();
780
781 v = *(ulong *)addr; /* this may cause a fault */
782 USED(probing);
783 coherence();
784
785 probing = 0;
786 coherence();
787 if (trapped)
788 v = -1;
789 iunlock(&fltlck);
790 return v;
791 }
792