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
 * traps, exceptions, faults and interrupts on ar7161
3
 */
4
#include	"u.h"
5
#include	"../port/lib.h"
6
#include	"mem.h"
7
#include	"dat.h"
8
#include	"fns.h"
9
#include	"ureg.h"
10
#include	"io.h"
11
#include	<tos.h>
12
#include	"../port/error.h"
13
 
14
#define setstatus(v)	/* experiment: delete this to enable recursive traps */
15
 
16
typedef struct Handler Handler;
17
 
18
struct Handler {
19
	void	(*handler)(void *);
20
	void	*arg;
21
	Handler	*next;			/* at this interrupt level */
22
	ulong	intrs;
23
};
24
 
25
ulong offintrs;
26
ulong intrcauses[ILmax+1];
27
 
28
int	intr(Ureg*);
29
void	kernfault(Ureg*, int);
30
void	noted(Ureg*, Ureg**, ulong);
31
void	rfnote(Ureg**);
32
 
33
char *excname[] =
34
{
35
	"trap: external interrupt",
36
	"trap: TLB modification (store to unwritable)",
37
	"trap: TLB miss (load or fetch)",
38
	"trap: TLB miss (store)",
39
	"trap: address error (load or fetch)",
40
	"trap: address error (store)",
41
	"trap: bus error (fetch)",
42
	"trap: bus error (data load or store)",
43
	"trap: system call",
44
	"breakpoint",
45
	"trap: reserved instruction",
46
	"trap: coprocessor unusable",
47
	"trap: arithmetic overflow",
48
	"trap: TRAP exception",
49
	"trap: VCE (instruction)",
50
	"trap: floating-point exception",
51
	"trap: coprocessor 2 implementation-specific", /* used as sys call for debugger */
52
	"trap: corextend unusable",
53
	"trap: precise coprocessor 2 exception",
54
	"trap: TLB read-inhibit",
55
	"trap: TLB execute-inhibit",
56
	"trap: undefined 21",
57
	"trap: undefined 22",
58
	"trap: WATCH exception",
59
	"trap: machine checkcore",
60
	"trap: undefined 25",
61
	"trap: undefined 26",
62
	"trap: undefined 27",
63
	"trap: undefined 28",
64
	"trap: undefined 29",
65
	"trap: cache error",
66
	"trap: VCE (data)",
67
};
68
 
69
char *fpcause[] =
70
{
71
	"inexact operation",
72
	"underflow",
73
	"overflow",
74
	"division by zero",
75
	"invalid operation",
76
};
77
char	*fpexcname(Ureg*, ulong, char*, uint);
78
#define FPEXPMASK	(0x3f<<12)	/* Floating exception bits in fcr31 */
79
 
80
struct {
81
	char	*name;
82
	uint	off;
83
} regname[] = {
84
	"STATUS", Ureg_status,
85
	"PC",	Ureg_pc,
86
	"SP",	Ureg_sp,
87
	"CAUSE",Ureg_cause,
88
	"BADADDR", Ureg_badvaddr,
89
	"TLBVIRT", Ureg_tlbvirt,
90
	"HI",	Ureg_hi,
91
	"LO",	Ureg_lo,
92
	"R31",	Ureg_r31,
93
	"R30",	Ureg_r30,
94
	"R28",	Ureg_r28,
95
	"R27",	Ureg_r27,
96
	"R26",	Ureg_r26,
97
	"R25",	Ureg_r25,
98
	"R24",	Ureg_r24,
99
	"R23",	Ureg_r23,
100
	"R22",	Ureg_r22,
101
	"R21",	Ureg_r21,
102
	"R20",	Ureg_r20,
103
	"R19",	Ureg_r19,
104
	"R18",	Ureg_r18,
105
	"R17",	Ureg_r17,
106
	"R16",	Ureg_r16,
107
	"R15",	Ureg_r15,
108
	"R14",	Ureg_r14,
109
	"R13",	Ureg_r13,
110
	"R12",	Ureg_r12,
111
	"R11",	Ureg_r11,
112
	"R10",	Ureg_r10,
113
	"R9",	Ureg_r9,
114
	"R8",	Ureg_r8,
115
	"R7",	Ureg_r7,
116
	"R6",	Ureg_r6,
117
	"R5",	Ureg_r5,
118
	"R4",	Ureg_r4,
119
	"R3",	Ureg_r3,
120
	"R2",	Ureg_r2,
121
	"R1",	Ureg_r1,
122
};
123
 
124
static Lock intrlock;
125
static Handler handlers[ILmax+1];
126
 
127
static char *
128
ptlb(ulong phys)
129
{
130
	static char buf[4][32];
131
	static int k;
132
	char *p;
133
 
134
	k = (k+1)&3;
135
	p = buf[k];
136
	p += snprint(p, sizeof buf[k] - (p - buf[k]), "(%#lux %lud ",
137
		(phys<<6) & ~(BY2PG-1), (phys>>3)&7);
138
	if(phys & 4)
139
		*p++ = 'd';
140
	if(phys & 2)
141
		*p++ = 'v';
142
	if(phys & 1)
143
		*p++ = 'g';
144
	*p++ = ')';
145
	*p = 0;
146
	return buf[k];
147
}
148
 
149
static void
150
kpteprint(Ureg *ur)
151
{
152
	ulong i, tlbstuff[3];
153
	KMap *k;
154
 
155
	i = (ur->badvaddr & ~(2*BY2PG-1)) | TLBPID(tlbvirt());
156
	print("tlbvirt=%#lux\n", i);
157
	i = gettlbp(i, tlbstuff);
158
	print("i=%lud v=%#lux p0=%s p1=%s\n",
159
		i, tlbstuff[0], ptlb(tlbstuff[1]), ptlb(tlbstuff[2]));
160
 
161
	i = (ur->badvaddr & ~KMAPADDR)>>15;
162
	if(i > KPTESIZE){
163
		print("kpte index = %lud ?\n", i);
164
		return;
165
	}
166
	k = &kpte[i];
167
	print("i=%lud, &k=%#p, k={v=%#lux, p0=%s, p1=%s, pg=%#p}\n",
168
		i, k, k->virt, ptlb(k->phys0), ptlb(k->phys1), k->pg);
169
	print("pg={pa=%#lux, va=%#lux}\n", k->pg->pa, k->pg->va);
170
}
171
 
172
void
173
kvce(Ureg *ur, int ecode)
174
{
175
	char c;
176
	Pte **p;
177
	Page **pg;
178
	Segment *s;
179
	ulong addr, soff;
180
 
181
	c = 'D';
182
	if(ecode == CVCEI)
183
		c = 'I';
184
	print("Trap: VCE%c: addr=%#lux\n", c, ur->badvaddr);
185
	if((ur->badvaddr & KSEGM) == KSEG3) {
186
		kpteprint(ur);
187
		return;
188
	}
189
	if(up && !(ur->badvaddr & KSEGM)) {
190
		addr = ur->badvaddr;
191
		s = seg(up, addr, 0);
192
		if(s == 0){
193
			print("kvce: no seg for %#lux\n", addr);
194
			for(;;)
195
				;
196
		}
197
		addr &= ~(BY2PG-1);
198
		soff = addr - s->base;
199
		p = &s->map[soff/PTEMAPMEM];
200
		if(*p){
201
			pg = &(*p)->pages[(soff&(PTEMAPMEM-1))/BY2PG];
202
			if(*pg)
203
				print("kvce: pa=%#lux, va=%#lux\n",
204
					(*pg)->pa, (*pg)->va);
205
			else
206
				print("kvce: no *pg\n");
207
		}else
208
			print("kvce: no *p\n");
209
	}
210
}
211
 
212
/* prepare to go to user space */
213
void
214
kexit(Ureg*)
215
{
216
	Tos *tos;
217
 
218
	/* precise time accounting, kernel exit */
219
	tos = (Tos*)(USTKTOP-sizeof(Tos));
220
	tos->kcycles += fastticks(&tos->cyclefreq) - up->kentry;
221
	tos->pcycles = up->pcycles;
222
	tos->pid = up->pid;
223
}
224
 
225
void
226
trap(Ureg *ur)
227
{
228
	int ecode, clockintr, user, cop, x, fpchk;
229
	ulong fpfcr31;
230
	char buf[2*ERRMAX], buf1[ERRMAX], *fpexcep;
231
	static int dumps;
232
 
233
	ecode = (ur->cause>>2)&EXCMASK;
234
	user = ur->status&KUSER;
235
	if (ur->cause & TS)
236
		panic("trap: tlb shutdown");
237
 
238
	fpchk = 0;
239
	if(user){
240
		up->dbgreg = ur;
241
		cycles(&up->kentry);
242
		/* no fpu, so no fp state to save */
243
	}
244
 
245
	if (up && (char *)(ur) - up->kstack < 1024 && dumps++ == 0) {
246
		iprint("trap: proc %ld kernel stack getting full\n", up->pid);
247
		dumpregs(ur);
248
		dumpstack();
249
	}
250
	if (up == nil &&
251
	    (char *)(ur) - (char *)m->stack < 1024 && dumps++ == 0) {
252
		iprint("trap: cpu%d kernel stack getting full\n", m->machno);
253
		dumpregs(ur);
254
		dumpstack();
255
	}
256
 
257
//	splhi();		/* for the experiment: make it explicit */
258
	/* clear EXL in status */
259
	setstatus(getstatus() & ~EXL);
260
 
261
	clockintr = 0;
262
	switch(ecode){
263
	case CINT:
264
		clockintr = intr(ur);
265
		break;
266
 
267
	case CFPE:
268
		panic("FP exception but no FPU");
269
#ifdef OLD_MIPS_EXAMPLE
270
		fptrap(ur);
271
		clrfpintr();
272
		fpchk = 1;
273
#endif
274
		break;
275
 
276
	case CTLBM:
277
	case CTLBL:
278
	case CTLBS:
279
		/* user tlb entries assumed not overwritten during startup */
280
		if(up == 0)
281
			kernfault(ur, ecode);
282
 
283
		if(!user && (ur->badvaddr & KSEGM) == KSEG3) {
284
			kfault(ur);
285
			break;
286
		}
287
		x = up->insyscall;
288
		up->insyscall = 1;
289
		spllo();
290
		faultmips(ur, user, ecode);
291
		up->insyscall = x;
292
		break;
293
 
294
	case CVCEI:
295
	case CVCED:
296
		kvce(ur, ecode);
297
		goto Default;
298
 
299
	case CWATCH:
300
		if(!user)
301
			panic("watchpoint trap from kernel mode pc=%#p",
302
				ur->pc);
303
		fpwatch(ur);
304
		break;
305
 
306
	case CCPU:
307
		cop = (ur->cause>>28)&3;
308
		if(user && up && cop == 1) {
309
			if(up->fpstate & FPillegal) {
310
				/* someone used floating point in a note handler */
311
				postnote(up, 1,
312
					"sys: floating point in note handler",
313
					NDebug);
314
				break;
315
			}
316
			/* no fpu, so we can only emulate fp ins'ns */
317
			if (fpuemu(ur) < 0)
318
				postnote(up, 1,
319
					"sys: fp instruction not emulated",
320
					NDebug);
321
			else
322
				fpchk = 1;
323
			break;
324
		}
325
		/* Fallthrough */
326
 
327
	Default:
328
	default:
329
		if(user) {
330
			spllo();
331
			snprint(buf, sizeof buf, "sys: %s", excname[ecode]);
332
			postnote(up, 1, buf, NDebug);
333
			break;
334
		}
335
		if (ecode == CADREL || ecode == CADRES)
336
			iprint("kernel addr exception for va %#p pid %#ld %s\n",
337
				ur->badvaddr, (up? up->pid: 0),
338
				(up? up->text: ""));
339
		print("cpu%d: kernel %s pc=%#lux\n",
340
			m->machno, excname[ecode], ur->pc);
341
		dumpregs(ur);
342
		dumpstack();
343
		if(m->machno == 0)
344
			spllo();
345
		exit(1);
346
	}
347
 
348
	if(fpchk) {
349
		fpfcr31 = up->fpsave.fpstatus;
350
		if((fpfcr31>>12) & ((fpfcr31>>7)|0x20) & 0x3f) {
351
			spllo();
352
			fpexcep	= fpexcname(ur, fpfcr31, buf1, sizeof buf1);
353
			snprint(buf, sizeof buf, "sys: fp: %s", fpexcep);
354
			postnote(up, 1, buf, NDebug);
355
		}
356
	}
357
 
358
	splhi();
359
 
360
	/* delaysched set because we held a lock or because our quantum ended */
361
	if(up && up->delaysched && clockintr){
362
		sched();
363
		splhi();
364
	}
365
 
366
	if(user){
367
		notify(ur);
368
		/* no fpu, so no fp state to restore */
369
		kexit(ur);
370
	}
371
 
372
	/* restore EXL in status */
373
	setstatus(getstatus() | EXL);
374
}
375
 
376
/* periodically zero all the interrupt counts */
377
static void
378
resetcounts(void)
379
{
380
	int i;
381
	Handler *hp;
382
 
383
	ilock(&intrlock);
384
	for (i = 0; i < nelem(handlers); i++)
385
		for (hp = &handlers[i]; hp != nil; hp = hp->next)
386
			hp->intrs = 0;
387
	iunlock(&intrlock);
388
}
389
 
390
/*
391
 *  set handlers
392
 */
393
void
394
intrenable(int irq, void (*h)(void *), void *arg)
395
{
396
	Handler *hp;
397
	static int resetclock;
398
 
399
	if (h == nil)
400
		panic("intrenable: nil handler intr %d", irq);
401
	if(irq < ILmin || irq >= nelem(handlers))
402
		panic("intrenable: bad handler intr %d %#p", irq, h);
403
 
404
	hp = &handlers[irq];
405
	ilock(&intrlock);
406
	if (hp->handler != nil) {		/* occupied? */
407
		/* add a new one at the end of the chain */
408
		for (; hp->next != nil; hp = hp->next)
409
			;
410
		hp->next = smalloc(sizeof *hp);
411
		hp = hp->next;
412
		hp->next = nil;
413
	}
414
	hp->handler = h;
415
	hp->arg = arg;
416
	iunlock(&intrlock);
417
 
418
	if (irq == ILduart0) {		/* special apb sub-interrupt */
419
		*Apbintrsts = 0;
420
		*Apbintrmask = 1 << Apbintruart;  /* enable, actually */
421
		coherence();
422
	}
423
	intron(1 << (ILshift + irq));
424
	if (!resetclock) {
425
		resetclock = 1;
426
		addclock0link(resetcounts, 100);
427
	}
428
}
429
 
430
void
431
intrshutdown(void)
432
{
433
	introff(INTMASK);
434
}
435
 
436
static void
437
jabberoff(Ureg *ur, int irq, ulong bit)
438
{
439
	introff(bit);			/* interrupt off now ... */
440
	if (ur)
441
		ur->status &= ~bit;	/* ... and upon return */
442
	offintrs |= bit;
443
	iprint("irq %d jabbering; shutting it down\n", irq);
444
}
445
 
446
ulong
447
pollall(Ureg *ur, ulong cause)			/* must be called splhi */
448
{
449
	int i, intrs, sts;
450
	ulong bit;
451
	Handler *hp;
452
 
453
	/* exclude clock and sw intrs */
454
	intrs = cause & (INTR6|INTR5|INTR4|INTR3|INTR2) & getstatus();
455
	if(intrs == 0)
456
		return cause;
457
 
458
	ilock(&intrlock);
459
	for (i = ILmax; i >= ILmin; i--) {
460
		bit = 1 << (ILshift + i);
461
		if (!(intrs & bit))
462
			continue;
463
		intrcauses[i]++;
464
		for (hp = &handlers[i]; hp != nil; hp = hp->next)
465
			if (hp->handler) {
466
				if (i == ILduart0) {
467
					sts = *Apbintrsts;
468
					if((sts & (1 << Apbintruart)) == 0)
469
						continue;
470
					/* don't need to ack apb sub-intr */
471
					// *Apbintrsts &= ~(1 << Apbintruart);
472
				}
473
				(*hp->handler)(hp->arg);
474
				splhi();
475
				if (++hp->intrs > 25000) {
476
					jabberoff(ur, i, bit);
477
					intrs &= ~bit;
478
					hp->intrs = 0;
479
				}
480
			} else if (ur)
481
				iprint("no handler for interrupt %d\n", i);
482
		cause &= ~bit;
483
	}
484
	iunlock(&intrlock);
485
	return cause;
486
}
487
 
488
int
489
intr(Ureg *ur)
490
{
491
	int clockintr;
492
	ulong cause;
493
 
494
	m->intr++;
495
	clockintr = 0;
496
	/*
497
	 * ignore interrupts that we have disabled, even if their cause bits
498
	 * are set.
499
	 */
500
	cause = ur->cause & ur->status & INTMASK;
501
	cause &= ~(INTR1|INTR0);		/* ignore sw interrupts */
502
	if (cause == 0)
503
		print("spurious interrupt\n");
504
	if(cause & INTR7){
505
		clock(ur);
506
		intrcauses[ILclock]++;
507
		cause &= ~(1 << (ILclock + ILshift));
508
		clockintr = 1;
509
	}
510
	cause = pollall(ur, cause);
511
	if(cause){
512
		print("intr: cause %#lux not handled\n", cause);
513
		exit(1);
514
	}
515
 
516
	/* preemptive scheduling */
517
	if(up && !clockintr)
518
		preempted();
519
	/* if it was a clockintr, sched will be called at end of trap() */
520
	return clockintr;
521
}
522
 
523
char*
524
fpexcname(Ureg *ur, ulong fcr31, char *buf, uint size)
525
{
526
	int i;
527
	char *s;
528
	ulong fppc;
529
 
530
	fppc = ur->pc;
531
	if(ur->cause & BD)	/* branch delay */
532
		fppc += 4;
533
	s = 0;
534
	if(fcr31 & (1<<17))
535
		s = "unimplemented operation";
536
	else{
537
		fcr31 >>= 7;		/* trap enable bits */
538
		fcr31 &= (fcr31>>5);	/* anded with exceptions */
539
		for(i=0; i<5; i++)
540
			if(fcr31 & (1<<i))
541
				s = fpcause[i];
542
	}
543
 
544
	if(s == 0)
545
		return "no floating point exception";
546
 
547
	snprint(buf, size, "%s fppc=%#lux", s, fppc);
548
	return buf;
549
}
550
 
551
#define KERNPC(x) (KTZERO <= (ulong)(x) && (ulong)(x) < (ulong)&etext)
552
 
553
void
554
kernfault(Ureg *ur, int code)
555
{
556
	print("panic: kfault %s badvaddr=%#lux", excname[code], ur->badvaddr);
557
	kpteprint(ur);
558
	print("u=%#p status=%#lux pc=%#lux sp=%#lux\n",
559
		up, ur->status, ur->pc, ur->sp);
560
	delay(500);
561
	panic("kfault");
562
}
563
 
564
static void
565
getpcsp(ulong *pc, ulong *sp)
566
{
567
	*pc = getcallerpc(&pc);
568
	*sp = (ulong)&pc-4;
569
}
570
 
571
void
572
callwithureg(void (*fn)(Ureg*))
573
{
574
	Ureg ureg;
575
 
576
	memset(&ureg, 0, sizeof ureg);
577
	getpcsp((ulong*)&ureg.pc, (ulong*)&ureg.sp);
578
	ureg.r31 = getcallerpc(&fn);
579
	fn(&ureg);
580
}
581
 
582
static void
583
_dumpstack(Ureg *ureg)
584
{
585
	ulong l, v, top, i;
586
	extern ulong etext;
587
 
588
	if(up == 0)
589
		return;
590
 
591
	print("ktrace /kernel/path %.8lux %.8lux %.8lux\n",
592
		ureg->pc, ureg->sp, ureg->r31);
593
	top = (ulong)up->kstack + KSTACK;
594
	i = 0;
595
	for(l=ureg->sp; l < top; l += BY2WD) {
596
		v = *(ulong*)l;
597
		if(KTZERO < v && v < (ulong)&etext) {
598
			print("%.8lux=%.8lux ", l, v);
599
			if((++i%4) == 0){
600
				print("\n");
601
				delay(200);
602
			}
603
		}
604
	}
605
	print("\n");
606
}
607
 
608
void
609
dumpstack(void)
610
{
611
	callwithureg(_dumpstack);
612
}
613
 
614
static ulong
615
R(Ureg *ur, int i)
616
{
617
	uchar *s;
618
 
619
	s = (uchar*)ur;
620
	return *(ulong*)(s + regname[i].off - Uoffset);
621
}
622
 
623
void
624
dumpregs(Ureg *ur)
625
{
626
	int i;
627
 
628
	if(up)
629
		print("registers for %s %lud\n", up->text, up->pid);
630
	else
631
		print("registers for kernel\n");
632
 
633
	for(i = 0; i < nelem(regname); i += 2)
634
		print("%s\t%#.8lux\t%s\t%#.8lux\n",
635
			regname[i].name,   R(ur, i),
636
			regname[i+1].name, R(ur, i+1));
637
}
638
 
639
int
640
notify(Ureg *ur)
641
{
642
	int l, s;
643
	ulong sp;
644
	Note *n;
645
 
646
	if(up->procctl)
647
		procctl(up);
648
	if(up->nnote == 0)
649
		return 0;
650
 
651
	s = spllo();
652
	qlock(&up->debug);
653
	up->fpstate |= FPillegal;
654
	up->notepending = 0;
655
	n = &up->note[0];
656
	if(strncmp(n->msg, "sys:", 4) == 0) {
657
		l = strlen(n->msg);
658
		if(l > ERRMAX-15)	/* " pc=0x12345678\0" */
659
			l = ERRMAX-15;
660
 
661
		seprint(n->msg+l, &n->msg[sizeof n->msg], " pc=%#lux", ur->pc);
662
	}
663
 
664
	if(n->flag != NUser && (up->notified || up->notify==0)) {
665
		if(n->flag == NDebug)
666
			pprint("suicide: %s\n", n->msg);
667
 
668
		qunlock(&up->debug);
669
		pexit(n->msg, n->flag!=NDebug);
670
	}
671
 
672
	if(up->notified) {
673
		qunlock(&up->debug);
674
		splx(s);
675
		return 0;
676
	}
677
 
678
	if(!up->notify) {
679
		qunlock(&up->debug);
680
		pexit(n->msg, n->flag!=NDebug);
681
	}
682
	sp = ur->usp & ~(BY2V-1);
683
	sp -= sizeof(Ureg);
684
 
685
	if(!okaddr((ulong)up->notify, BY2WD, 0) ||
686
	   !okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1)) {
687
		pprint("suicide: bad address or sp in notify\n");
688
		qunlock(&up->debug);
689
		pexit("Suicide", 0);
690
	}
691
 
692
	memmove((Ureg*)sp, ur, sizeof(Ureg));	/* push user regs */
693
	*(Ureg**)(sp-BY2WD) = up->ureg;	/* word under Ureg is old up->ureg */
694
	up->ureg = (void*)sp;
695
 
696
	sp -= BY2WD+ERRMAX;
697
	memmove((char*)sp, up->note[0].msg, ERRMAX);	/* push err string */
698
 
699
	sp -= 3*BY2WD;
700
	*(ulong*)(sp+2*BY2WD) = sp+3*BY2WD;	/* arg 2 is string */
701
	ur->r1 = (long)up->ureg;		/* arg 1 is ureg* */
702
	((ulong*)sp)[1] = (ulong)up->ureg;	/* arg 1 0(FP) is ureg* */
703
	((ulong*)sp)[0] = 0;			/* arg 0 is pc */
704
	ur->usp = sp;
705
	/*
706
	 * arrange to resume at user's handler as if handler(ureg, errstr)
707
	 * were being called.
708
	 */
709
	ur->pc = (ulong)up->notify;
710
 
711
	up->notified = 1;
712
	up->nnote--;
713
	memmove(&up->lastnote, &up->note[0], sizeof(Note));
714
	memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note));
715
 
716
	qunlock(&up->debug);
717
	splx(s);
718
	return 1;
719
}
720
 
721
/*
722
 * Check that status is OK to return from note.
723
 */
724
int
725
validstatus(ulong kstatus, ulong ustatus)
726
{
727
//	if((kstatus & (INTMASK|KX|SX|UX)) != (ustatus & (INTMASK|KX|SX|UX)))
728
	if((kstatus & INTMASK) != (ustatus & INTMASK))
729
		return 0;
730
	if((ustatus&(KSU|ERL|EXL|IE)) != (KUSER|EXL|IE))
731
		return 0;
732
	if(ustatus & (0xFFFF0000&~CU1))	/* no CU3, CU2, CU0, RP, FR, RE, DS */
733
		return 0;
734
	return 1;
735
}
736
 
737
/*
738
 * Return user to state before notify(); called from user's handler.
739
 */
740
void
741
noted(Ureg *kur, Ureg **urp, ulong arg0)
742
{
743
	Ureg *nur;
744
	ulong oureg, sp;
745
 
746
	qlock(&up->debug);
747
	if(arg0!=NRSTR && !up->notified) {
748
		qunlock(&up->debug);
749
		pprint("call to noted() when not notified\n");
750
		pexit("Suicide", 0);
751
	}
752
	up->notified = 0;
753
 
754
	up->fpstate &= ~FPillegal;
755
 
756
	nur = up->ureg;
757
 
758
	oureg = (ulong)nur;
759
	if((oureg & (BY2WD-1))
760
	|| !okaddr((ulong)oureg-BY2WD, BY2WD+sizeof(Ureg), 0)){
761
		pprint("bad up->ureg in noted or call to noted() when not notified\n");
762
		qunlock(&up->debug);
763
		pexit("Suicide", 0);
764
	}
765
 
766
	if(!validstatus(kur->status, nur->status)) {
767
		qunlock(&up->debug);
768
		pprint("bad noted ureg status %#lux\n", nur->status);
769
		pexit("Suicide", 0);
770
	}
771
 
772
	memmove(*urp, up->ureg, sizeof(Ureg));
773
	switch(arg0) {
774
	case NCONT:
775
	case NRSTR:				/* only used by APE */
776
		if(!okaddr(nur->pc, BY2WD, 0) || !okaddr(nur->usp, BY2WD, 0)){
777
			pprint("suicide: trap in noted\n");
778
			qunlock(&up->debug);
779
			pexit("Suicide", 0);
780
		}
781
		up->ureg = (Ureg*)(*(ulong*)(oureg-BY2WD));
782
		qunlock(&up->debug);
783
		splhi();
784
		/*
785
		 * the old challenge and carrera ports called rfnote here,
786
		 * but newer ports do not, and notes seem to work only
787
		 * without this call.
788
		 */
789
		// rfnote(urp);		/* return from note with SP=urp */
790
		break;
791
 
792
	case NSAVE:				/* only used by APE */
793
		if(!okaddr(nur->pc, BY2WD, 0) || !okaddr(nur->usp, BY2WD, 0)){
794
			pprint("suicide: trap in noted\n");
795
			qunlock(&up->debug);
796
			pexit("Suicide", 0);
797
		}
798
		qunlock(&up->debug);
799
		sp = oureg-4*BY2WD-ERRMAX;
800
 
801
		splhi();
802
		(*urp)->sp = sp;
803
		((ulong*)sp)[1] = oureg;	/* arg 1 0(FP) is ureg* */
804
		((ulong*)sp)[0] = 0;		/* arg 0 is pc */
805
		(*urp)->r1 = oureg;		/* arg 1 is ureg* */
806
 
807
		// rfnote(urp);		/* return from note with SP=urp */
808
		break;
809
 
810
	default:
811
		pprint("unknown noted arg %#lux\n", arg0);
812
		up->lastnote.flag = NDebug;
813
		/* fall through */
814
 
815
	case NDFLT:
816
		if(up->lastnote.flag == NDebug)
817
			pprint("suicide: %s\n", up->lastnote.msg);
818
		qunlock(&up->debug);
819
		pexit(up->lastnote.msg, up->lastnote.flag!=NDebug);
820
	}
821
}
822
 
823
#include "../port/systab.h"
824
 
825
static Ref goodsyscall;
826
static Ref totalsyscall;
827
 
828
static void
829
sctracesetup(ulong scallnr, ulong sp, uintptr pc, vlong *startnsp)
830
{
831
	if(up->procctl == Proc_tracesyscall){
832
		/*
833
		 * Redundant validaddr.  Do we care?
834
		 * Tracing syscalls is not exactly a fast path...
835
		 * Beware, validaddr currently does a pexit rather
836
		 * than an error if there's a problem; that might
837
		 * change in the future.
838
		 */
839
		if(sp < (USTKTOP-BY2PG) || sp > (USTKTOP-sizeof(Sargs)-BY2WD))
840
			validaddr(sp, sizeof(Sargs)+BY2WD, 0);
841
 
842
		syscallfmt(scallnr, pc, (va_list)(sp+BY2WD));
843
		up->procctl = Proc_stopme;
844
		procctl(up);
845
		if(up->syscalltrace)
846
			free(up->syscalltrace);
847
		up->syscalltrace = nil;
848
		*startnsp = todget(nil);
849
	}
850
}
851
 
852
static void
853
sctracefinish(ulong scallnr, ulong sp, int ret, vlong startns)
854
{
855
	int s;
856
 
857
	if(up->procctl == Proc_tracesyscall){
858
		up->procctl = Proc_stopme;
859
		sysretfmt(scallnr, (va_list)(sp+BY2WD), ret,
860
			startns, todget(nil));
861
		s = splhi();
862
		procctl(up);
863
		splx(s);
864
		if(up->syscalltrace)
865
			free(up->syscalltrace);
866
		up->syscalltrace = nil;
867
	}
868
}
869
 
870
/*
871
 * called directly from assembler, not via trap()
872
 */
873
long
874
syscall(Ureg *aur)
875
{
876
	int i;
877
	volatile long ret;
878
	ulong sp, scallnr;
879
	vlong startns;
880
	char *e;
881
	Ureg *ur;
882
 
883
	cycles(&up->kentry);
884
 
885
	incref(&totalsyscall);
886
	m->syscall++;
887
	up->insyscall = 1;
888
	ur = aur;
889
	up->pc = ur->pc;
890
	up->dbgreg = aur;
891
	ur->cause = 16<<2;	/* for debugging: system call is undef 16 */
892
 
893
	scallnr = ur->r1;
894
	up->scallnr = ur->r1;
895
	sp = ur->sp;
896
	sctracesetup(scallnr, sp, ur->pc, &startns);
897
 
898
	/* clear EXL in status */
899
	setstatus(getstatus() & ~EXL);
900
 
901
	/* no fpu, so no fp state to save */
902
	spllo();
903
 
904
	up->nerrlab = 0;
905
	ret = -1;
906
	if(!waserror()) {
907
		if(scallnr >= nsyscall || systab[scallnr] == 0){
908
			pprint("bad sys call number %ld pc %#lux\n",
909
				scallnr, ur->pc);
910
			postnote(up, 1, "sys: bad sys call", NDebug);
911
			error(Ebadarg);
912
		}
913
 
914
		if(sp & (BY2WD-1)){
915
			pprint("odd sp in sys call pc %#lux sp %#lux\n",
916
				ur->pc, ur->sp);
917
			postnote(up, 1, "sys: odd stack", NDebug);
918
			error(Ebadarg);
919
		}
920
 
921
		if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-sizeof(Sargs)-BY2WD))
922
			validaddr(sp, sizeof(Sargs)+BY2WD, 0);
923
 
924
		up->s = *((Sargs*)(sp+BY2WD));
925
		up->psstate = sysctab[scallnr];
926
 
927
		ret = systab[scallnr](up->s.args);
928
		poperror();
929
	}else{
930
		/* failure: save the error buffer for errstr */
931
		e = up->syserrstr;
932
		up->syserrstr = up->errstr;
933
		up->errstr = e;
934
		if(0 && up->pid == 1)
935
			print("[%lud %s] syscall %lud: %s\n",
936
				up->pid, up->text, scallnr, up->errstr);
937
	}
938
	if(up->nerrlab){
939
		print("bad errstack [%lud]: %d extra\n", scallnr, up->nerrlab);
940
		for(i = 0; i < NERR; i++)
941
			print("sp=%#lux pc=%#lux\n",
942
				up->errlab[i].sp, up->errlab[i].pc);
943
		panic("error stack");
944
	}
945
	sctracefinish(scallnr, sp, ret, startns);
946
 
947
	ur->pc += 4;
948
	ur->r1 = ret;
949
 
950
	up->psstate = 0;
951
	up->insyscall = 0;
952
 
953
	if(scallnr == NOTED) {				/* ugly hack */
954
		noted(ur, &aur, *(ulong*)(sp+BY2WD));	/* may return */
955
		ret = ur->r1;
956
	}
957
	incref(&goodsyscall);
958
	splhi();
959
	if(scallnr!=RFORK && (up->procctl || up->nnote)){
960
		ur->r1 = ret;			/* load up for noted() above */
961
		notify(ur);
962
	}
963
	/* if we delayed sched because we held a lock, sched now */
964
	if(up->delaysched)
965
		sched();
966
	kexit(ur);
967
 
968
	/* restore EXL in status */
969
	setstatus(getstatus() | EXL);
970
 
971
	return ret;
972
}
973
 
974
void
975
forkchild(Proc *p, Ureg *ur)
976
{
977
	Ureg *cur;
978
 
979
	p->sched.sp = (ulong)p->kstack+KSTACK-UREGSIZE;
980
	p->sched.pc = (ulong)forkret;
981
 
982
	cur = (Ureg*)(p->sched.sp+2*BY2WD);
983
	memmove(cur, ur, sizeof(Ureg));
984
 
985
	cur->pc += 4;
986
 
987
	/* Things from bottom of syscall we never got to execute */
988
	p->psstate = 0;
989
	p->insyscall = 0;
990
}
991
 
992
static
993
void
994
linkproc(void)
995
{
996
	spllo();
997
	up->kpfun(up->kparg);
998
	pexit("kproc exiting", 0);
999
}
1000
 
1001
void
1002
kprocchild(Proc *p, void (*func)(void*), void *arg)
1003
{
1004
	p->sched.pc = (ulong)linkproc;
1005
	p->sched.sp = (ulong)p->kstack+KSTACK;
1006
 
1007
	p->kpfun = func;
1008
	p->kparg = arg;
1009
}
1010
 
1011
/* set up user registers before return from exec() */
1012
long
1013
execregs(ulong entry, ulong ssize, ulong nargs)
1014
{
1015
	Ureg *ur;
1016
	ulong *sp;
1017
 
1018
	sp = (ulong*)(USTKTOP - ssize);
1019
	*--sp = nargs;
1020
 
1021
	ur = (Ureg*)up->dbgreg;
1022
	ur->usp = (ulong)sp;
1023
	ur->pc = entry - 4;		/* syscall advances it */
1024
	up->fpsave.fpstatus = initfp.fpstatus;
1025
	return USTKTOP-sizeof(Tos);	/* address of kernel/user shared data */
1026
}
1027
 
1028
ulong
1029
userpc(void)
1030
{
1031
	Ureg *ur;
1032
 
1033
	ur = (Ureg*)up->dbgreg;
1034
	return ur->pc;
1035
}
1036
 
1037
/*
1038
 * This routine must save the values of registers the user is not
1039
 * permitted to write from devproc and then restore the saved values
1040
 * before returning
1041
 */
1042
void
1043
setregisters(Ureg *xp, char *pureg, char *uva, int n)
1044
{
1045
	ulong status;
1046
 
1047
	status = xp->status;
1048
	memmove(pureg, uva, n);
1049
	xp->status = status;
1050
}
1051
 
1052
/*
1053
 * Give enough context in the ureg to produce a kernel stack for
1054
 * a sleeping process
1055
 */
1056
void
1057
setkernur(Ureg *xp, Proc *p)
1058
{
1059
	xp->pc = p->sched.pc;
1060
	xp->sp = p->sched.sp;
1061
	xp->r24 = (ulong)p;		/* up */
1062
	xp->r31 = (ulong)sched;
1063
}
1064
 
1065
ulong
1066
dbgpc(Proc *p)
1067
{
1068
	Ureg *ur;
1069
 
1070
	ur = p->dbgreg;
1071
	if(ur == 0)
1072
		return 0;
1073
 
1074
	return ur->pc;
1075
}