xref: /plan9-contrib/sys/src/9/pc/trap.c (revision 5e4924093ecb86f7174bf23023955abc83fb6962)
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 %luX %luX %luX %luX\n",
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\n", 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 			nmienable();
420 			if(m->machno != 0){
421 				print("cpu%d: PC %8.8luX\n",
422 					m->machno, ureg->pc);
423 				for(;;);
424 			}
425 		}
426 		dumpregs(ureg);
427 		if(!user){
428 			ureg->sp = (ulong)&ureg->sp;
429 			_dumpstack(ureg);
430 		}
431 		if(vno < nelem(excname))
432 			panic("%s", excname[vno]);
433 		panic("unknown trap/intr: %d\n", vno);
434 	}
435 	splhi();
436 
437 	/* delaysched set because we held a lock or because our quantum ended */
438 	if(up && up->delaysched && clockintr){
439 		sched();
440 		splhi();
441 	}
442 
443 	if(user){
444 		if(up->procctl || up->nnote)
445 			notify(ureg);
446 		kexit(ureg);
447 	}
448 }
449 
450 /*
451  *  dump registers
452  */
453 void
454 dumpregs2(Ureg* ureg)
455 {
456 	if(up)
457 		print("cpu%d: registers for %s %lud\n",
458 			m->machno, up->text, up->pid);
459 	else
460 		print("cpu%d: registers for kernel\n", m->machno);
461 	print("FLAGS=%luX TRAP=%luX ECODE=%luX PC=%luX",
462 		ureg->flags, ureg->trap, ureg->ecode, ureg->pc);
463 	print(" SS=%4.4luX USP=%luX\n", ureg->ss & 0xFFFF, ureg->usp);
464 	print("  AX %8.8luX  BX %8.8luX  CX %8.8luX  DX %8.8luX\n",
465 		ureg->ax, ureg->bx, ureg->cx, ureg->dx);
466 	print("  SI %8.8luX  DI %8.8luX  BP %8.8luX\n",
467 		ureg->si, ureg->di, ureg->bp);
468 	print("  CS %4.4luX  DS %4.4luX  ES %4.4luX  FS %4.4luX  GS %4.4luX\n",
469 		ureg->cs & 0xFFFF, ureg->ds & 0xFFFF, ureg->es & 0xFFFF,
470 		ureg->fs & 0xFFFF, ureg->gs & 0xFFFF);
471 }
472 
473 void
474 dumpregs(Ureg* ureg)
475 {
476 	vlong mca, mct;
477 
478 	dumpregs2(ureg);
479 
480 	/*
481 	 * Processor control registers.
482 	 * If machine check exception, time stamp counter, page size extensions
483 	 * or enhanced virtual 8086 mode extensions are supported, there is a
484 	 * CR4. If there is a CR4 and machine check extensions, read the machine
485 	 * check address and machine check type registers if RDMSR supported.
486 	 */
487 	print("  CR0 %8.8lux CR2 %8.8lux CR3 %8.8lux",
488 		getcr0(), getcr2(), getcr3());
489 	if(m->cpuiddx & 0x9A){
490 		print(" CR4 %8.8lux", getcr4());
491 		if((m->cpuiddx & 0xA0) == 0xA0){
492 			rdmsr(0x00, &mca);
493 			rdmsr(0x01, &mct);
494 			print("\n  MCA %8.8llux MCT %8.8llux", mca, mct);
495 		}
496 	}
497 	print("\n  ur %lux up %lux\n", ureg, up);
498 }
499 
500 
501 /*
502  * Fill in enough of Ureg to get a stack trace, and call a function.
503  * Used by debugging interface rdb.
504  */
505 void
506 callwithureg(void (*fn)(Ureg*))
507 {
508 	Ureg ureg;
509 	ureg.pc = getcallerpc(&fn);
510 	ureg.sp = (ulong)&fn;
511 	fn(&ureg);
512 }
513 
514 static void
515 _dumpstack(Ureg *ureg)
516 {
517 	ulong l, v, i, estack;
518 	extern ulong etext;
519 	int x;
520 
521 	if(getconf("*nodumpstack")){
522 		iprint("dumpstack disabled\n");
523 		return;
524 	}
525 	iprint("dumpstack\n");
526 
527 	x = 0;
528 	x += print("ktrace /kernel/path %.8lux %.8lux <<EOF\n", ureg->pc, ureg->sp);
529 	i = 0;
530 	if(up
531 	&& (ulong)&l >= (ulong)up->kstack
532 	&& (ulong)&l <= (ulong)up->kstack+KSTACK)
533 		estack = (ulong)up->kstack+KSTACK;
534 	else if((ulong)&l >= (ulong)m->stack
535 	&& (ulong)&l <= (ulong)m+BY2PG)
536 		estack = (ulong)m+MACHSIZE;
537 	else
538 		return;
539 	x += print("estackx %.8lux\n", estack);
540 
541 	for(l=(ulong)&l; l<estack; l+=4){
542 		v = *(ulong*)l;
543 		if((KTZERO < v && v < (ulong)&etext) || estack-l<32){
544 			/*
545 			 * we could Pick off general CALL (((uchar*)v)[-5] == 0xE8)
546 			 * and CALL indirect through AX (((uchar*)v)[-2] == 0xFF && ((uchar*)v)[-2] == 0xD0),
547 			 * but this is too clever and misses faulting address.
548 			 */
549 			x += print("%.8lux=%.8lux ", l, v);
550 			i++;
551 		}
552 		if(i == 4){
553 			i = 0;
554 			x += print("\n");
555 		}
556 	}
557 	if(i)
558 		print("\n");
559 	print("EOF\n");
560 }
561 
562 void
563 dumpstack(void)
564 {
565 	callwithureg(_dumpstack);
566 }
567 
568 static void
569 debugbpt(Ureg* ureg, void*)
570 {
571 	char buf[ERRMAX];
572 
573 	if(up == 0)
574 		panic("kernel bpt");
575 	/* restore pc to instruction that caused the trap */
576 	ureg->pc--;
577 	sprint(buf, "sys: breakpoint");
578 	postnote(up, 1, buf, NDebug);
579 }
580 
581 static void
582 doublefault(Ureg*, void*)
583 {
584 	panic("double fault");
585 }
586 
587 static void
588 unexpected(Ureg* ureg, void*)
589 {
590 	print("unexpected trap %lud; ignoring\n", ureg->trap);
591 }
592 
593 extern void checkpages(void);
594 extern void checkfault(ulong, ulong);
595 static void
596 fault386(Ureg* ureg, void*)
597 {
598 	ulong addr;
599 	int read, user, n, insyscall;
600 	char buf[ERRMAX];
601 
602 	addr = getcr2();
603 	read = !(ureg->ecode & 2);
604 
605 	user = (ureg->cs & 0xFFFF) == UESEL;
606 	if(!user){
607 		if(vmapsync(addr))
608 			return;
609 		if(addr >= USTKTOP)
610 			panic("kernel fault: bad address pc=0x%.8lux addr=0x%.8lux", ureg->pc, addr);
611 		if(up == nil)
612 			panic("kernel fault: no user process pc=0x%.8lux addr=0x%.8lux", ureg->pc, addr);
613 	}
614 	if(up == nil)
615 		panic("user fault: up=0 pc=0x%.8lux addr=0x%.8lux", ureg->pc, addr);
616 
617 	insyscall = up->insyscall;
618 	up->insyscall = 1;
619 	n = fault(addr, read);
620 	if(n < 0){
621 		if(!user){
622 			dumpregs(ureg);
623 			panic("fault: 0x%lux\n", addr);
624 		}
625 		checkpages();
626 		checkfault(addr, ureg->pc);
627 		sprint(buf, "sys: trap: fault %s addr=0x%lux",
628 			read ? "read" : "write", addr);
629 		postnote(up, 1, buf, NDebug);
630 	}
631 	up->insyscall = insyscall;
632 }
633 
634 /*
635  *  system calls
636  */
637 #include "../port/systab.h"
638 
639 /*
640  *  Syscall is called directly from assembler without going through trap().
641  */
642 void
643 syscall(Ureg* ureg)
644 {
645 	char *e;
646 	ulong	sp;
647 	long	ret;
648 	int	i, s;
649 	ulong scallnr;
650 
651 	if((ureg->cs & 0xFFFF) != UESEL)
652 		panic("syscall: cs 0x%4.4luX\n", ureg->cs);
653 
654 	cycles(&up->kentry);
655 
656 	m->syscall++;
657 	up->insyscall = 1;
658 	up->pc = ureg->pc;
659 	up->dbgreg = ureg;
660 
661 	if(up->procctl == Proc_tracesyscall){
662 		up->procctl = Proc_stopme;
663 		procctl(up);
664 	}
665 
666 	scallnr = ureg->ax;
667 	up->scallnr = scallnr;
668 	if(scallnr == RFORK && up->fpstate == FPactive){
669 		fpsave(&up->fpsave);
670 		up->fpstate = FPinactive;
671 	}
672 	spllo();
673 
674 	sp = ureg->usp;
675 	up->nerrlab = 0;
676 	ret = -1;
677 	if(!waserror()){
678 		if(scallnr >= nsyscall || systab[scallnr] == 0){
679 			pprint("bad sys call number %d pc %lux\n",
680 				scallnr, ureg->pc);
681 			postnote(up, 1, "sys: bad sys call", NDebug);
682 			error(Ebadarg);
683 		}
684 
685 		if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-sizeof(Sargs)-BY2WD))
686 			validaddr(sp, sizeof(Sargs)+BY2WD, 0);
687 
688 		up->s = *((Sargs*)(sp+BY2WD));
689 		up->psstate = sysctab[scallnr];
690 
691 		ret = systab[scallnr](up->s.args);
692 		poperror();
693 	}else{
694 		/* failure: save the error buffer for errstr */
695 		e = up->syserrstr;
696 		up->syserrstr = up->errstr;
697 		up->errstr = e;
698 		if(0 && up->pid == 1)
699 			print("syscall %lud error %s\n", scallnr, up->syserrstr);
700 	}
701 	if(up->nerrlab){
702 		print("bad errstack [%lud]: %d extra\n", scallnr, up->nerrlab);
703 		for(i = 0; i < NERR; i++)
704 			print("sp=%lux pc=%lux\n",
705 				up->errlab[i].sp, up->errlab[i].pc);
706 		panic("error stack");
707 	}
708 
709 	/*
710 	 *  Put return value in frame.  On the x86 the syscall is
711 	 *  just another trap and the return value from syscall is
712 	 *  ignored.  On other machines the return value is put into
713 	 *  the results register by caller of syscall.
714 	 */
715 	ureg->ax = ret;
716 
717 	if(up->procctl == Proc_tracesyscall){
718 		up->procctl = Proc_stopme;
719 		s = splhi();
720 		procctl(up);
721 		splx(s);
722 	}
723 
724 	up->insyscall = 0;
725 	up->psstate = 0;
726 
727 	if(scallnr == NOTED)
728 		noted(ureg, *(ulong*)(sp+BY2WD));
729 
730 	if(scallnr!=RFORK && (up->procctl || up->nnote)){
731 		splhi();
732 		notify(ureg);
733 	}
734 	/* if we delayed sched because we held a lock, sched now */
735 	if(up->delaysched)
736 		sched();
737 	kexit(ureg);
738 }
739 
740 /*
741  *  Call user, if necessary, with note.
742  *  Pass user the Ureg struct and the note on his stack.
743  */
744 int
745 notify(Ureg* ureg)
746 {
747 	int l;
748 	ulong s, sp;
749 	Note *n;
750 
751 	if(up->procctl)
752 		procctl(up);
753 	if(up->nnote == 0)
754 		return 0;
755 
756 	if(up->fpstate == FPactive){
757 		fpsave(&up->fpsave);
758 		up->fpstate = FPinactive;
759 	}
760 	up->fpstate |= FPillegal;
761 
762 	s = spllo();
763 	qlock(&up->debug);
764 	up->notepending = 0;
765 	n = &up->note[0];
766 	if(strncmp(n->msg, "sys:", 4) == 0){
767 		l = strlen(n->msg);
768 		if(l > ERRMAX-15)	/* " pc=0x12345678\0" */
769 			l = ERRMAX-15;
770 		sprint(n->msg+l, " pc=0x%.8lux", ureg->pc);
771 	}
772 
773 	if(n->flag!=NUser && (up->notified || up->notify==0)){
774 		if(n->flag == NDebug)
775 			pprint("suicide: %s\n", n->msg);
776 		qunlock(&up->debug);
777 		pexit(n->msg, n->flag!=NDebug);
778 	}
779 
780 	if(up->notified){
781 		qunlock(&up->debug);
782 		splhi();
783 		return 0;
784 	}
785 
786 	if(!up->notify){
787 		qunlock(&up->debug);
788 		pexit(n->msg, n->flag!=NDebug);
789 	}
790 	sp = ureg->usp;
791 	sp -= sizeof(Ureg);
792 
793 	if(!okaddr((ulong)up->notify, 1, 0)
794 	|| !okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1)){
795 		pprint("suicide: bad address in notify\n");
796 		qunlock(&up->debug);
797 		pexit("Suicide", 0);
798 	}
799 
800 	up->ureg = (void*)sp;
801 	memmove((Ureg*)sp, ureg, sizeof(Ureg));
802 	*(Ureg**)(sp-BY2WD) = up->ureg;	/* word under Ureg is old up->ureg */
803 	up->ureg = (void*)sp;
804 	sp -= BY2WD+ERRMAX;
805 	memmove((char*)sp, up->note[0].msg, ERRMAX);
806 	sp -= 3*BY2WD;
807 	*(ulong*)(sp+2*BY2WD) = sp+3*BY2WD;		/* arg 2 is string */
808 	*(ulong*)(sp+1*BY2WD) = (ulong)up->ureg;	/* arg 1 is ureg* */
809 	*(ulong*)(sp+0*BY2WD) = 0;			/* arg 0 is pc */
810 	ureg->usp = sp;
811 	ureg->pc = (ulong)up->notify;
812 	up->notified = 1;
813 	up->nnote--;
814 	memmove(&up->lastnote, &up->note[0], sizeof(Note));
815 	memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note));
816 
817 	qunlock(&up->debug);
818 	splx(s);
819 	return 1;
820 }
821 
822 /*
823  *   Return user to state before notify()
824  */
825 void
826 noted(Ureg* ureg, ulong arg0)
827 {
828 	Ureg *nureg;
829 	ulong oureg, sp;
830 
831 	qlock(&up->debug);
832 	if(arg0!=NRSTR && !up->notified) {
833 		qunlock(&up->debug);
834 		pprint("call to noted() when not notified\n");
835 		pexit("Suicide", 0);
836 	}
837 	up->notified = 0;
838 
839 	nureg = up->ureg;	/* pointer to user returned Ureg struct */
840 
841 	up->fpstate &= ~FPillegal;
842 
843 	/* sanity clause */
844 	oureg = (ulong)nureg;
845 	if(!okaddr((ulong)oureg-BY2WD, BY2WD+sizeof(Ureg), 0)){
846 		pprint("bad ureg in noted or call to noted when not notified\n");
847 		qunlock(&up->debug);
848 		pexit("Suicide", 0);
849 	}
850 
851 	/*
852 	 * Check the segment selectors are all valid, otherwise
853 	 * a fault will be taken on attempting to return to the
854 	 * user process.
855 	 * Take care with the comparisons as different processor
856 	 * generations push segment descriptors in different ways.
857 	 */
858 	if((nureg->cs & 0xFFFF) != UESEL || (nureg->ss & 0xFFFF) != UDSEL
859 	  || (nureg->ds & 0xFFFF) != UDSEL || (nureg->es & 0xFFFF) != UDSEL
860 	  || (nureg->fs & 0xFFFF) != UDSEL || (nureg->gs & 0xFFFF) != UDSEL){
861 		pprint("bad segment selector in noted\n");
862 		qunlock(&up->debug);
863 		pexit("Suicide", 0);
864 	}
865 
866 	/* don't let user change system flags */
867 	nureg->flags = (ureg->flags & ~0xCD5) | (nureg->flags & 0xCD5);
868 
869 	memmove(ureg, nureg, sizeof(Ureg));
870 
871 	switch(arg0){
872 	case NCONT:
873 	case NRSTR:
874 		if(!okaddr(nureg->pc, 1, 0) || !okaddr(nureg->usp, BY2WD, 0)){
875 			qunlock(&up->debug);
876 			pprint("suicide: trap in noted\n");
877 			pexit("Suicide", 0);
878 		}
879 		up->ureg = (Ureg*)(*(ulong*)(oureg-BY2WD));
880 		qunlock(&up->debug);
881 		break;
882 
883 	case NSAVE:
884 		if(!okaddr(nureg->pc, BY2WD, 0)
885 		|| !okaddr(nureg->usp, BY2WD, 0)){
886 			qunlock(&up->debug);
887 			pprint("suicide: trap in noted\n");
888 			pexit("Suicide", 0);
889 		}
890 		qunlock(&up->debug);
891 		sp = oureg-4*BY2WD-ERRMAX;
892 		splhi();
893 		ureg->sp = sp;
894 		((ulong*)sp)[1] = oureg;	/* arg 1 0(FP) is ureg* */
895 		((ulong*)sp)[0] = 0;		/* arg 0 is pc */
896 		break;
897 
898 	default:
899 		pprint("unknown noted arg 0x%lux\n", arg0);
900 		up->lastnote.flag = NDebug;
901 		/* fall through */
902 
903 	case NDFLT:
904 		if(up->lastnote.flag == NDebug){
905 			qunlock(&up->debug);
906 			pprint("suicide: %s\n", up->lastnote.msg);
907 		} else
908 			qunlock(&up->debug);
909 		pexit(up->lastnote.msg, up->lastnote.flag!=NDebug);
910 	}
911 }
912 
913 long
914 execregs(ulong entry, ulong ssize, ulong nargs)
915 {
916 	ulong *sp;
917 	Ureg *ureg;
918 
919 	up->fpstate = FPinit;
920 	fpoff();
921 
922 	sp = (ulong*)(USTKTOP - ssize);
923 	*--sp = nargs;
924 
925 	ureg = up->dbgreg;
926 	ureg->usp = (ulong)sp;
927 	ureg->pc = entry;
928 	return USTKTOP-sizeof(Tos);		/* address of kernel/user shared data */
929 }
930 
931 /*
932  *  return the userpc the last exception happened at
933  */
934 ulong
935 userpc(void)
936 {
937 	Ureg *ureg;
938 
939 	ureg = (Ureg*)up->dbgreg;
940 	return ureg->pc;
941 }
942 
943 /* This routine must save the values of registers the user is not permitted
944  * to write from devproc and then restore the saved values before returning.
945  */
946 void
947 setregisters(Ureg* ureg, char* pureg, char* uva, int n)
948 {
949 	ulong flags;
950 	ulong cs;
951 	ulong ss;
952 
953 	flags = ureg->flags;
954 	cs = ureg->cs;
955 	ss = ureg->ss;
956 	memmove(pureg, uva, n);
957 	ureg->flags = (ureg->flags & 0x00FF) | (flags & 0xFF00);
958 	ureg->cs = cs;
959 	ureg->ss = ss;
960 }
961 
962 static void
963 linkproc(void)
964 {
965 	spllo();
966 	up->kpfun(up->kparg);
967 	pexit("kproc dying", 0);
968 }
969 
970 void
971 kprocchild(Proc* p, void (*func)(void*), void* arg)
972 {
973 	/*
974 	 * gotolabel() needs a word on the stack in
975 	 * which to place the return PC used to jump
976 	 * to linkproc().
977 	 */
978 	p->sched.pc = (ulong)linkproc;
979 	p->sched.sp = (ulong)p->kstack+KSTACK-BY2WD;
980 
981 	p->kpfun = func;
982 	p->kparg = arg;
983 }
984 
985 void
986 forkchild(Proc *p, Ureg *ureg)
987 {
988 	Ureg *cureg;
989 
990 	/*
991 	 * Add 2*BY2WD to the stack to account for
992 	 *  - the return PC
993 	 *  - trap's argument (ur)
994 	 */
995 	p->sched.sp = (ulong)p->kstack+KSTACK-(sizeof(Ureg)+2*BY2WD);
996 	p->sched.pc = (ulong)forkret;
997 
998 	cureg = (Ureg*)(p->sched.sp+2*BY2WD);
999 	memmove(cureg, ureg, sizeof(Ureg));
1000 	/* return value of syscall in child */
1001 	cureg->ax = 0;
1002 
1003 	/* Things from bottom of syscall which were never executed */
1004 	p->psstate = 0;
1005 	p->insyscall = 0;
1006 }
1007 
1008 /* Give enough context in the ureg to produce a kernel stack for
1009  * a sleeping process
1010  */
1011 void
1012 setkernur(Ureg* ureg, Proc* p)
1013 {
1014 	ureg->pc = p->sched.pc;
1015 	ureg->sp = p->sched.sp+4;
1016 }
1017 
1018 ulong
1019 dbgpc(Proc *p)
1020 {
1021 	Ureg *ureg;
1022 
1023 	ureg = p->dbgreg;
1024 	if(ureg == 0)
1025 		return 0;
1026 
1027 	return ureg->pc;
1028 }
1029