Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 1
#include	"u.h"
2
#include	"../port/lib.h"
3
#include	"mem.h"
4
#include	"dat.h"
5
#include	"fns.h"
6
#include	"ureg.h"
7
#include	"io.h"
8
#include	"tos.h"
9
#include	"../port/error.h"
10
 
11
static Lock vctllock;
12
static Vctl *vctl[256];
13
 
14
void
15
hwintrinit(void)
16
{
17
	i8259init();
18
	mpicenable(0, nil);	/* 8259 interrupts are routed through MPIC intr 0 */
19
}
20
 
21
static int
22
hwintrenable(Vctl *v)
23
{
24
	int vec, irq;
25
 
26
	irq = v->irq;
27
	if(BUSTYPE(v->tbdf) == BusPCI) {	/* MPIC? */
28
		if(irq > 15) {
29
			print("intrenable: pci irq %d out of range\n", v->irq);
30
			return -1;
31
		}
32
		vec = irq;
33
		mpicenable(vec, v);
34
	}
35
	else {
36
		if(irq > MaxIrqPIC) {
37
			print("intrenable: irq %d out of range\n", v->irq);
38
			return -1;
39
		}
40
		vec = irq+VectorPIC;
41
		if(i8259enable(v) == -1)
42
			return -1;
43
	}
44
	return vec;
45
}
46
 
47
static int
48
hwintrdisable(Vctl *v)
49
{
50
	int vec, irq;
51
 
52
	irq = v->irq;
53
	if(BUSTYPE(v->tbdf) == BusPCI) {	/* MPIC? */
54
		if(irq > 15) {
55
			print("intrdisable: pci irq %d out of range\n", v->irq);
56
			return -1;
57
		}
58
		vec = irq;
59
		mpicdisable(vec);
60
	}
61
	else {
62
		if(irq > MaxIrqPIC) {
63
			print("intrdisable: irq %d out of range\n", v->irq);
64
			return -1;
65
		}
66
		vec = irq+VectorPIC;
67
		if(i8259disable(irq) == -1)
68
			return -1;
69
	}
70
	return vec;
71
}
72
 
73
static int
74
hwvecno(int irq, int tbdf)
75
{
76
	if(BUSTYPE(tbdf) == BusPCI) 	/* MPIC? */
77
		return irq;
78
	else
79
		return irq+VectorPIC;
80
}
81
 
82
void
83
intrenable(int irq, void (*f)(Ureg*, void*), void* a, int tbdf, char *name)
84
{
85
	int vno;
86
	Vctl *v;
87
 
88
	if(f == nil){
89
		print("intrenable: nil handler for %d, tbdf 0x%uX for %s\n",
90
			irq, tbdf, name);
91
		return;
92
	}
93
 
94
	v = xalloc(sizeof(Vctl));
95
	v->isintr = 1;
96
	v->irq = irq;
97
	v->tbdf = tbdf;
98
	v->f = f;
99
	v->a = a;
100
	strncpy(v->name, name, KNAMELEN-1);
101
	v->name[KNAMELEN-1] = 0;
102
 
103
	ilock(&vctllock);
104
	vno = hwintrenable(v);
105
	if(vno == -1){
106
		iunlock(&vctllock);
107
		print("intrenable: couldn't enable irq %d, tbdf 0x%uX for %s\n",
108
			irq, tbdf, v->name);
109
		xfree(v);
110
		return;
111
	}
112
	if(vctl[vno]){
113
		if(vctl[vno]->isr != v->isr || vctl[vno]->eoi != v->eoi)
114
			panic("intrenable: handler: %s %s %#p %#p %#p %#p",
115
				vctl[vno]->name, v->name,
116
				vctl[vno]->isr, v->isr, vctl[vno]->eoi, v->eoi);
117
		v->next = vctl[vno];
118
	}
119
	vctl[vno] = v;
120
	iunlock(&vctllock);
121
}
122
 
123
void
124
intrdisable(int irq, void (*f)(Ureg *, void *), void *a, int tbdf, char *name)
125
{
126
	Vctl **pv, *v;
127
	int vno;
128
 
129
	vno = hwvecno(irq, tbdf);
130
	ilock(&vctllock);
131
	pv = &vctl[vno];
132
	while (*pv && 
133
		  ((*pv)->irq != irq || (*pv)->tbdf != tbdf || (*pv)->f != f || (*pv)->a != a ||
134
		   strcmp((*pv)->name, name)))
135
		pv = &((*pv)->next);
136
	assert(*pv);
137
 
138
	v = *pv;
139
	*pv = (*pv)->next;	/* Link out the entry */
140
 
141
	if(vctl[vno] == nil)
142
		hwintrdisable(v);
143
	iunlock(&vctllock);
144
	xfree(v);
145
}
146
 
147
void	syscall(Ureg*);
148
void	noted(Ureg*, ulong);
149
static void _dumpstack(Ureg*);
150
 
151
char *excname[] =
152
{
153
	"reserved 0",
154
	"system reset",
155
	"machine check",
156
	"data access",
157
	"instruction access",
158
	"external interrupt",
159
	"alignment",
160
	"program exception",
161
	"floating-point unavailable",
162
	"decrementer",
163
	"reserved A",
164
	"reserved B",
165
	"system call",
166
	"trace trap",
167
	"floating point assist",
168
	"reserved F",
169
	"reserved 10",
170
	"reserved 11",
171
	"reserved 12",
172
	"instruction address breakpoint",
173
	"system management interrupt",
174
};
175
 
176
char *fpcause[] =
177
{
178
	"inexact operation",
179
	"division by zero",
180
	"underflow",
181
	"overflow",
182
	"invalid operation",
183
};
184
char	*fpexcname(Ureg*, ulong, char*);
185
#define FPEXPMASK	0xfff80300		/* Floating exception bits in fpscr */
186
 
187
 
188
char *regname[]={
189
	"CAUSE",	"SRR1",
190
	"PC",		"GOK",
191
	"LR",		"CR",
192
	"XER",	"CTR",
193
	"R0",		"R1",
194
	"R2",		"R3",
195
	"R4",		"R5",
196
	"R6",		"R7",
197
	"R8",		"R9",
198
	"R10",	"R11",
199
	"R12",	"R13",
200
	"R14",	"R15",
201
	"R16",	"R17",
202
	"R18",	"R19",
203
	"R20",	"R21",
204
	"R22",	"R23",
205
	"R24",	"R25",
206
	"R26",	"R27",
207
	"R28",	"R29",
208
	"R30",	"R31",
209
};
210
 
211
void
212
trap(Ureg *ureg)
213
{
214
	ulong dsisr;
215
	int ecode, user;
216
	char buf[ERRMAX], *s;
217
 
218
	ecode = (ureg->cause >> 8) & 0xff;
219
	user = (ureg->srr1 & MSR_PR) != 0;
220
	if(user)
221
		up->dbgreg = ureg;
222
 
223
	if(ureg->status & MSR_RI == 0)
224
		print("double fault?: ecode = %d\n", ecode);
225
 
226
	switch(ecode) {
227
	case CEI:
228
		intr(ureg);
229
		break;
230
	case CDEC:
231
		clockintr(ureg);
232
		break;
233
	case CSYSCALL:
234
		if(!user)
235
			panic("syscall in kernel: srr1 0x%4.4luX", ureg->srr1);
236
		syscall(ureg);
237
		return;		/* syscall() calls notify itself, don't do it again */
238
	case CFPU:
239
		if(!user || up == nil) {
240
			dumpregs(ureg);
241
			panic("floating point in kernel");
242
		}
243
		switch(up->fpstate){
244
		case FPinit:
245
			fprestore(&initfp);
246
			up->fpstate = FPactive;
247
			break;
248
		case FPinactive:
249
			fprestore(&up->fpsave);
250
			up->fpstate = FPactive;
251
			break;
252
		default:
253
			panic("fpstate");
254
		}
255
		ureg->srr1 |= MSR_FP;
256
		break;
257
	case CISI:
258
		faultpower(ureg, ureg->pc, 1);
259
		break;
260
	case CDSI:
261
		dsisr = getdsisr();
262
		if(dsisr & BIT(6))
263
			faultpower(ureg, getdar(), 0);
264
		else
265
			faultpower(ureg, getdar(), 1);
266
		break;
267
	case CPROG:
268
		if(ureg->status & (1<<19))
269
			s = "floating point exception";
270
		else if(ureg->status & (1<<18))
271
			s = "illegal instruction";
272
		else if(ureg->status & (1<<17))
273
			s = "privileged instruction";
274
		else
275
			s = "undefined program exception";
276
		if(user){
277
			spllo();
278
			sprint(buf, "sys: trap: %s", s);
279
			postnote(up, 1, buf, NDebug);
280
			break;
281
		}
282
		dumpregs(ureg);
283
		panic(s);
284
		break;
285
	default:
286
		if(ecode < nelem(excname) && user){
287
			spllo();
288
			sprint(buf, "sys: trap: %s", excname[ecode]);
289
			postnote(up, 1, buf, NDebug);
290
			break;
291
		}
292
		dumpregs(ureg);
293
		if(ecode < nelem(excname))
294
			panic("%s", excname[ecode]);
295
		panic("unknown trap/intr: %d", ecode);
296
	}
297
 
298
	/* restoreureg must execute at high IPL */
299
	splhi();
300
 
301
	/* delaysched set because we held a lock or because our quantum ended */
302
	if(up && up->delaysched && ecode == CDEC){
303
		sched();
304
		splhi();
305
	}
306
 
307
	if(user) {
308
		notify(ureg);
309
		if(up->fpstate == FPinactive)
310
			ureg->srr1 &= ~MSR_FP;
311
		kexit(ureg);
312
	}
313
}
314
 
315
void
316
faultpower(Ureg *ureg, ulong addr, int read)
317
{
318
	int user, insyscall, n;
319
	char buf[ERRMAX];
320
 
321
	user = (ureg->srr1 & MSR_PR) != 0;
322
	insyscall = up->insyscall;
323
	up->insyscall = 1;
324
	n = fault(addr, read);
325
	if(n < 0){
326
		if(!user){
327
			dumpregs(ureg);
328
			panic("fault: 0x%lux", addr);
329
		}
330
		sprint(buf, "sys: trap: fault %s addr=0x%lux", read? "read" : "write", addr);
331
		postnote(up, 1, buf, NDebug);
332
	}
333
	up->insyscall = insyscall;
334
}
335
 
336
void
337
sethvec(int v, void (*r)(void))
338
{
339
	ulong *vp, pa, o;
340
 
341
	vp = KADDR(v);
342
	vp[0] = 0x7c1043a6;	/* MOVW R0, SPR(SPRG0) */
343
	vp[1] = 0x7c0802a6;	/* MOVW LR, R0 */
344
	vp[2] = 0x7c1243a6;	/* MOVW R0, SPR(SPRG2) */
345
	pa = PADDR(r);
346
	o = pa >> 25;
347
	if(o != 0 && o != 0x7F){
348
		/* a branch too far */
349
		vp[3] = (15<<26)|(pa>>16);	/* MOVW $r&~0xFFFF, R0 */
350
		vp[4] = (24<<26)|(pa&0xFFFF);	/* OR $r&0xFFFF, R0 */
351
		vp[5] = 0x7c0803a6;	/* MOVW	R0, LR */
352
		vp[6] = 0x4e800021;	/* BL (LR) */
353
	}else
354
		vp[3] = (18<<26)|(pa&0x3FFFFFC)|3;	/* bla */
355
	dcflush(vp, 8*sizeof(ulong));
356
}
357
 
358
void
359
trapinit(void)
360
{
361
	int i;
362
 
363
	/*
364
	 * set all exceptions to trap
365
	 */
366
	for(i = 0; i < 0x2000; i += 0x100)
367
		sethvec(i, trapvec);
368
 
369
	putmsr(getmsr() & ~MSR_IP);
370
}
371
 
372
void
373
intr(Ureg *ureg)
374
{
375
	int vno;
376
	Vctl *ctl, *v;
377
 
378
	vno = mpicintack();
379
	if(vno == 0) {			/* 8259, wired through MPIC vec 0 */
380
		vno = i8259intack();
381
		mpiceoi(0);
382
	}
383
 
384
	if(vno > nelem(vctl) || (ctl = vctl[vno]) == 0) {
385
		panic("spurious intr %d", vno);
386
		return;
387
	}
388
 
389
	if(ctl->isr)
390
		ctl->isr(vno);
391
	for(v = ctl; v != nil; v = v->next){
392
		if(v->f)
393
			v->f(ureg, v->a);
394
	}
395
	if(ctl->eoi)
396
		ctl->eoi(vno);
397
 
398
	if(up)
399
		preempted();
400
}
401
 
402
char*
403
fpexcname(Ureg *ur, ulong fpscr, char *buf)
404
{
405
	int i;
406
	char *s;
407
	ulong fppc;
408
 
409
	fppc = ur->pc;
410
	s = 0;
411
	fpscr >>= 3;		/* trap enable bits */
412
	fpscr &= (fpscr>>22);	/* anded with exceptions */
413
	for(i=0; i<5; i++)
414
		if(fpscr & (1<<i))
415
			s = fpcause[i];
416
	if(s == 0)
417
		return "no floating point exception";
418
	sprint(buf, "%s fppc=0x%lux", s, fppc);
419
	return buf;
420
}
421
 
422
/*
423
 * Fill in enough of Ureg to get a stack trace, and call a function.
424
 * Used by debugging interface rdb.
425
 */
426
 
427
static void
428
getpcsp(ulong *pc, ulong *sp)
429
{
430
	*pc = getcallerpc(&pc);
431
	*sp = (ulong)&pc-4;
432
}
433
 
434
void
435
callwithureg(void (*fn)(Ureg*))
436
{
437
	Ureg ureg;
438
 
439
	getpcsp((ulong*)&ureg.pc, (ulong*)&ureg.sp);
440
	ureg.lr = getcallerpc(&fn);
441
	fn(&ureg);
442
}
443
 
444
static void
445
_dumpstack(Ureg *ureg)
446
{
447
	ulong l, sl, el, v;
448
	int i;
449
 
450
	l = (ulong)&l;
451
	if(up == 0){
452
		el = (ulong)m+BY2PG;
453
		sl = el-KSTACK;
454
	}
455
	else{
456
		sl = (ulong)up->kstack;
457
		el = sl + KSTACK;
458
	}
459
	if(l > el || l < sl){
460
		el = (ulong)m+BY2PG;
461
		sl = el-KSTACK;
462
	}
463
	if(l > el || l < sl)
464
		return;
465
	print("ktrace /kernel/path %.8lux %.8lux %.8lux\n", ureg->pc, ureg->sp, ureg->lr);
466
	i = 0;
467
	for(; l < el; l += 4){
468
		v = *(ulong*)l;
469
		if(KTZERO < v && v < (ulong)etext){
470
			print("%.8lux=%.8lux ", l, v);
471
			if(i++ == 4){
472
				print("\n");
473
				i = 0;
474
			}
475
		}
476
	}
477
}
478
 
479
void
480
dumpstack(void)
481
{
482
	callwithureg(_dumpstack);
483
}
484
 
485
void
486
dumpregs(Ureg *ur)
487
{
488
	int i;
489
	ulong *l;
490
 
491
	if(up) {
492
		print("registers for %s %ld\n", up->text, up->pid);
493
		if(ur->srr1 & MSR_PR == 0)
494
		if(ur->usp < (ulong)up->kstack || ur->usp > (ulong)up->kstack+KSTACK)
495
			print("invalid stack ptr\n");
496
	}
497
	else
498
		print("registers for kernel\n");
499
 
500
	print("dsisr\t%.8lux\tdar\t%.8lux\n", getdsisr(), getdar());
501
	l = &ur->cause;
502
	for(i=0; i<sizeof regname/sizeof(char*); i+=2, l+=2)
503
		print("%s\t%.8lux\t%s\t%.8lux\n", regname[i], l[0], regname[i+1], l[1]);
504
}
505
 
506
static void
507
linkproc(void)
508
{
509
	spllo();
510
	(*up->kpfun)(up->kparg);
511
	pexit("", 0);
512
}
513
 
514
void
515
kprocchild(Proc *p, void (*func)(void*), void *arg)
516
{
517
	p->sched.pc = (ulong)linkproc;
518
	p->sched.sp = (ulong)p->kstack+KSTACK;
519
 
520
	p->kpfun = func;
521
	p->kparg = arg;
522
}
523
 
524
/*
525
 * called in syscallfmt.c, sysfile.c, sysproc.c
526
 */
527
void
528
validalign(uintptr addr, unsigned align)
529
{
530
	/*
531
	 * Plan 9 is a 32-bit O/S, and the hardware it runs on
532
	 * does not usually have instructions which move 64-bit
533
	 * quantities directly, synthesizing the operations
534
	 * with 32-bit move instructions. Therefore, the compiler
535
	 * (and hardware) usually only enforce 32-bit alignment,
536
	 * if at all.
537
	 *
538
	 * Take this out if the architecture warrants it.
539
	 */
540
	if(align == sizeof(vlong))
541
		align = sizeof(long);
542
 
543
	/*
544
	 * Check align is a power of 2, then addr alignment.
545
	 */
546
	if((align != 0 && !(align & (align-1))) && !(addr & (align-1)))
547
		return;
548
	postnote(up, 1, "sys: odd address", NDebug);
549
	error(Ebadarg);
550
	/*NOTREACHED*/
551
}
552
 
553
long
554
execregs(ulong entry, ulong ssize, ulong nargs)
555
{
556
	ulong *sp;
557
	Ureg *ureg;
558
 
559
	sp = (ulong*)(USTKTOP - ssize);
560
	*--sp = nargs;
561
 
562
	ureg = up->dbgreg;
563
	ureg->usp = (ulong)sp;
564
	ureg->pc = entry;
565
	ureg->srr1 &= ~MSR_FP;
566
	return USTKTOP-sizeof(Tos);		/* address of kernel/user shared data */
567
}
568
 
569
void
570
forkchild(Proc *p, Ureg *ur)
571
{
572
	Ureg *cur;
573
 
574
	p->sched.sp = (ulong)p->kstack+KSTACK-UREGSIZE;
575
	p->sched.pc = (ulong)forkret;
576
 
577
	cur = (Ureg*)(p->sched.sp+2*BY2WD);
578
	memmove(cur, ur, sizeof(Ureg));
579
	cur->r3 = 0;
580
 
581
	/* Things from bottom of syscall we never got to execute */
582
	p->psstate = 0;
583
	p->insyscall = 0;
584
}
585
 
586
ulong
587
userpc(void)
588
{
589
	Ureg *ureg;
590
 
591
	ureg = (Ureg*)up->dbgreg;
592
	return ureg->pc;
593
}
594
 
595
 
596
/* This routine must save the values of registers the user is not 
597
 * permitted to write from devproc and then restore the saved values 
598
 * before returning
599
 */
600
void
601
setregisters(Ureg *xp, char *pureg, char *uva, int n)
602
{
603
	ulong status;
604
 
605
	status = xp->status;
606
	memmove(pureg, uva, n);
607
	xp->status = status;
608
}
609
 
610
/* Give enough context in the ureg to produce a kernel stack for
611
 * a sleeping process
612
 */
613
void
614
setkernur(Ureg* ureg, Proc* p)
615
{
616
	ureg->pc = p->sched.pc;
617
	ureg->sp = p->sched.sp+4;
618
}
619
 
620
ulong
621
dbgpc(Proc *p)
622
{
623
	Ureg *ureg;
624
 
625
	ureg = p->dbgreg;
626
	if(ureg == 0)
627
		return 0;
628
 
629
	return ureg->pc;
630
}
631
 
632
/*
633
 *  system calls
634
 */
635
#include "../port/systab.h"
636
 
637
/* TODO: make this trap a separate asm entry point, like on other RISC architectures */
638
void
639
syscall(Ureg* ureg)
640
{
641
	int i;
642
	char *e;
643
	long	ret;
644
	ulong sp, scallnr;
645
 
646
	m->syscall++;
647
	up->insyscall = 1;
648
	up->pc = ureg->pc;
649
	up->dbgreg = ureg;
650
 
651
	scallnr = ureg->r3;
652
	up->scallnr = ureg->r3;
653
	spllo();
654
 
655
	sp = ureg->usp;
656
	up->nerrlab = 0;
657
	ret = -1;
658
	if(!waserror()){
659
		if(scallnr >= nsyscall || systab[scallnr] == nil){
660
			pprint("bad sys call number %lud pc %lux\n",
661
				scallnr, ureg->pc);
662
			postnote(up, 1, "sys: bad sys call", NDebug);
663
			error(Ebadarg);
664
		}
665
 
666
		if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-sizeof(Sargs)-BY2WD))
667
			validaddr(sp, sizeof(Sargs)+BY2WD, 0);
668
 
669
		up->s = *((Sargs*)(sp+BY2WD));
670
		up->psstate = sysctab[scallnr];
671
 
672
		ret = systab[scallnr](up->s.args);
673
		poperror();
674
	}else{
675
		/* failure: save the error buffer for errstr */
676
		e = up->syserrstr;
677
		up->syserrstr = up->errstr;
678
		up->errstr = e;
679
	}
680
	if(up->nerrlab){
681
		print("bad errstack [%uld]: %d extra\n", scallnr, up->nerrlab);
682
		print("scall %s lr =%lux\n", sysctab[scallnr], ureg->lr);
683
		for(i = 0; i < NERR; i++)
684
			print("sp=%lux pc=%lux\n", up->errlab[i].sp, up->errlab[i].pc);
685
		panic("error stack");
686
	}
687
 
688
	up->insyscall = 0;
689
	up->psstate = 0;
690
 
691
	/*
692
	 *  Put return value in frame.  On the x86 the syscall is
693
	 *  just another trap and the return value from syscall is
694
	 *  ignored.  On other machines the return value is put into
695
	 *  the results register by caller of syscall.
696
	 */
697
	ureg->r3 = ret;
698
 
699
	if(scallnr == NOTED)
700
		noted(ureg, *(ulong*)(sp+BY2WD));
701
 
702
	/* restoreureg must execute at high IPL */
703
	splhi();
704
	if(scallnr!=RFORK)
705
		notify(ureg);
706
	if(up->fpstate == FPinactive)
707
		ureg->srr1 &= ~MSR_FP;
708
}
709
 
710
/*
711
 *  Call user, if necessary, with note.
712
 *  Pass user the Ureg struct and the note on his stack.
713
 */
714
int
715
notify(Ureg* ur)
716
{
717
	int l;
718
	ulong s, sp;
719
	Note *n;
720
 
721
	if(up->procctl)
722
		procctl(up);
723
	if(up->nnote == 0)
724
		return 0;
725
 
726
	s = spllo();
727
	qlock(&up->debug);
728
	up->notepending = 0;
729
	n = &up->note[0];
730
	if(strncmp(n->msg, "sys:", 4) == 0){
731
		l = strlen(n->msg);
732
		if(l > ERRMAX-15)	/* " pc=0x12345678\0" */
733
			l = ERRMAX-15;
734
		sprint(n->msg+l, " pc=0x%.8lux", ur->pc);
735
	}
736
 
737
	if(n->flag!=NUser && (up->notified || up->notify==0)){
738
		if(n->flag == NDebug)
739
			pprint("suicide: %s\n", n->msg);
740
		qunlock(&up->debug);
741
		pexit(n->msg, n->flag!=NDebug);
742
	}
743
 
744
	if(up->notified) {
745
		qunlock(&up->debug);
746
		splhi();
747
		return 0;
748
	}
749
 
750
	if(!up->notify) {
751
		qunlock(&up->debug);
752
		pexit(n->msg, n->flag!=NDebug);
753
	}
754
	sp = ur->usp & ~(BY2V-1);
755
	sp -= sizeof(Ureg);
756
 
757
	if(!okaddr((ulong)up->notify, BY2WD, 0) ||
758
	   !okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1)) {
759
		pprint("suicide: bad address or sp in notify\n");
760
		qunlock(&up->debug);
761
		pexit("Suicide", 0);
762
	}
763
 
764
	memmove((Ureg*)sp, ur, sizeof(Ureg));
765
	*(Ureg**)(sp-BY2WD) = up->ureg;	/* word under Ureg is old up->ureg */
766
	up->ureg = (void*)sp;
767
	sp -= BY2WD+ERRMAX;
768
	memmove((char*)sp, up->note[0].msg, ERRMAX);
769
	sp -= 3*BY2WD;
770
	*(ulong*)(sp+2*BY2WD) = sp+3*BY2WD;	/* arg 2 is string */
771
	ur->r1 = (long)up->ureg;		/* arg 1 is ureg* */
772
	((ulong*)sp)[1] = (ulong)up->ureg;	/* arg 1 0(FP) is ureg* */
773
	((ulong*)sp)[0] = 0;			/* arg 0 is pc */
774
	ur->usp = sp;
775
	ur->pc = (ulong)up->notify;
776
	up->notified = 1;
777
	up->nnote--;
778
	memmove(&up->lastnote, &up->note[0], sizeof(Note));
779
	memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note));
780
 
781
	qunlock(&up->debug);
782
	splx(s);
783
	return 1;
784
}
785
 
786
 
787
/*
788
 *   Return user to state before notify()
789
 */
790
void
791
noted(Ureg* ureg, ulong arg0)
792
{
793
	Ureg *nureg;
794
	ulong oureg, sp;
795
 
796
	qlock(&up->debug);
797
	if(arg0!=NRSTR && !up->notified) {
798
		qunlock(&up->debug);
799
		pprint("call to noted() when not notified\n");
800
		pexit("Suicide", 0);
801
	}
802
	up->notified = 0;
803
 
804
	nureg = up->ureg;	/* pointer to user returned Ureg struct */
805
 
806
	/* sanity clause */
807
	oureg = (ulong)nureg;
808
	if(!okaddr((ulong)oureg-BY2WD, BY2WD+sizeof(Ureg), 0)){
809
		pprint("bad ureg in noted or call to noted when not notified\n");
810
		qunlock(&up->debug);
811
		pexit("Suicide", 0);
812
	}
813
 
814
	memmove(ureg, nureg, sizeof(Ureg));
815
 
816
	switch(arg0){
817
	case NCONT:
818
	case NRSTR:
819
		if(!okaddr(nureg->pc, 1, 0) || !okaddr(nureg->usp, BY2WD, 0)){
820
			pprint("suicide: trap in noted\n");
821
			qunlock(&up->debug);
822
			pexit("Suicide", 0);
823
		}
824
		up->ureg = (Ureg*)(*(ulong*)(oureg-BY2WD));
825
		qunlock(&up->debug);
826
		break;
827
 
828
	case NSAVE:
829
		if(!okaddr(nureg->pc, BY2WD, 0)
830
		|| !okaddr(nureg->usp, BY2WD, 0)){
831
			pprint("suicide: trap in noted\n");
832
			qunlock(&up->debug);
833
			pexit("Suicide", 0);
834
		}
835
		qunlock(&up->debug);
836
		sp = oureg-4*BY2WD-ERRMAX;
837
		splhi();
838
		ureg->sp = sp;
839
		((ulong*)sp)[1] = oureg;	/* arg 1 0(FP) is ureg* */
840
		((ulong*)sp)[0] = 0;		/* arg 0 is pc */
841
		break;
842
 
843
	default:
844
		pprint("unknown noted arg 0x%lux\n", arg0);
845
		up->lastnote.flag = NDebug;
846
		/* fall through */
847
 
848
	case NDFLT:
849
		if(up->lastnote.flag == NDebug)
850
			pprint("suicide: %s\n", up->lastnote.msg);
851
		qunlock(&up->debug);
852
		pexit(up->lastnote.msg, up->lastnote.flag!=NDebug);
853
	}
854
}