Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

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