xref: /plan9/sys/src/9/pc/trap.c (revision ff579efb6d9c16f03df7f0fbdbd7810dcb61813e)
1 #include	"u.h"
2 #include	"tos.h"
3 #include	"../port/lib.h"
4 #include	"mem.h"
5 #include	"dat.h"
6 #include	"fns.h"
7 #include	"io.h"
8 #include	"ureg.h"
9 #include	"../port/error.h"
10 #include	<trace.h>
11 
12 static int trapinited;
13 
14 void	noted(Ureg*, ulong);
15 
16 static void debugbpt(Ureg*, void*);
17 static void fault386(Ureg*, void*);
18 static void doublefault(Ureg*, void*);
19 static void unexpected(Ureg*, void*);
20 static void _dumpstack(Ureg*);
21 
22 static Lock vctllock;
23 static Vctl *vctl[256];
24 
25 enum
26 {
27 	Ntimevec = 20		/* number of time buckets for each intr */
28 };
29 ulong intrtimes[256][Ntimevec];
30 
31 void
32 intrenable(int irq, void (*f)(Ureg*, void*), void* a, int tbdf, char *name)
33 {
34 	int vno;
35 	Vctl *v;
36 
37 	if(f == nil){
38 		print("intrenable: nil handler for %d, tbdf 0x%uX for %s\n",
39 			irq, tbdf, name);
40 		return;
41 	}
42 
43 	v = xalloc(sizeof(Vctl));
44 	v->isintr = 1;
45 	v->irq = irq;
46 	v->tbdf = tbdf;
47 	v->f = f;
48 	v->a = a;
49 	strncpy(v->name, name, KNAMELEN-1);
50 	v->name[KNAMELEN-1] = 0;
51 
52 	ilock(&vctllock);
53 	vno = arch->intrenable(v);
54 	if(vno == -1){
55 		iunlock(&vctllock);
56 		print("intrenable: couldn't enable irq %d, tbdf 0x%uX for %s\n",
57 			irq, tbdf, v->name);
58 		xfree(v);
59 		return;
60 	}
61 	if(vctl[vno]){
62 		if(vctl[vno]->isr != v->isr || vctl[vno]->eoi != v->eoi)
63 			panic("intrenable: handler: %s %s %#p %#p %#p %#p",
64 				vctl[vno]->name, v->name,
65 				vctl[vno]->isr, v->isr, vctl[vno]->eoi, v->eoi);
66 		v->next = vctl[vno];
67 	}
68 	vctl[vno] = v;
69 	iunlock(&vctllock);
70 }
71 
72 int
73 intrdisable(int irq, void (*f)(Ureg *, void *), void *a, int tbdf, char *name)
74 {
75 	Vctl **pv, *v;
76 	int vno;
77 
78 	/*
79 	 * For now, none of this will work with the APIC code,
80 	 * there is no mapping between irq and vector as the IRQ
81 	 * is pretty meaningless.
82 	 */
83 	if(arch->intrvecno == nil)
84 		return -1;
85 	vno = arch->intrvecno(irq);
86 	ilock(&vctllock);
87 	pv = &vctl[vno];
88 	while (*pv &&
89 		  ((*pv)->irq != irq || (*pv)->tbdf != tbdf || (*pv)->f != f || (*pv)->a != a ||
90 		   strcmp((*pv)->name, name)))
91 		pv = &((*pv)->next);
92 	assert(*pv);
93 
94 	v = *pv;
95 	*pv = (*pv)->next;	/* Link out the entry */
96 
97 	if(vctl[vno] == nil && arch->intrdisable != nil)
98 		arch->intrdisable(irq);
99 	iunlock(&vctllock);
100 	xfree(v);
101 	return 0;
102 }
103 
104 static long
105 irqallocread(Chan*, void *vbuf, long n, vlong offset)
106 {
107 	char *buf, *p, str[2*(11+1)+KNAMELEN+1+1];
108 	int m, vno;
109 	long oldn;
110 	Vctl *v;
111 
112 	if(n < 0 || offset < 0)
113 		error(Ebadarg);
114 
115 	oldn = n;
116 	buf = vbuf;
117 	for(vno=0; vno<nelem(vctl); vno++){
118 		for(v=vctl[vno]; v; v=v->next){
119 			m = snprint(str, sizeof str, "%11d %11d %.*s\n", vno, v->irq, KNAMELEN, v->name);
120 			if(m <= offset)	/* if do not want this, skip entry */
121 				offset -= m;
122 			else{
123 				/* skip offset bytes */
124 				m -= offset;
125 				p = str+offset;
126 				offset = 0;
127 
128 				/* write at most max(n,m) bytes */
129 				if(m > n)
130 					m = n;
131 				memmove(buf, p, m);
132 				n -= m;
133 				buf += m;
134 
135 				if(n == 0)
136 					return oldn;
137 			}
138 		}
139 	}
140 	return oldn - n;
141 }
142 
143 void
144 trapenable(int vno, void (*f)(Ureg*, void*), void* a, char *name)
145 {
146 	Vctl *v;
147 
148 	if(vno < 0 || vno >= VectorPIC)
149 		panic("trapenable: vno %d", vno);
150 	v = xalloc(sizeof(Vctl));
151 	v->tbdf = BUSUNKNOWN;
152 	v->f = f;
153 	v->a = a;
154 	strncpy(v->name, name, KNAMELEN);
155 	v->name[KNAMELEN-1] = 0;
156 
157 	ilock(&vctllock);
158 	if(vctl[vno])
159 		v->next = vctl[vno]->next;
160 	vctl[vno] = v;
161 	iunlock(&vctllock);
162 }
163 
164 static void
165 nmienable(void)
166 {
167 	int x;
168 
169 	/*
170 	 * Hack: should be locked with NVRAM access.
171 	 */
172 	outb(0x70, 0x80);		/* NMI latch clear */
173 	outb(0x70, 0);
174 
175 	x = inb(0x61) & 0x07;		/* Enable NMI */
176 	outb(0x61, 0x08|x);
177 	outb(0x61, x);
178 }
179 
180 /*
181  * Minimal trap setup.  Just enough so that we can panic
182  * on traps (bugs) during kernel initialization.
183  * Called very early - malloc is not yet available.
184  */
185 void
186 trapinit0(void)
187 {
188 	int d1, v;
189 	ulong vaddr;
190 	Segdesc *idt;
191 
192 	idt = (Segdesc*)IDTADDR;
193 	vaddr = (ulong)vectortable;
194 	for(v = 0; v < 256; v++){
195 		d1 = (vaddr & 0xFFFF0000)|SEGP;
196 		switch(v){
197 
198 		case VectorBPT:
199 			d1 |= SEGPL(3)|SEGIG;
200 			break;
201 
202 		case VectorSYSCALL:
203 			d1 |= SEGPL(3)|SEGIG;
204 			break;
205 
206 		default:
207 			d1 |= SEGPL(0)|SEGIG;
208 			break;
209 		}
210 		idt[v].d0 = (vaddr & 0xFFFF)|(KESEL<<16);
211 		idt[v].d1 = d1;
212 		vaddr += 6;
213 	}
214 }
215 
216 void
217 trapinit(void)
218 {
219 	/*
220 	 * Special traps.
221 	 * Syscall() is called directly without going through trap().
222 	 */
223 	trapenable(VectorBPT, debugbpt, 0, "debugpt");
224 	trapenable(VectorPF, fault386, 0, "fault386");
225 	trapenable(Vector2F, doublefault, 0, "doublefault");
226 	trapenable(Vector15, unexpected, 0, "unexpected");
227 	nmienable();
228 
229 	addarchfile("irqalloc", 0444, irqallocread, nil);
230 	trapinited = 1;
231 }
232 
233 static char* excname[32] = {
234 	"divide error",
235 	"debug exception",
236 	"nonmaskable interrupt",
237 	"breakpoint",
238 	"overflow",
239 	"bounds check",
240 	"invalid opcode",
241 	"coprocessor not available",
242 	"double fault",
243 	"coprocessor segment overrun",
244 	"invalid TSS",
245 	"segment not present",
246 	"stack exception",
247 	"general protection violation",
248 	"page fault",
249 	"15 (reserved)",
250 	"coprocessor error",
251 	"alignment check",
252 	"machine check",
253 	"19 (reserved)",
254 	"20 (reserved)",
255 	"21 (reserved)",
256 	"22 (reserved)",
257 	"23 (reserved)",
258 	"24 (reserved)",
259 	"25 (reserved)",
260 	"26 (reserved)",
261 	"27 (reserved)",
262 	"28 (reserved)",
263 	"29 (reserved)",
264 	"30 (reserved)",
265 	"31 (reserved)",
266 };
267 
268 /*
269  *  keep histogram of interrupt service times
270  */
271 void
272 intrtime(Mach*, int vno)
273 {
274 	ulong diff;
275 	ulong x;
276 
277 	x = perfticks();
278 	diff = x - m->perf.intrts;
279 	m->perf.intrts = x;
280 
281 	m->perf.inintr += diff;
282 	if(up == nil && m->perf.inidle > diff)
283 		m->perf.inidle -= diff;
284 
285 	diff /= m->cpumhz*100;		/* quantum = 100µsec */
286 	if(diff >= Ntimevec)
287 		diff = Ntimevec-1;
288 	intrtimes[vno][diff]++;
289 }
290 
291 /* go to user space */
292 void
293 kexit(Ureg*)
294 {
295 	uvlong t;
296 	Tos *tos;
297 
298 	/* precise time accounting, kernel exit */
299 	tos = (Tos*)(USTKTOP-sizeof(Tos));
300 	cycles(&t);
301 	tos->kcycles += t - up->kentry;
302 	tos->pcycles = up->pcycles;
303 	tos->pid = up->pid;
304 }
305 
306 /*
307  *  All traps come here.  It is slower to have all traps call trap()
308  *  rather than directly vectoring the handler.  However, this avoids a
309  *  lot of code duplication and possible bugs.  The only exception is
310  *  VectorSYSCALL.
311  *  Trap is called with interrupts disabled via interrupt-gates.
312  */
313 void
314 trap(Ureg* ureg)
315 {
316 	int clockintr, i, vno, user;
317 	char buf[ERRMAX];
318 	Vctl *ctl, *v;
319 	Mach *mach;
320 
321 	if(!trapinited){
322 		/* fault386 can give a better error message */
323 		if(ureg->trap == VectorPF)
324 			fault386(ureg, nil);
325 		panic("trap %lud: not ready", ureg->trap);
326 	}
327 
328 	m->perf.intrts = perfticks();
329 	user = (ureg->cs & 0xFFFF) == UESEL;
330 	if(user){
331 		up->dbgreg = ureg;
332 		cycles(&up->kentry);
333 	}
334 
335 	clockintr = 0;
336 
337 	vno = ureg->trap;
338 	if(ctl = vctl[vno]){
339 		if(ctl->isintr){
340 			m->intr++;
341 			if(vno >= VectorPIC && vno != VectorSYSCALL)
342 				m->lastintr = ctl->irq;
343 		}
344 
345 		if(ctl->isr)
346 			ctl->isr(vno);
347 		for(v = ctl; v != nil; v = v->next){
348 			if(v->f)
349 				v->f(ureg, v->a);
350 		}
351 		if(ctl->eoi)
352 			ctl->eoi(vno);
353 
354 		if(ctl->isintr){
355 			intrtime(m, vno);
356 
357 			if(ctl->irq == IrqCLOCK || ctl->irq == IrqTIMER)
358 				clockintr = 1;
359 
360 			if(up && !clockintr)
361 				preempted();
362 		}
363 	}
364 	else if(vno < nelem(excname) && user){
365 		spllo();
366 		sprint(buf, "sys: trap: %s", excname[vno]);
367 		postnote(up, 1, buf, NDebug);
368 	}
369 	else if(vno >= VectorPIC && vno != VectorSYSCALL){
370 		/*
371 		 * An unknown interrupt.
372 		 * Check for a default IRQ7. This can happen when
373 		 * the IRQ input goes away before the acknowledge.
374 		 * In this case, a 'default IRQ7' is generated, but
375 		 * the corresponding bit in the ISR isn't set.
376 		 * In fact, just ignore all such interrupts.
377 		 */
378 
379 		/* call all interrupt routines, just in case */
380 		for(i = VectorPIC; i <= MaxIrqLAPIC; i++){
381 			ctl = vctl[i];
382 			if(ctl == nil)
383 				continue;
384 			if(!ctl->isintr)
385 				continue;
386 			for(v = ctl; v != nil; v = v->next){
387 				if(v->f)
388 					v->f(ureg, v->a);
389 			}
390 			/* should we do this? */
391 			if(ctl->eoi)
392 				ctl->eoi(i);
393 		}
394 
395 		/* clear the interrupt */
396 		i8259isr(vno);
397 
398 		if(0)print("cpu%d: spurious interrupt %d, last %d\n",
399 			m->machno, vno, m->lastintr);
400 		if(0)if(conf.nmach > 1){
401 			for(i = 0; i < 32; i++){
402 				if(!(active.machs & (1<<i)))
403 					continue;
404 				mach = MACHP(i);
405 				if(m->machno == mach->machno)
406 					continue;
407 				print(" cpu%d: last %d",
408 					mach->machno, mach->lastintr);
409 			}
410 			print("\n");
411 		}
412 		m->spuriousintr++;
413 		if(user)
414 			kexit(ureg);
415 		return;
416 	}
417 	else{
418 		if(vno == VectorNMI){
419 			/*
420 			 * Don't re-enable, it confuses the crash dumps.
421 			nmienable();
422 			 */
423 			iprint("cpu%d: PC %#8.8lux\n", m->machno, ureg->pc);
424 			while(m->machno != 0)
425 				;
426 		}
427 		dumpregs(ureg);
428 		if(!user){
429 			ureg->sp = (ulong)&ureg->sp;
430 			_dumpstack(ureg);
431 		}
432 		if(vno < nelem(excname))
433 			panic("%s", excname[vno]);
434 		panic("unknown trap/intr: %d", vno);
435 	}
436 	splhi();
437 
438 	/* delaysched set because we held a lock or because our quantum ended */
439 	if(up && up->delaysched && clockintr){
440 		sched();
441 		splhi();
442 	}
443 
444 	if(user){
445 		if(up->procctl || up->nnote)
446 			notify(ureg);
447 		kexit(ureg);
448 	}
449 }
450 
451 /*
452  *  dump registers
453  */
454 void
455 dumpregs2(Ureg* ureg)
456 {
457 	if(up)
458 		iprint("cpu%d: registers for %s %lud\n",
459 			m->machno, up->text, up->pid);
460 	else
461 		iprint("cpu%d: registers for kernel\n", m->machno);
462 	iprint("FLAGS=%luX TRAP=%luX ECODE=%luX PC=%luX",
463 		ureg->flags, ureg->trap, ureg->ecode, ureg->pc);
464 	iprint(" SS=%4.4luX USP=%luX\n", ureg->ss & 0xFFFF, ureg->usp);
465 	iprint("  AX %8.8luX  BX %8.8luX  CX %8.8luX  DX %8.8luX\n",
466 		ureg->ax, ureg->bx, ureg->cx, ureg->dx);
467 	iprint("  SI %8.8luX  DI %8.8luX  BP %8.8luX\n",
468 		ureg->si, ureg->di, ureg->bp);
469 	iprint("  CS %4.4luX  DS %4.4luX  ES %4.4luX  FS %4.4luX  GS %4.4luX\n",
470 		ureg->cs & 0xFFFF, ureg->ds & 0xFFFF, ureg->es & 0xFFFF,
471 		ureg->fs & 0xFFFF, ureg->gs & 0xFFFF);
472 }
473 
474 void
475 dumpregs(Ureg* ureg)
476 {
477 	vlong mca, mct;
478 
479 	dumpregs2(ureg);
480 
481 	/*
482 	 * Processor control registers.
483 	 * If machine check exception, time stamp counter, page size extensions
484 	 * or enhanced virtual 8086 mode extensions are supported, there is a
485 	 * CR4. If there is a CR4 and machine check extensions, read the machine
486 	 * check address and machine check type registers if RDMSR supported.
487 	 */
488 	iprint("  CR0 %8.8lux CR2 %8.8lux CR3 %8.8lux",
489 		getcr0(), getcr2(), getcr3());
490 	if(m->cpuiddx & 0x9A){
491 		iprint(" CR4 %8.8lux", getcr4());
492 		if((m->cpuiddx & 0xA0) == 0xA0){
493 			rdmsr(0x00, &mca);
494 			rdmsr(0x01, &mct);
495 			iprint("\n  MCA %8.8llux MCT %8.8llux", mca, mct);
496 		}
497 	}
498 	iprint("\n  ur %#p up %#p\n", ureg, up);
499 }
500 
501 
502 /*
503  * Fill in enough of Ureg to get a stack trace, and call a function.
504  * Used by debugging interface rdb.
505  */
506 void
507 callwithureg(void (*fn)(Ureg*))
508 {
509 	Ureg ureg;
510 	ureg.pc = getcallerpc(&fn);
511 	ureg.sp = (ulong)&fn;
512 	fn(&ureg);
513 }
514 
515 static void
516 _dumpstack(Ureg *ureg)
517 {
518 	uintptr l, v, i, estack;
519 	extern ulong etext;
520 	int x;
521 	char *s;
522 
523 	if((s = getconf("*nodumpstack")) != nil && strcmp(s, "0") != 0){
524 		iprint("dumpstack disabled\n");
525 		return;
526 	}
527 	iprint("dumpstack\n");
528 
529 	x = 0;
530 	x += iprint("ktrace /kernel/path %.8lux %.8lux <<EOF\n", ureg->pc, ureg->sp);
531 	i = 0;
532 	if(up
533 	&& (uintptr)&l >= (uintptr)up->kstack
534 	&& (uintptr)&l <= (uintptr)up->kstack+KSTACK)
535 		estack = (uintptr)up->kstack+KSTACK;
536 	else if((uintptr)&l >= (uintptr)m->stack
537 	&& (uintptr)&l <= (uintptr)m+MACHSIZE)
538 		estack = (uintptr)m+MACHSIZE;
539 	else
540 		return;
541 	x += iprint("estackx %p\n", estack);
542 
543 	for(l = (uintptr)&l; l < estack; l += sizeof(uintptr)){
544 		v = *(uintptr*)l;
545 		if((KTZERO < v && v < (uintptr)&etext) || estack-l < 32){
546 			/*
547 			 * Could Pick off general CALL (((uchar*)v)[-5] == 0xE8)
548 			 * and CALL indirect through AX
549 			 * (((uchar*)v)[-2] == 0xFF && ((uchar*)v)[-2] == 0xD0),
550 			 * but this is too clever and misses faulting address.
551 			 */
552 			x += iprint("%.8p=%.8p ", l, v);
553 			i++;
554 		}
555 		if(i == 4){
556 			i = 0;
557 			x += iprint("\n");
558 		}
559 	}
560 	if(i)
561 		iprint("\n");
562 	iprint("EOF\n");
563 
564 	if(ureg->trap != VectorNMI)
565 		return;
566 
567 	i = 0;
568 	for(l = (uintptr)&l; l < estack; l += sizeof(uintptr)){
569 		iprint("%.8p ", *(uintptr*)l);
570 		if(++i == 8){
571 			i = 0;
572 			iprint("\n");
573 		}
574 	}
575 	if(i)
576 		iprint("\n");
577 }
578 
579 void
580 dumpstack(void)
581 {
582 	callwithureg(_dumpstack);
583 }
584 
585 static void
586 debugbpt(Ureg* ureg, void*)
587 {
588 	char buf[ERRMAX];
589 
590 	if(up == 0)
591 		panic("kernel bpt");
592 	/* restore pc to instruction that caused the trap */
593 	ureg->pc--;
594 	sprint(buf, "sys: breakpoint");
595 	postnote(up, 1, buf, NDebug);
596 }
597 
598 static void
599 doublefault(Ureg*, void*)
600 {
601 	panic("double fault");
602 }
603 
604 static void
605 unexpected(Ureg* ureg, void*)
606 {
607 	print("unexpected trap %lud; ignoring\n", ureg->trap);
608 }
609 
610 extern void checkpages(void);
611 extern void checkfault(ulong, ulong);
612 static void
613 fault386(Ureg* ureg, void*)
614 {
615 	ulong addr;
616 	int read, user, n, insyscall;
617 	char buf[ERRMAX];
618 
619 	addr = getcr2();
620 	read = !(ureg->ecode & 2);
621 
622 	user = (ureg->cs & 0xFFFF) == UESEL;
623 	if(!user){
624 		if(vmapsync(addr))
625 			return;
626 		if(addr >= USTKTOP)
627 			panic("kernel fault: bad address pc=0x%.8lux addr=0x%.8lux", ureg->pc, addr);
628 		if(up == nil)
629 			panic("kernel fault: no user process pc=0x%.8lux addr=0x%.8lux", ureg->pc, addr);
630 	}
631 	if(up == nil)
632 		panic("user fault: up=0 pc=0x%.8lux addr=0x%.8lux", ureg->pc, addr);
633 
634 	insyscall = up->insyscall;
635 	up->insyscall = 1;
636 	n = fault(addr, read);
637 	if(n < 0){
638 		if(!user){
639 			dumpregs(ureg);
640 			panic("fault: 0x%lux", addr);
641 		}
642 		checkpages();
643 		checkfault(addr, ureg->pc);
644 		sprint(buf, "sys: trap: fault %s addr=0x%lux",
645 			read ? "read" : "write", addr);
646 		postnote(up, 1, buf, NDebug);
647 	}
648 	up->insyscall = insyscall;
649 }
650 
651 /*
652  *  system calls
653  */
654 #include "../port/systab.h"
655 
656 /*
657  *  Syscall is called directly from assembler without going through trap().
658  */
659 void
660 syscall(Ureg* ureg)
661 {
662 	char *e;
663 	ulong	sp;
664 	long	ret;
665 	int	i, s;
666 	ulong scallnr;
667 
668 	if((ureg->cs & 0xFFFF) != UESEL)
669 		panic("syscall: cs 0x%4.4luX", ureg->cs);
670 
671 	cycles(&up->kentry);
672 
673 	m->syscall++;
674 	up->insyscall = 1;
675 	up->pc = ureg->pc;
676 	up->dbgreg = ureg;
677 
678 	if(up->procctl == Proc_tracesyscall){
679 		up->procctl = Proc_stopme;
680 		procctl(up);
681 	}
682 
683 	scallnr = ureg->ax;
684 	up->scallnr = scallnr;
685 	if(scallnr == RFORK && up->fpstate == FPactive){
686 		fpsave(&up->fpsave);
687 		up->fpstate = FPinactive;
688 	}
689 	spllo();
690 
691 	sp = ureg->usp;
692 	up->nerrlab = 0;
693 	ret = -1;
694 	if(!waserror()){
695 		if(scallnr >= nsyscall || systab[scallnr] == 0){
696 			pprint("bad sys call number %lud pc %lux\n",
697 				scallnr, ureg->pc);
698 			postnote(up, 1, "sys: bad sys call", NDebug);
699 			error(Ebadarg);
700 		}
701 
702 		if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-sizeof(Sargs)-BY2WD))
703 			validaddr(sp, sizeof(Sargs)+BY2WD, 0);
704 
705 		up->s = *((Sargs*)(sp+BY2WD));
706 		up->psstate = sysctab[scallnr];
707 
708 		ret = systab[scallnr](up->s.args);
709 		poperror();
710 	}else{
711 		/* failure: save the error buffer for errstr */
712 		e = up->syserrstr;
713 		up->syserrstr = up->errstr;
714 		up->errstr = e;
715 		if(0 && up->pid == 1)
716 			print("syscall %lud error %s\n", scallnr, up->syserrstr);
717 	}
718 	if(up->nerrlab){
719 		print("bad errstack [%lud]: %d extra\n", scallnr, up->nerrlab);
720 		for(i = 0; i < NERR; i++)
721 			print("sp=%lux pc=%lux\n",
722 				up->errlab[i].sp, up->errlab[i].pc);
723 		panic("error stack");
724 	}
725 
726 	/*
727 	 *  Put return value in frame.  On the x86 the syscall is
728 	 *  just another trap and the return value from syscall is
729 	 *  ignored.  On other machines the return value is put into
730 	 *  the results register by caller of syscall.
731 	 */
732 	ureg->ax = ret;
733 
734 	if(up->procctl == Proc_tracesyscall){
735 		up->procctl = Proc_stopme;
736 		s = splhi();
737 		procctl(up);
738 		splx(s);
739 	}
740 
741 	up->insyscall = 0;
742 	up->psstate = 0;
743 
744 	if(scallnr == NOTED)
745 		noted(ureg, *(ulong*)(sp+BY2WD));
746 
747 	if(scallnr!=RFORK && (up->procctl || up->nnote)){
748 		splhi();
749 		notify(ureg);
750 	}
751 	/* if we delayed sched because we held a lock, sched now */
752 	if(up->delaysched)
753 		sched();
754 	kexit(ureg);
755 }
756 
757 /*
758  *  Call user, if necessary, with note.
759  *  Pass user the Ureg struct and the note on his stack.
760  */
761 int
762 notify(Ureg* ureg)
763 {
764 	int l;
765 	ulong s, sp;
766 	Note *n;
767 
768 	if(up->procctl)
769 		procctl(up);
770 	if(up->nnote == 0)
771 		return 0;
772 
773 	if(up->fpstate == FPactive){
774 		fpsave(&up->fpsave);
775 		up->fpstate = FPinactive;
776 	}
777 	up->fpstate |= FPillegal;
778 
779 	s = spllo();
780 	qlock(&up->debug);
781 	up->notepending = 0;
782 	n = &up->note[0];
783 	if(strncmp(n->msg, "sys:", 4) == 0){
784 		l = strlen(n->msg);
785 		if(l > ERRMAX-15)	/* " pc=0x12345678\0" */
786 			l = ERRMAX-15;
787 		sprint(n->msg+l, " pc=0x%.8lux", ureg->pc);
788 	}
789 
790 	if(n->flag!=NUser && (up->notified || up->notify==0)){
791 		if(n->flag == NDebug)
792 			pprint("suicide: %s\n", n->msg);
793 		qunlock(&up->debug);
794 		pexit(n->msg, n->flag!=NDebug);
795 	}
796 
797 	if(up->notified){
798 		qunlock(&up->debug);
799 		splhi();
800 		return 0;
801 	}
802 
803 	if(!up->notify){
804 		qunlock(&up->debug);
805 		pexit(n->msg, n->flag!=NDebug);
806 	}
807 	sp = ureg->usp;
808 	sp -= 256;	/* debugging: preserve context causing problem */
809 	sp -= sizeof(Ureg);
810 if(0) print("%s %lud: notify %.8lux %.8lux %.8lux %s\n",
811 	up->text, up->pid, ureg->pc, ureg->usp, sp, n->msg);
812 
813 	if(!okaddr((ulong)up->notify, 1, 0)
814 	|| !okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1)){
815 		pprint("suicide: bad address in notify\n");
816 		qunlock(&up->debug);
817 		pexit("Suicide", 0);
818 	}
819 
820 	memmove((Ureg*)sp, ureg, sizeof(Ureg));
821 	*(Ureg**)(sp-BY2WD) = up->ureg;	/* word under Ureg is old up->ureg */
822 	up->ureg = (void*)sp;
823 	sp -= BY2WD+ERRMAX;
824 	memmove((char*)sp, up->note[0].msg, ERRMAX);
825 	sp -= 3*BY2WD;
826 	*(ulong*)(sp+2*BY2WD) = sp+3*BY2WD;		/* arg 2 is string */
827 	*(ulong*)(sp+1*BY2WD) = (ulong)up->ureg;	/* arg 1 is ureg* */
828 	*(ulong*)(sp+0*BY2WD) = 0;			/* arg 0 is pc */
829 	ureg->usp = sp;
830 	ureg->pc = (ulong)up->notify;
831 	up->notified = 1;
832 	up->nnote--;
833 	memmove(&up->lastnote, &up->note[0], sizeof(Note));
834 	memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note));
835 
836 	qunlock(&up->debug);
837 	splx(s);
838 	return 1;
839 }
840 
841 /*
842  *   Return user to state before notify()
843  */
844 void
845 noted(Ureg* ureg, ulong arg0)
846 {
847 	Ureg *nureg;
848 	ulong oureg, sp;
849 
850 	qlock(&up->debug);
851 	if(arg0!=NRSTR && !up->notified) {
852 		qunlock(&up->debug);
853 		pprint("call to noted() when not notified\n");
854 		pexit("Suicide", 0);
855 	}
856 	up->notified = 0;
857 
858 	nureg = up->ureg;	/* pointer to user returned Ureg struct */
859 
860 	up->fpstate &= ~FPillegal;
861 
862 	/* sanity clause */
863 	oureg = (ulong)nureg;
864 	if(!okaddr((ulong)oureg-BY2WD, BY2WD+sizeof(Ureg), 0)){
865 		pprint("bad ureg in noted or call to noted when not notified\n");
866 		qunlock(&up->debug);
867 		pexit("Suicide", 0);
868 	}
869 
870 	/*
871 	 * Check the segment selectors are all valid, otherwise
872 	 * a fault will be taken on attempting to return to the
873 	 * user process.
874 	 * Take care with the comparisons as different processor
875 	 * generations push segment descriptors in different ways.
876 	 */
877 	if((nureg->cs & 0xFFFF) != UESEL || (nureg->ss & 0xFFFF) != UDSEL
878 	  || (nureg->ds & 0xFFFF) != UDSEL || (nureg->es & 0xFFFF) != UDSEL
879 	  || (nureg->fs & 0xFFFF) != UDSEL || (nureg->gs & 0xFFFF) != UDSEL){
880 		pprint("bad segment selector in noted\n");
881 		qunlock(&up->debug);
882 		pexit("Suicide", 0);
883 	}
884 
885 	/* don't let user change system flags */
886 	nureg->flags = (ureg->flags & ~0xCD5) | (nureg->flags & 0xCD5);
887 
888 	memmove(ureg, nureg, sizeof(Ureg));
889 
890 	switch(arg0){
891 	case NCONT:
892 	case NRSTR:
893 if(0) print("%s %lud: noted %.8lux %.8lux\n",
894 	up->text, up->pid, nureg->pc, nureg->usp);
895 		if(!okaddr(nureg->pc, 1, 0) || !okaddr(nureg->usp, BY2WD, 0)){
896 			qunlock(&up->debug);
897 			pprint("suicide: trap in noted\n");
898 			pexit("Suicide", 0);
899 		}
900 		up->ureg = (Ureg*)(*(ulong*)(oureg-BY2WD));
901 		qunlock(&up->debug);
902 		break;
903 
904 	case NSAVE:
905 		if(!okaddr(nureg->pc, BY2WD, 0)
906 		|| !okaddr(nureg->usp, BY2WD, 0)){
907 			qunlock(&up->debug);
908 			pprint("suicide: trap in noted\n");
909 			pexit("Suicide", 0);
910 		}
911 		qunlock(&up->debug);
912 		sp = oureg-4*BY2WD-ERRMAX;
913 		splhi();
914 		ureg->sp = sp;
915 		((ulong*)sp)[1] = oureg;	/* arg 1 0(FP) is ureg* */
916 		((ulong*)sp)[0] = 0;		/* arg 0 is pc */
917 		break;
918 
919 	default:
920 		pprint("unknown noted arg 0x%lux\n", arg0);
921 		up->lastnote.flag = NDebug;
922 		/* fall through */
923 
924 	case NDFLT:
925 		if(up->lastnote.flag == NDebug){
926 			qunlock(&up->debug);
927 			pprint("suicide: %s\n", up->lastnote.msg);
928 		} else
929 			qunlock(&up->debug);
930 		pexit(up->lastnote.msg, up->lastnote.flag!=NDebug);
931 	}
932 }
933 
934 long
935 execregs(ulong entry, ulong ssize, ulong nargs)
936 {
937 	ulong *sp;
938 	Ureg *ureg;
939 
940 	up->fpstate = FPinit;
941 	fpoff();
942 
943 	sp = (ulong*)(USTKTOP - ssize);
944 	*--sp = nargs;
945 
946 	ureg = up->dbgreg;
947 	ureg->usp = (ulong)sp;
948 	ureg->pc = entry;
949 	return USTKTOP-sizeof(Tos);		/* address of kernel/user shared data */
950 }
951 
952 /*
953  *  return the userpc the last exception happened at
954  */
955 ulong
956 userpc(void)
957 {
958 	Ureg *ureg;
959 
960 	ureg = (Ureg*)up->dbgreg;
961 	return ureg->pc;
962 }
963 
964 /* This routine must save the values of registers the user is not permitted
965  * to write from devproc and then restore the saved values before returning.
966  */
967 void
968 setregisters(Ureg* ureg, char* pureg, char* uva, int n)
969 {
970 	ulong cs, ds, es, flags, fs, gs, ss;
971 
972 	ss = ureg->ss;
973 	flags = ureg->flags;
974 	cs = ureg->cs;
975 	ds = ureg->ds;
976 	es = ureg->es;
977 	fs = ureg->fs;
978 	gs = ureg->gs;
979 	memmove(pureg, uva, n);
980 	ureg->gs = gs;
981 	ureg->fs = fs;
982 	ureg->es = es;
983 	ureg->ds = ds;
984 	ureg->cs = cs;
985 	ureg->flags = (ureg->flags & 0x00FF) | (flags & 0xFF00);
986 	ureg->ss = ss;
987 }
988 
989 static void
990 linkproc(void)
991 {
992 	spllo();
993 	up->kpfun(up->kparg);
994 	pexit("kproc dying", 0);
995 }
996 
997 void
998 kprocchild(Proc* p, void (*func)(void*), void* arg)
999 {
1000 	/*
1001 	 * gotolabel() needs a word on the stack in
1002 	 * which to place the return PC used to jump
1003 	 * to linkproc().
1004 	 */
1005 	p->sched.pc = (ulong)linkproc;
1006 	p->sched.sp = (ulong)p->kstack+KSTACK-BY2WD;
1007 
1008 	p->kpfun = func;
1009 	p->kparg = arg;
1010 }
1011 
1012 void
1013 forkchild(Proc *p, Ureg *ureg)
1014 {
1015 	Ureg *cureg;
1016 
1017 	/*
1018 	 * Add 2*BY2WD to the stack to account for
1019 	 *  - the return PC
1020 	 *  - trap's argument (ur)
1021 	 */
1022 	p->sched.sp = (ulong)p->kstack+KSTACK-(sizeof(Ureg)+2*BY2WD);
1023 	p->sched.pc = (ulong)forkret;
1024 
1025 	cureg = (Ureg*)(p->sched.sp+2*BY2WD);
1026 	memmove(cureg, ureg, sizeof(Ureg));
1027 	/* return value of syscall in child */
1028 	cureg->ax = 0;
1029 
1030 	/* Things from bottom of syscall which were never executed */
1031 	p->psstate = 0;
1032 	p->insyscall = 0;
1033 }
1034 
1035 /* Give enough context in the ureg to produce a kernel stack for
1036  * a sleeping process
1037  */
1038 void
1039 setkernur(Ureg* ureg, Proc* p)
1040 {
1041 	ureg->pc = p->sched.pc;
1042 	ureg->sp = p->sched.sp+4;
1043 }
1044 
1045 ulong
1046 dbgpc(Proc *p)
1047 {
1048 	Ureg *ureg;
1049 
1050 	ureg = p->dbgreg;
1051 	if(ureg == 0)
1052 		return 0;
1053 
1054 	return ureg->pc;
1055 }
1056