Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – planix.SVN – Blame – /os/branches/feature-vt/sys/src/9/bcm/trap.c – Rev 2

Subversion Repositories planix.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
/*
2
 * 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
#define INTREGS		(VIRTIO+0xB200)
16
 
17
typedef struct Intregs Intregs;
18
typedef struct Vctl Vctl;
19
 
20
enum {
21
	Debug = 0,
22
 
23
	Nvec = 8,		/* # of vectors at start of lexception.s */
24
	Fiqenable = 1<<7,
25
};
26
 
27
/*
28
 *   Layout at virtual address KZERO (double mapped at HVECTORS).
29
 */
30
typedef struct Vpage0 {
31
	void	(*vectors[Nvec])(void);
32
	u32int	vtable[Nvec];
33
} Vpage0;
34
 
35
/*
36
 * interrupt control registers
37
 */
38
struct Intregs {
39
	u32int	ARMpending;
40
	u32int	GPUpending[2];
41
	u32int	FIQctl;
42
	u32int	GPUenable[2];
43
	u32int	ARMenable;
44
	u32int	GPUdisable[2];
45
	u32int	ARMdisable;
46
};
47
 
48
struct Vctl {
49
	Vctl	*next;
50
	int	irq;
51
	u32int	*reg;
52
	u32int	mask;
53
	void	(*f)(Ureg*, void*);
54
	void	*a;
55
};
56
 
57
static Vctl *vctl, *vfiq;
58
 
59
static char *trapnames[PsrMask+1] = {
60
	[ PsrMusr ] "user mode",
61
	[ PsrMfiq ] "fiq interrupt",
62
	[ PsrMirq ] "irq interrupt",
63
	[ PsrMsvc ] "svc/swi exception",
64
	[ PsrMabt ] "prefetch abort/data abort",
65
	[ PsrMabt+1 ] "data abort",
66
	[ PsrMund ] "undefined instruction",
67
	[ PsrMsys ] "sys trap",
68
};
69
 
70
extern int notify(Ureg*);
71
 
72
/*
73
 *  set up for exceptions
74
 */
75
void
76
trapinit(void)
77
{
78
	Vpage0 *vpage0;
79
 
80
	/* disable everything */
81
	intrsoff();
82
 
83
	/* set up the exception vectors */
84
	vpage0 = (Vpage0*)HVECTORS;
85
	memmove(vpage0->vectors, vectors, sizeof(vpage0->vectors));
86
	memmove(vpage0->vtable, vtable, sizeof(vpage0->vtable));
87
	cacheuwbinv();
88
 
89
	/* set up the stacks for the interrupt modes */
90
	setr13(PsrMfiq, (u32int*)(FIQSTKTOP));
91
	setr13(PsrMirq, m->sirq);
92
	setr13(PsrMabt, m->sabt);
93
	setr13(PsrMund, m->sund);
94
	setr13(PsrMsys, m->ssys);
95
 
96
	coherence();
97
}
98
 
99
void
100
intrsoff(void)
101
{
102
	Intregs *ip;
103
	int disable;
104
 
105
	ip = (Intregs*)INTREGS;
106
	disable = ~0;
107
	ip->GPUdisable[0] = disable;
108
	ip->GPUdisable[1] = disable;
109
	ip->ARMdisable = disable;
110
	ip->FIQctl = 0;
111
}
112
 
113
/*
114
 *  called by trap to handle irq interrupts.
115
 *  returns true iff a clock interrupt, thus maybe reschedule.
116
 */
117
static int
118
irq(Ureg* ureg)
119
{
120
	Vctl *v;
121
	int clockintr;
122
 
123
	clockintr = 0;
124
	for(v = vctl; v; v = v->next)
125
		if(*v->reg & v->mask){
126
			coherence();
127
			v->f(ureg, v->a);
128
			coherence();
129
			if(v->irq == IRQclock)
130
				clockintr = 1;
131
		}
132
	return clockintr;
133
}
134
 
135
/*
136
 * called direct from lexception.s to handle fiq interrupt.
137
 */
138
void
139
fiq(Ureg *ureg)
140
{
141
	Vctl *v;
142
 
143
	v = vfiq;
144
	if(v == nil)
145
		panic("unexpected item in bagging area");
146
	m->intr++;
147
	ureg->pc -= 4;
148
	coherence();
149
	v->f(ureg, v->a);
150
	coherence();
151
}
152
 
153
void
154
irqenable(int irq, void (*f)(Ureg*, void*), void* a)
155
{
156
	Vctl *v;
157
	Intregs *ip;
158
	u32int *enable;
159
 
160
	ip = (Intregs*)INTREGS;
161
	v = (Vctl*)malloc(sizeof(Vctl));
162
	if(v == nil)
163
		panic("irqenable: no mem");
164
	v->irq = irq;
165
	if(irq >= IRQbasic){
166
		enable = &ip->ARMenable;
167
		v->reg = &ip->ARMpending;
168
		v->mask = 1 << (irq - IRQbasic);
169
	}else{
170
		enable = &ip->GPUenable[irq/32];
171
		v->reg = &ip->GPUpending[irq/32];
172
		v->mask = 1 << (irq % 32);
173
	}
174
	v->f = f;
175
	v->a = a;
176
	if(irq == IRQfiq){
177
		assert((ip->FIQctl & Fiqenable) == 0);
178
		assert((*enable & v->mask) == 0);
179
		vfiq = v;
180
		ip->FIQctl = Fiqenable | irq;
181
	}else{
182
		v->next = vctl;
183
		vctl = v;
184
		*enable = v->mask;
185
	}
186
}
187
 
188
static char *
189
trapname(int psr)
190
{
191
	char *s;
192
 
193
	s = trapnames[psr & PsrMask];
194
	if(s == nil)
195
		s = "unknown trap number in psr";
196
	return s;
197
}
198
 
199
/* this is quite helpful during mmu and cache debugging */
200
static void
201
ckfaultstuck(uintptr va)
202
{
203
	static int cnt, lastpid;
204
	static uintptr lastva;
205
 
206
	if (va == lastva && up->pid == lastpid) {
207
		++cnt;
208
		if (cnt >= 2)
209
			/* fault() isn't fixing the underlying cause */
210
			panic("fault: %d consecutive faults for va %#p",
211
				cnt+1, va);
212
	} else {
213
		cnt = 0;
214
		lastva = va;
215
		lastpid = up->pid;
216
	}
217
}
218
 
219
/*
220
 *  called by trap to handle access faults
221
 */
222
static void
223
faultarm(Ureg *ureg, uintptr va, int user, int read)
224
{
225
	int n, insyscall;
226
	char buf[ERRMAX];
227
 
228
	if(up == nil) {
229
		dumpregs(ureg);
230
		panic("fault: nil up in faultarm, accessing %#p", va);
231
	}
232
	insyscall = up->insyscall;
233
	up->insyscall = 1;
234
	if (Debug)
235
		ckfaultstuck(va);
236
 
237
	n = fault(va, read);
238
	if(n < 0){
239
		if(!user){
240
			dumpregs(ureg);
241
			panic("fault: kernel accessing %#p", va);
242
		}
243
		/* don't dump registers; programs suicide all the time */
244
		snprint(buf, sizeof buf, "sys: trap: fault %s va=%#p",
245
			read? "read": "write", va);
246
		postnote(up, 1, buf, NDebug);
247
	}
248
	up->insyscall = insyscall;
249
}
250
 
251
/*
252
 *  returns 1 if the instruction writes memory, 0 otherwise
253
 */
254
int
255
writetomem(ulong inst)
256
{
257
	/* swap always write memory */
258
	if((inst & 0x0FC00000) == 0x01000000)
259
		return 1;
260
 
261
	/* loads and stores are distinguished by bit 20 */
262
	if(inst & (1<<20))
263
		return 0;
264
 
265
	return 1;
266
}
267
 
268
/*
269
 *  here on all exceptions other than syscall (SWI) and fiq
270
 */
271
void
272
trap(Ureg *ureg)
273
{
274
	int clockintr, user, x, rv, rem;
275
	ulong inst, fsr;
276
	uintptr va;
277
	char buf[ERRMAX];
278
 
279
	assert(!islo());
280
	if(up != nil)
281
		rem = ((char*)ureg)-up->kstack;
282
	else
283
		rem = ((char*)ureg)-((char*)m+sizeof(Mach));
284
	if(rem < 256) {
285
		iprint("trap: %d stack bytes left, up %#p ureg %#p at pc %#lux\n",
286
			rem, up, ureg, ureg->pc);
287
		delay(1000);
288
		dumpstack();
289
		panic("trap: %d stack bytes left, up %#p ureg %#p at pc %#lux",
290
			rem, up, ureg, ureg->pc);
291
	}
292
 
293
	user = (ureg->psr & PsrMask) == PsrMusr;
294
	if(user){
295
		up->dbgreg = ureg;
296
		cycles(&up->kentry);
297
	}
298
 
299
	/*
300
	 * All interrupts/exceptions should be resumed at ureg->pc-4,
301
	 * except for Data Abort which resumes at ureg->pc-8.
302
	 */
303
	if(ureg->type == (PsrMabt+1))
304
		ureg->pc -= 8;
305
	else
306
		ureg->pc -= 4;
307
 
308
	clockintr = 0;		/* if set, may call sched() before return */
309
	switch(ureg->type){
310
	default:
311
		panic("unknown trap; type %#lux, psr mode %#lux", ureg->type,
312
			ureg->psr & PsrMask);
313
		break;
314
	case PsrMirq:
315
		clockintr = irq(ureg);
316
		m->intr++;
317
		break;
318
	case PsrMabt:			/* prefetch fault */
319
		x = ifsrget();
320
		fsr = (x>>7) & 0x8 | x & 0x7;
321
		switch(fsr){
322
		case 0x02:		/* instruction debug event (BKPT) */
323
			if(user){
324
				snprint(buf, sizeof buf, "sys: breakpoint");
325
				postnote(up, 1, buf, NDebug);
326
			}else{
327
				iprint("kernel bkpt: pc %#lux inst %#ux\n",
328
					ureg->pc, *(u32int*)ureg->pc);
329
				panic("kernel bkpt");
330
			}
331
			break;
332
		default:
333
			faultarm(ureg, ureg->pc, user, 1);
334
			break;
335
		}
336
		break;
337
	case PsrMabt+1:			/* data fault */
338
		va = farget();
339
		inst = *(ulong*)(ureg->pc);
340
		/* bits 12 and 10 have to be concatenated with status */
341
		x = fsrget();
342
		fsr = (x>>7) & 0x20 | (x>>6) & 0x10 | x & 0xf;
343
		switch(fsr){
344
		default:
345
		case 0xa:		/* ? was under external abort */
346
			panic("unknown data fault, 6b fsr %#lux", fsr);
347
			break;
348
		case 0x0:
349
			panic("vector exception at %#lux", ureg->pc);
350
			break;
351
		case 0x1:		/* alignment fault */
352
		case 0x3:		/* access flag fault (section) */
353
			if(user){
354
				snprint(buf, sizeof buf,
355
					"sys: alignment: pc %#lux va %#p\n",
356
					ureg->pc, va);
357
				postnote(up, 1, buf, NDebug);
358
			} else
359
				panic("kernel alignment: pc %#lux va %#p", ureg->pc, va);
360
			break;
361
		case 0x2:
362
			panic("terminal exception at %#lux", ureg->pc);
363
			break;
364
		case 0x4:		/* icache maint fault */
365
		case 0x6:		/* access flag fault (page) */
366
		case 0x8:		/* precise external abort, non-xlat'n */
367
		case 0x28:
368
		case 0xc:		/* l1 translation, precise ext. abort */
369
		case 0x2c:
370
		case 0xe:		/* l2 translation, precise ext. abort */
371
		case 0x2e:
372
		case 0x16:		/* imprecise ext. abort, non-xlt'n */
373
		case 0x36:
374
			panic("external abort %#lux pc %#lux addr %#p",
375
				fsr, ureg->pc, va);
376
			break;
377
		case 0x1c:		/* l1 translation, precise parity err */
378
		case 0x1e:		/* l2 translation, precise parity err */
379
		case 0x18:		/* imprecise parity or ecc err */
380
			panic("translation parity error %#lux pc %#lux addr %#p",
381
				fsr, ureg->pc, va);
382
			break;
383
		case 0x5:		/* translation fault, no section entry */
384
		case 0x7:		/* translation fault, no page entry */
385
			faultarm(ureg, va, user, !writetomem(inst));
386
			break;
387
		case 0x9:
388
		case 0xb:
389
			/* domain fault, accessing something we shouldn't */
390
			if(user){
391
				snprint(buf, sizeof buf,
392
					"sys: access violation: pc %#lux va %#p\n",
393
					ureg->pc, va);
394
				postnote(up, 1, buf, NDebug);
395
			} else
396
				panic("kernel access violation: pc %#lux va %#p",
397
					ureg->pc, va);
398
			break;
399
		case 0xd:
400
		case 0xf:
401
			/* permission error, copy on write or real permission error */
402
			faultarm(ureg, va, user, !writetomem(inst));
403
			break;
404
		}
405
		break;
406
	case PsrMund:			/* undefined instruction */
407
		if(user){
408
			if(seg(up, ureg->pc, 0) != nil &&
409
			   *(u32int*)ureg->pc == 0xD1200070)
410
				postnote(up, 1, "sys: breakpoint", NDebug);
411
			else{
412
				/* look for floating point instructions to interpret */
413
				rv = fpuemu(ureg);
414
				if(rv == 0){
415
					snprint(buf, sizeof buf,
416
						"undefined instruction: pc %#lux\n",
417
						ureg->pc);
418
					postnote(up, 1, buf, NDebug);
419
				}
420
			}
421
		}else{
422
			if (ureg->pc & 3) {
423
				iprint("rounding fault pc %#lux down to word\n",
424
					ureg->pc);
425
				ureg->pc &= ~3;
426
			}
427
			iprint("undefined instruction: pc %#lux inst %#ux\n",
428
				ureg->pc, *(u32int*)ureg->pc);
429
			panic("undefined instruction");
430
		}
431
		break;
432
	}
433
	splhi();
434
 
435
	/* delaysched set because we held a lock or because our quantum ended */
436
	if(up && up->delaysched && clockintr){
437
		sched();		/* can cause more traps */
438
		splhi();
439
	}
440
 
441
	if(user){
442
		if(up->procctl || up->nnote)
443
			notify(ureg);
444
		kexit(ureg);
445
	}
446
}
447
 
448
int
449
isvalidaddr(void *v)
450
{
451
	return (uintptr)v >= KZERO;
452
}
453
 
454
static void
455
dumplongs(char *msg, ulong *v, int n)
456
{
457
	int i, l;
458
 
459
	l = 0;
460
	iprint("%s at %.8p: ", msg, v);
461
	for(i=0; i<n; i++){
462
		if(l >= 4){
463
			iprint("\n    %.8p: ", v);
464
			l = 0;
465
		}
466
		if(isvalidaddr(v)){
467
			iprint(" %.8lux", *v++);
468
			l++;
469
		}else{
470
			iprint(" invalid");
471
			break;
472
		}
473
	}
474
	iprint("\n");
475
}
476
 
477
static void
478
dumpstackwithureg(Ureg *ureg)
479
{
480
	uintptr l, i, v, estack;
481
	u32int *p;
482
	char *s;
483
 
484
	if((s = getconf("*nodumpstack")) != nil && strcmp(s, "0") != 0){
485
		iprint("dumpstack disabled\n");
486
		return;
487
	}
488
	iprint("ktrace /kernel/path %#.8lux %#.8lux %#.8lux # pc, sp, link\n",
489
		ureg->pc, ureg->sp, ureg->r14);
490
	delay(2000);
491
	i = 0;
492
	if(up != nil && (uintptr)&l <= (uintptr)up->kstack+KSTACK)
493
		estack = (uintptr)up->kstack+KSTACK;
494
	else if((uintptr)&l >= (uintptr)m->stack
495
	     && (uintptr)&l <= (uintptr)m+MACHSIZE)
496
		estack = (uintptr)m+MACHSIZE;
497
	else{
498
		if(up != nil)
499
			iprint("&up->kstack %#p &l %#p\n", up->kstack, &l);
500
		else
501
			iprint("&m %#p &l %#p\n", m, &l);
502
		return;
503
	}
504
	for(l = (uintptr)&l; l < estack; l += sizeof(uintptr)){
505
		v = *(uintptr*)l;
506
		if(KTZERO < v && v < (uintptr)etext && !(v & 3)){
507
			v -= sizeof(u32int);		/* back up an instr */
508
			p = (u32int*)v;
509
			if((*p & 0x0f000000) == 0x0b000000){	/* BL instr? */
510
				iprint("%#8.8lux=%#8.8lux ", l, v);
511
				i++;
512
			}
513
		}
514
		if(i == 4){
515
			i = 0;
516
			iprint("\n");
517
		}
518
	}
519
	if(i)
520
		iprint("\n");
521
}
522
 
523
/*
524
 * Fill in enough of Ureg to get a stack trace, and call a function.
525
 * Used by debugging interface rdb.
526
 */
527
void
528
callwithureg(void (*fn)(Ureg*))
529
{
530
	Ureg ureg;
531
 
532
	ureg.pc = getcallerpc(&fn);
533
	ureg.sp = PTR2UINT(&fn);
534
	fn(&ureg);
535
}
536
 
537
void
538
dumpstack(void)
539
{
540
	callwithureg(dumpstackwithureg);
541
}
542
 
543
void
544
dumpregs(Ureg* ureg)
545
{
546
	int s;
547
 
548
	if (ureg == nil) {
549
		iprint("trap: no user process\n");
550
		return;
551
	}
552
	s = splhi();
553
	iprint("trap: %s", trapname(ureg->type));
554
	if(ureg != nil && (ureg->psr & PsrMask) != PsrMsvc)
555
		iprint(" in %s", trapname(ureg->psr));
556
	iprint("\n");
557
	iprint("psr %8.8lux type %2.2lux pc %8.8lux link %8.8lux\n",
558
		ureg->psr, ureg->type, ureg->pc, ureg->link);
559
	iprint("R14 %8.8lux R13 %8.8lux R12 %8.8lux R11 %8.8lux R10 %8.8lux\n",
560
		ureg->r14, ureg->r13, ureg->r12, ureg->r11, ureg->r10);
561
	iprint("R9  %8.8lux R8  %8.8lux R7  %8.8lux R6  %8.8lux R5  %8.8lux\n",
562
		ureg->r9, ureg->r8, ureg->r7, ureg->r6, ureg->r5);
563
	iprint("R4  %8.8lux R3  %8.8lux R2  %8.8lux R1  %8.8lux R0  %8.8lux\n",
564
		ureg->r4, ureg->r3, ureg->r2, ureg->r1, ureg->r0);
565
	iprint("stack is at %#p\n", ureg);
566
	iprint("pc %#lux link %#lux\n", ureg->pc, ureg->link);
567
 
568
	if(up)
569
		iprint("user stack: %#p-%#p\n", up->kstack, up->kstack+KSTACK-4);
570
	else
571
		iprint("kernel stack: %8.8lux-%8.8lux\n",
572
			(ulong)(m+1), (ulong)m+BY2PG-4);
573
	dumplongs("stack", (ulong *)(ureg + 1), 16);
574
	delay(2000);
575
	dumpstack();
576
	splx(s);
577
}