xref: /plan9/sys/src/9/pcboot/trap.c (revision 76a51bbfeb38f900d220158ac11ead554452ed25)
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 
11 enum {
12 	Dumpstack = 1,		/* flag: allow stack dump on panic */
13 };
14 
15 static int trapinited;
16 
17 void	noted(Ureg*, ulong);
18 
19 static void debugbpt(Ureg*, void*);
20 static void fault386(Ureg*, void*);
21 static void doublefault(Ureg*, void*);
22 static void unexpected(Ureg*, void*);
23 static void _dumpstack(Ureg*);
24 
25 static Lock vctllock;
26 static Vctl *vctl[256];
27 
28 enum
29 {
30 	Ntimevec = 20		/* number of time buckets for each intr */
31 };
32 
33 void
intrenable(int irq,void (* f)(Ureg *,void *),void * a,int tbdf,char * name)34 intrenable(int irq, void (*f)(Ureg*, void*), void* a, int tbdf, char *name)
35 {
36 	int vno;
37 	Vctl *v;
38 
39 	if(f == nil){
40 		print("intrenable: nil handler for %d, tbdf %#uX for %s\n",
41 			irq, tbdf, name);
42 		return;
43 	}
44 
45 	v = xalloc(sizeof(Vctl));
46 	v->isintr = 1;
47 	v->irq = irq;
48 	v->tbdf = tbdf;
49 	v->f = f;
50 	v->a = a;
51 	strncpy(v->name, name, KNAMELEN-1);
52 	v->name[KNAMELEN-1] = 0;
53 
54 	ilock(&vctllock);
55 	vno = arch->intrenable(v);
56 	if(vno == -1){
57 		iunlock(&vctllock);
58 		print("intrenable: couldn't enable irq %d, tbdf %#uX for %s\n",
59 			irq, tbdf, v->name);
60 		xfree(v);
61 		return;
62 	}
63 	if(vctl[vno]){
64 		if(vctl[vno]->isr != v->isr || vctl[vno]->eoi != v->eoi)
65 			panic("intrenable: handler: %s %s %#p %#p %#p %#p",
66 				vctl[vno]->name, v->name,
67 				vctl[vno]->isr, v->isr, vctl[vno]->eoi, v->eoi);
68 		v->next = vctl[vno];
69 	}
70 	vctl[vno] = v;
71 	iunlock(&vctllock);
72 }
73 
74 int
intrdisable(int irq,void (* f)(Ureg *,void *),void * a,int tbdf,char * name)75 intrdisable(int irq, void (*f)(Ureg *, void *), void *a, int tbdf, char *name)
76 {
77 	Vctl **pv, *v;
78 	int vno;
79 
80 	/*
81 	 * For now, none of this will work with the APIC code,
82 	 * there is no mapping between irq and vector as the IRQ
83 	 * is pretty meaningless.
84 	 */
85 	if(arch->intrvecno == nil)
86 		return -1;
87 	vno = arch->intrvecno(irq);
88 	ilock(&vctllock);
89 	pv = &vctl[vno];
90 	while (*pv &&
91 		  ((*pv)->irq != irq || (*pv)->tbdf != tbdf || (*pv)->f != f || (*pv)->a != a ||
92 		   strcmp((*pv)->name, name)))
93 		pv = &((*pv)->next);
94 	assert(*pv);
95 
96 	v = *pv;
97 	*pv = (*pv)->next;	/* Link out the entry */
98 
99 	if(vctl[vno] == nil && arch->intrdisable != nil)
100 		arch->intrdisable(irq);
101 	iunlock(&vctllock);
102 	xfree(v);
103 	return 0;
104 }
105 
106 static long
irqallocread(Chan *,void * vbuf,long n,vlong offset)107 irqallocread(Chan*, void *vbuf, long n, vlong offset)
108 {
109 	char *buf, *p, str[2*(11+1)+KNAMELEN+1+1];
110 	int m, vno;
111 	long oldn;
112 	Vctl *v;
113 
114 	if(n < 0 || offset < 0)
115 		error(Ebadarg);
116 
117 	oldn = n;
118 	buf = vbuf;
119 	for(vno=0; vno<nelem(vctl); vno++){
120 		for(v=vctl[vno]; v; v=v->next){
121 			m = snprint(str, sizeof str, "%11d %11d %.*s\n", vno, v->irq, KNAMELEN, v->name);
122 			if(m <= offset)	/* if do not want this, skip entry */
123 				offset -= m;
124 			else{
125 				/* skip offset bytes */
126 				m -= offset;
127 				p = str+offset;
128 				offset = 0;
129 
130 				/* write at most max(n,m) bytes */
131 				if(m > n)
132 					m = n;
133 				memmove(buf, p, m);
134 				n -= m;
135 				buf += m;
136 
137 				if(n == 0)
138 					return oldn;
139 			}
140 		}
141 	}
142 	return oldn - n;
143 }
144 
145 void
trapenable(int vno,void (* f)(Ureg *,void *),void * a,char * name)146 trapenable(int vno, void (*f)(Ureg*, void*), void* a, char *name)
147 {
148 	Vctl *v;
149 
150 	if(vno < 0 || vno >= VectorPIC)
151 		panic("trapenable: vno %d", vno);
152 	v = xalloc(sizeof(Vctl));
153 	v->tbdf = BUSUNKNOWN;
154 	v->f = f;
155 	v->a = a;
156 	strncpy(v->name, name, KNAMELEN);
157 	v->name[KNAMELEN-1] = 0;
158 
159 	ilock(&vctllock);
160 	v->next = vctl[vno];
161 	vctl[vno] = v;
162 	iunlock(&vctllock);
163 }
164 
165 static void
nmienable(void)166 nmienable(void)
167 {
168 	int x;
169 
170 	/*
171 	 * Hack: should be locked with NVRAM access.
172 	 */
173 	outb(0x70, 0x80);		/* NMI latch clear */
174 	outb(0x70, 0);
175 
176 	x = inb(0x61) & 0x07;		/* Enable NMI */
177 	outb(0x61, 0x08|x);
178 	outb(0x61, x);
179 }
180 
181 /*
182  * Minimal trap setup.  Just enough so that we can panic
183  * on traps (bugs) during kernel initialization.
184  * Called very early - malloc is not yet available.
185  */
186 void
trapinit0(void)187 trapinit0(void)
188 {
189 	int d1, v;
190 	ulong vaddr;
191 	Segdesc *idt;
192 
193 	idt = (Segdesc*)IDTADDR;
194 	vaddr = (ulong)vectortable;
195 	for(v = 0; v < 256; v++){
196 		d1 = (vaddr & 0xFFFF0000)|SEGP;
197 		switch(v){
198 
199 		case VectorBPT:
200 			d1 |= SEGPL(3)|SEGIG;
201 			break;
202 
203 		case VectorSYSCALL:
204 			d1 |= SEGPL(3)|SEGIG;
205 			break;
206 
207 		default:
208 			d1 |= SEGPL(0)|SEGIG;
209 			break;
210 		}
211 		idt[v].d0 = (vaddr & 0xFFFF)|(KESEL<<16);
212 		idt[v].d1 = d1;
213 		vaddr += 6;
214 	}
215 }
216 
217 void
trapinit(void)218 trapinit(void)
219 {
220 	/*
221 	 * Special traps.
222 	 * Syscall() is called directly without going through trap().
223 	 */
224 	trapenable(VectorBPT, debugbpt, 0, "debugpt");
225 	trapenable(VectorPF, fault386, 0, "fault386");
226 	trapenable(Vector2F, doublefault, 0, "doublefault");
227 	trapenable(Vector15, unexpected, 0, "unexpected");
228 	nmienable();
229 
230 	addarchfile("irqalloc", 0444, irqallocread, nil);
231 	trapinited = 1;
232 }
233 
234 static char* excname[32] = {
235 	"divide error",
236 	"debug exception",
237 	"nonmaskable interrupt",
238 	"breakpoint",
239 	"overflow",
240 	"bounds check",
241 	"invalid opcode",
242 	"coprocessor not available",
243 	"double fault",
244 	"coprocessor segment overrun",
245 	"invalid TSS",
246 	"segment not present",
247 	"stack exception",
248 	"general protection violation",
249 	"page fault",
250 	"15 (reserved)",
251 	"coprocessor error",
252 	"alignment check",
253 	"machine check",
254 	"19 (reserved)",
255 	"20 (reserved)",
256 	"21 (reserved)",
257 	"22 (reserved)",
258 	"23 (reserved)",
259 	"24 (reserved)",
260 	"25 (reserved)",
261 	"26 (reserved)",
262 	"27 (reserved)",
263 	"28 (reserved)",
264 	"29 (reserved)",
265 	"30 (reserved)",
266 	"31 (reserved)",
267 };
268 
269 /*
270  *  keep histogram of interrupt service times
271  */
272 void
intrtime(Mach *,int vno)273 intrtime(Mach*, int vno)
274 {
275 	ulong diff;
276 	ulong x;
277 
278 	x = perfticks();
279 	diff = x - m->perf.intrts;
280 	m->perf.intrts = x;
281 
282 	m->perf.inintr += diff;
283 	if(up == nil && m->perf.inidle > diff)
284 		m->perf.inidle -= diff;
285 	USED(vno);
286 }
287 
288 /* go to user space */
289 void
kexit(Ureg *)290 kexit(Ureg*)
291 {
292 	uvlong t;
293 	Tos *tos;
294 
295 	/* precise time accounting, kernel exit */
296 	tos = (Tos*)(USTKTOP-sizeof(Tos));
297 	cycles(&t);
298 	tos->kcycles += t - up->kentry;
299 	tos->pcycles = up->pcycles;
300 	tos->pid = up->pid;
301 }
302 
303 /*
304  *  All traps come here.  It is slower to have all traps call trap()
305  *  rather than directly vectoring the handler.  However, this avoids a
306  *  lot of code duplication and possible bugs.  The only exception is
307  *  VectorSYSCALL.
308  *  Trap is called with interrupts disabled via interrupt-gates.
309  */
310 void
trap(Ureg * ureg)311 trap(Ureg* ureg)
312 {
313 	int clockintr, i, vno, user;
314 	Vctl *ctl, *v;
315 	Mach *mach;
316 
317 	if(!trapinited){
318 		/* fault386 can give a better error message */
319 		if(ureg->trap == VectorPF)
320 			fault386(ureg, nil);
321 		panic("trap %lud: not ready", ureg->trap);
322 	}
323 
324 	if (m == 0)
325 		panic("trap: nil m");
326 	m->perf.intrts = perfticks();
327 	user = (ureg->cs & 0xFFFF) == UESEL;
328 
329 	clockintr = 0;
330 
331 	vno = ureg->trap;
332 	if(ctl = vctl[vno]){
333 		if(ctl->isintr){
334 			m->intr++;
335 			if(vno >= VectorPIC && vno != VectorSYSCALL)
336 				m->lastintr = ctl->irq;
337 		}
338 
339 		if(ctl->isr)
340 			ctl->isr(vno);
341 		for(v = ctl; v != nil; v = v->next){
342 			if(v->f)
343 				v->f(ureg, v->a);
344 		}
345 		if(ctl->eoi)
346 			ctl->eoi(vno);
347 
348 		if(ctl->isintr){
349 			intrtime(m, vno);
350 
351 			if(ctl->irq == IrqCLOCK || ctl->irq == IrqTIMER)
352 				clockintr = 1;
353 
354 			if(up && !clockintr)
355 				preempted();
356 		}
357 	}
358 	else if(vno < nelem(excname) && user){
359 		char buf[ERRMAX];
360 
361 		spllo();
362 		snprint(buf, sizeof buf, "sys: trap: %s", excname[vno]);
363 		postnote(up, 1, buf, NDebug);
364 	}
365 	else if(vno >= VectorPIC && vno != VectorSYSCALL){
366 		/*
367 		 * An unknown interrupt.
368 		 * Check for a default IRQ7. This can happen when
369 		 * the IRQ input goes away before the acknowledge.
370 		 * In this case, a 'default IRQ7' is generated, but
371 		 * the corresponding bit in the ISR isn't set.
372 		 * In fact, just ignore all such interrupts.
373 		 */
374 
375 		/* call all interrupt routines, just in case */
376 		for(i = VectorPIC; i <= MaxIrqLAPIC; i++){
377 			ctl = vctl[i];
378 			if(ctl == nil)
379 				continue;
380 			if(!ctl->isintr)
381 				continue;
382 			for(v = ctl; v != nil; v = v->next){
383 				if(v->f)
384 					v->f(ureg, v->a);
385 			}
386 			/* should we do this? */
387 			if(ctl->eoi)
388 				ctl->eoi(i);
389 		}
390 
391 		/* clear the interrupt */
392 		i8259isr(vno);
393 
394 		if(0)print("cpu%d: spurious interrupt %d, last %d\n",
395 			m->machno, vno, m->lastintr);
396 		if(0)if(conf.nmach > 1){
397 			for(i = 0; i < 32; i++){
398 				if(!(active.machs & (1<<i)))
399 					continue;
400 				mach = MACHP(i);
401 				if(m->machno == mach->machno)
402 					continue;
403 				print(" cpu%d: last %d",
404 					mach->machno, mach->lastintr);
405 			}
406 			print("\n");
407 		}
408 		m->spuriousintr++;
409 		return;
410 	}
411 	else{
412 		if(vno == VectorNMI){
413 			/*
414 			 * Don't re-enable, it confuses the crash dumps.
415 			nmienable();
416 			 */
417 			iprint("cpu%d: NMI PC %#8.8lux\n", m->machno, ureg->pc);
418 			while(m->machno != 0)
419 				;
420 		}
421 		dumpregs(ureg);
422 		if(vno < nelem(excname))
423 			panic("%s", excname[vno]);
424 		panic("unknown trap/intr: %d", vno);
425 	}
426 	splhi();
427 
428 	/* delaysched set because we held a lock or because our quantum ended */
429 	if(up && up->delaysched && clockintr){
430 		sched();
431 		splhi();
432 	}
433 }
434 
435 /*
436  *  dump registers
437  */
438 void
dumpregs2(Ureg * ureg)439 dumpregs2(Ureg* ureg)
440 {
441 	if(up)
442 		iprint("cpu%d: registers for %s %lud\n",
443 			m->machno, up->text, up->pid);
444 	else
445 		iprint("cpu%d: registers for kernel\n", m->machno);
446 	iprint("FLAGS=%luX TRAP=%luX ECODE=%luX PC=%luX",
447 		ureg->flags, ureg->trap, ureg->ecode, ureg->pc);
448 	iprint(" SS=%4.4luX USP=%luX\n", ureg->ss & 0xFFFF, ureg->usp);
449 	iprint("  AX %8.8luX  BX %8.8luX  CX %8.8luX  DX %8.8luX\n",
450 		ureg->ax, ureg->bx, ureg->cx, ureg->dx);
451 	iprint("  SI %8.8luX  DI %8.8luX  BP %8.8luX\n",
452 		ureg->si, ureg->di, ureg->bp);
453 	iprint("  CS %4.4luX  DS %4.4luX  ES %4.4luX  FS %4.4luX  GS %4.4luX\n",
454 		ureg->cs & 0xFFFF, ureg->ds & 0xFFFF, ureg->es & 0xFFFF,
455 		ureg->fs & 0xFFFF, ureg->gs & 0xFFFF);
456 }
457 
458 void
dumpregs(Ureg * ureg)459 dumpregs(Ureg* ureg)
460 {
461 	vlong mca, mct;
462 
463 	dumpregs2(ureg);
464 
465 	/*
466 	 * Processor control registers.
467 	 * If machine check exception, time stamp counter, page size extensions
468 	 * or enhanced virtual 8086 mode extensions are supported, there is a
469 	 * CR4. If there is a CR4 and machine check extensions, read the machine
470 	 * check address and machine check type registers if RDMSR supported.
471 	 */
472 	iprint("  CR0 %8.8lux CR2 %8.8lux CR3 %8.8lux",
473 		getcr0(), getcr2(), getcr3());
474 	if(m->cpuiddx & 0x9A){
475 		iprint(" CR4 %8.8lux", getcr4());
476 		if((m->cpuiddx & 0xA0) == 0xA0){
477 			rdmsr(0x00, &mca);
478 			rdmsr(0x01, &mct);
479 			iprint("\n  MCA %8.8llux MCT %8.8llux", mca, mct);
480 		}
481 	}
482 	iprint("\n  ur %#p up %#p\n", ureg, up);
483 }
484 
485 
486 /*
487  * Fill in enough of Ureg to get a stack trace, and call a function.
488  * Used by debugging interface rdb.
489  */
490 void
callwithureg(void (* fn)(Ureg *))491 callwithureg(void (*fn)(Ureg*))
492 {
493 	Ureg ureg;
494 	ureg.pc = getcallerpc(&fn);
495 	ureg.sp = (ulong)&fn;
496 	fn(&ureg);
497 }
498 
499 static void
_dumpstack(Ureg * ureg)500 _dumpstack(Ureg *ureg)
501 {
502 	uintptr l, v, i, estack;
503 	extern ulong etext;
504 	int x;
505 	char *s;
506 
507 	if (!Dumpstack) {
508 		print("no stack dump\n");
509 		return;
510 	}
511 	if((s = getconf("*nodumpstack")) != nil && strcmp(s, "0") != 0){
512 		iprint("dumpstack disabled\n");
513 		return;
514 	}
515 	iprint("dumpstack\n");
516 
517 	x = 0;
518 	x += iprint("ktrace /kernel/path %.8lux %.8lux <<EOF\n", ureg->pc, ureg->sp);
519 	i = 0;
520 	if(up
521 	&& (uintptr)&l >= (uintptr)up->kstack
522 	&& (uintptr)&l <= (uintptr)up->kstack+KSTACK)
523 		estack = (uintptr)up->kstack+KSTACK;
524 	else if((uintptr)&l >= (uintptr)m->stack
525 	&& (uintptr)&l <= (uintptr)m+MACHSIZE)
526 		estack = (uintptr)m+MACHSIZE;
527 	else
528 		return;
529 	x += iprint("estackx %p\n", estack);
530 
531 	for(l = (uintptr)&l; l < estack; l += sizeof(uintptr)){
532 		v = *(uintptr*)l;
533 		if((KTZERO < v && v < (uintptr)&etext) || estack-l < 32){
534 			/*
535 			 * Could Pick off general CALL (((uchar*)v)[-5] == 0xE8)
536 			 * and CALL indirect through AX
537 			 * (((uchar*)v)[-2] == 0xFF && ((uchar*)v)[-2] == 0xD0),
538 			 * but this is too clever and misses faulting address.
539 			 */
540 			x += iprint("%.8p=%.8p ", l, v);
541 			i++;
542 		}
543 		if(i == 4){
544 			i = 0;
545 			x += iprint("\n");
546 		}
547 	}
548 	if(i)
549 		iprint("\n");
550 	iprint("EOF\n");
551 
552 	if(ureg->trap != VectorNMI)
553 		return;
554 
555 	i = 0;
556 	for(l = (uintptr)&l; l < estack; l += sizeof(uintptr)){
557 		iprint("%.8p ", *(uintptr*)l);
558 		if(++i == 8){
559 			i = 0;
560 			iprint("\n");
561 		}
562 	}
563 	if(i)
564 		iprint("\n");
565 }
566 
567 void
dumpstack(void)568 dumpstack(void)
569 {
570 	callwithureg(_dumpstack);
571 }
572 
573 static void
debugbpt(Ureg * ureg,void *)574 debugbpt(Ureg* ureg, void*)
575 {
576 	char buf[ERRMAX];
577 
578 	if(up == 0)
579 		panic("kernel bpt");
580 	/* restore pc to instruction that caused the trap */
581 	ureg->pc--;
582 	snprint(buf, sizeof buf, "sys: breakpoint");
583 	postnote(up, 1, buf, NDebug);
584 }
585 
586 static void
doublefault(Ureg *,void *)587 doublefault(Ureg*, void*)
588 {
589 	panic("double fault");
590 }
591 
592 static void
unexpected(Ureg * ureg,void *)593 unexpected(Ureg* ureg, void*)
594 {
595 	print("unexpected trap %lud; ignoring\n", ureg->trap);
596 }
597 
598 extern void checkfault(ulong, ulong);
599 static void
fault386(Ureg * ureg,void *)600 fault386(Ureg* ureg, void*)
601 {
602 	ulong addr;
603 	int read, user, n, insyscall;
604 
605 	addr = getcr2();
606 	read = !(ureg->ecode & 2);
607 
608 	user = (ureg->cs & 0xFFFF) == UESEL;
609 	if(!user){
610 		if(vmapsync(addr))
611 			return;
612 		if(addr >= USTKTOP)
613 			panic("kernel fault: bad address pc=%#.8lux addr=%#.8lux", ureg->pc, addr);
614 		if(up == nil)
615 			panic("kernel fault: no user process pc=%#.8lux addr=%#.8lux", ureg->pc, addr);
616 	} else
617 		panic("fault386: fault from user mode");
618 	if(up == nil)
619 		panic("user fault: up=0 pc=%#.8lux addr=%#.8lux", ureg->pc, addr);
620 
621 	insyscall = up->insyscall;
622 	up->insyscall = 1;
623 	n = fault(addr, read);
624 	if(n < 0){
625 		dumpregs(ureg);
626 		panic("fault: %#lux", addr);
627 	}
628 	up->insyscall = insyscall;
629 }
630 
631 /*
632  *  dregs of system calls
633  */
634 
635 /*
636  *  Syscall is called directly from assembler without going through trap().
637  */
638 void
syscall(Ureg *)639 syscall(Ureg*)
640 {
641 	/* the bootstrap doesn't implement system calls */
642 	panic("syscall");
643 }
644 
645 long
execregs(ulong entry,ulong ssize,ulong nargs)646 execregs(ulong entry, ulong ssize, ulong nargs)
647 {
648 	ulong *sp;
649 	Ureg *ureg;
650 
651 	up->fpstate = FPinit;
652 	fpoff();
653 
654 	sp = (ulong*)(USTKTOP - ssize);
655 	*--sp = nargs;
656 
657 	ureg = up->dbgreg;
658 	ureg->usp = (ulong)sp;
659 	ureg->pc = entry;
660 	return USTKTOP-sizeof(Tos);		/* address of kernel/user shared data */
661 }
662 
663 /*
664  *  return the userpc the last exception happened at
665  */
666 ulong
userpc(void)667 userpc(void)
668 {
669 	Ureg *ureg;
670 
671 	ureg = (Ureg*)up->dbgreg;
672 	return ureg->pc;
673 }
674 
675 /* This routine must save the values of registers the user is not permitted
676  * to write from devproc and then restore the saved values before returning.
677  */
678 void
setregisters(Ureg * ureg,char * pureg,char * uva,int n)679 setregisters(Ureg* ureg, char* pureg, char* uva, int n)
680 {
681 	ulong cs, ds, es, flags, fs, gs, ss;
682 
683 	ss = ureg->ss;
684 	flags = ureg->flags;
685 	cs = ureg->cs;
686 	ds = ureg->ds;
687 	es = ureg->es;
688 	fs = ureg->fs;
689 	gs = ureg->gs;
690 	memmove(pureg, uva, n);
691 	ureg->gs = gs;
692 	ureg->fs = fs;
693 	ureg->es = es;
694 	ureg->ds = ds;
695 	ureg->cs = cs;
696 	ureg->flags = (ureg->flags & 0x00FF) | (flags & 0xFF00);
697 	ureg->ss = ss;
698 }
699 
700 static void
linkproc(void)701 linkproc(void)
702 {
703 	spllo();
704 	up->kpfun(up->kparg);
705 	pexit("kproc dying", 0);
706 }
707 
708 void
kprocchild(Proc * p,void (* func)(void *),void * arg)709 kprocchild(Proc* p, void (*func)(void*), void* arg)
710 {
711 	/*
712 	 * gotolabel() needs a word on the stack in
713 	 * which to place the return PC used to jump
714 	 * to linkproc().
715 	 */
716 	p->sched.pc = (ulong)linkproc;
717 	p->sched.sp = (ulong)p->kstack+KSTACK-BY2WD;
718 
719 	p->kpfun = func;
720 	p->kparg = arg;
721 }
722 
723 void
forkchild(Proc * p,Ureg * ureg)724 forkchild(Proc *p, Ureg *ureg)
725 {
726 	Ureg *cureg;
727 
728 	/*
729 	 * Add 2*BY2WD to the stack to account for
730 	 *  - the return PC
731 	 *  - trap's argument (ur)
732 	 */
733 	p->sched.sp = (ulong)p->kstack+KSTACK-(sizeof(Ureg)+2*BY2WD);
734 	p->sched.pc = (ulong)forkret;
735 
736 	cureg = (Ureg*)(p->sched.sp+2*BY2WD);
737 	memmove(cureg, ureg, sizeof(Ureg));
738 	/* return value of syscall in child */
739 	cureg->ax = 0;
740 
741 	/* Things from bottom of syscall which were never executed */
742 	p->psstate = 0;
743 	p->insyscall = 0;
744 }
745 
746 /* Give enough context in the ureg to produce a kernel stack for
747  * a sleeping process
748  */
749 void
setkernur(Ureg * ureg,Proc * p)750 setkernur(Ureg* ureg, Proc* p)
751 {
752 	ureg->pc = p->sched.pc;
753 	ureg->sp = p->sched.sp+4;
754 }
755 
756 ulong
dbgpc(Proc * p)757 dbgpc(Proc *p)
758 {
759 	Ureg *ureg;
760 
761 	ureg = p->dbgreg;
762 	if(ureg == 0)
763 		return 0;
764 
765 	return ureg->pc;
766 }
767