]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/trap.c
audiohda: fix syntax error
[plan9front.git] / sys / src / 9 / pc / trap.c
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 extern int irqhandled(Ureg*, int);
13 extern void irqinit(void);
14
15 void    noted(Ureg*, ulong);
16
17 static void debugexc(Ureg*, void*);
18 static void debugbpt(Ureg*, void*);
19 static void fault386(Ureg*, void*);
20 static void doublefault(Ureg*, void*);
21 static void unexpected(Ureg*, void*);
22 static void _dumpstack(Ureg*);
23
24 /*
25  * Minimal trap setup.  Just enough so that we can panic
26  * on traps (bugs) during kernel initialization.
27  * Called very early - malloc is not yet available.
28  */
29 void
30 trapinit0(void)
31 {
32         int d1, v;
33         ulong vaddr;
34         Segdesc *idt;
35         ushort ptr[3];
36
37         idt = (Segdesc*)IDTADDR;
38         vaddr = (ulong)vectortable;
39         for(v = 0; v < 256; v++){
40                 d1 = (vaddr & 0xFFFF0000)|SEGP;
41                 switch(v){
42                 case VectorBPT:
43                         d1 |= SEGPL(3)|SEGIG;
44                         break;
45
46                 case VectorSYSCALL:
47                         d1 |= SEGPL(3)|SEGIG;
48                         break;
49
50                 default:
51                         d1 |= SEGPL(0)|SEGIG;
52                         break;
53                 }
54                 idt[v].d0 = (vaddr & 0xFFFF)|(KESEL<<16);
55                 idt[v].d1 = d1;
56                 vaddr += 6;
57         }
58         ptr[0] = sizeof(Segdesc)*256-1;
59         ptr[1] = IDTADDR & 0xFFFF;
60         ptr[2] = IDTADDR >> 16;
61         lidt(ptr);
62 }
63
64 void
65 trapinit(void)
66 {
67         irqinit();
68
69         nmienable();
70
71         /*
72          * Special traps.
73          * Syscall() is called directly without going through trap().
74          */
75         trapenable(VectorDE, debugexc, 0, "debugexc");
76         trapenable(VectorBPT, debugbpt, 0, "debugpt");
77         trapenable(VectorPF, fault386, 0, "fault386");
78         trapenable(Vector2F, doublefault, 0, "doublefault");
79         trapenable(Vector15, unexpected, 0, "unexpected");
80 }
81
82 static char* excname[32] = {
83         "divide error",
84         "debug exception",
85         "nonmaskable interrupt",
86         "breakpoint",
87         "overflow",
88         "bounds check",
89         "invalid opcode",
90         "coprocessor not available",
91         "double fault",
92         "coprocessor segment overrun",
93         "invalid TSS",
94         "segment not present",
95         "stack exception",
96         "general protection violation",
97         "page fault",
98         "15 (reserved)",
99         "coprocessor error",
100         "alignment check",
101         "machine check",
102         "simd error",
103         "20 (reserved)",
104         "21 (reserved)",
105         "22 (reserved)",
106         "23 (reserved)",
107         "24 (reserved)",
108         "25 (reserved)",
109         "26 (reserved)",
110         "27 (reserved)",
111         "28 (reserved)",
112         "29 (reserved)",
113         "30 (reserved)",
114         "31 (reserved)",
115 };
116
117 static int
118 usertrap(int vno)
119 {
120         char buf[ERRMAX];
121
122         if(vno < nelem(excname)){
123                 spllo();
124                 sprint(buf, "sys: trap: %s", excname[vno]);
125                 postnote(up, 1, buf, NDebug);
126                 return 1;
127         }
128         return 0;
129 }
130
131 /*
132  *  All traps come here.  It is slower to have all traps call trap()
133  *  rather than directly vectoring the handler.  However, this avoids a
134  *  lot of code duplication and possible bugs.  The only exception is
135  *  VectorSYSCALL.
136  *  Trap is called with interrupts disabled via interrupt-gates.
137  */
138 void
139 trap(Ureg* ureg)
140 {
141         int vno, user;
142
143         user = kenter(ureg);
144         vno = ureg->trap;
145         if(!irqhandled(ureg, vno) && (!user || !usertrap(vno))){
146                 if(!user){
147                         void (*pc)(void);
148                         ulong *sp; 
149
150                         extern void _forkretpopgs(void);
151                         extern void _forkretpopfs(void);
152                         extern void _forkretpopes(void);
153                         extern void _forkretpopds(void);
154                         extern void _forkretiret(void);
155                         extern void _rdmsrinst(void);
156                         extern void _wrmsrinst(void);
157                         extern void _peekinst(void);
158
159                         extern void load_fs(ulong);
160                         extern void load_gs(ulong);
161
162                         load_fs(NULLSEL);
163                         load_gs(NULLSEL);
164
165                         sp = (ulong*)&ureg->sp; /* kernel stack */
166                         pc = (void*)ureg->pc;
167
168                         if(pc == _forkretpopgs || pc == _forkretpopfs || 
169                            pc == _forkretpopes || pc == _forkretpopds){
170                                 if(vno == VectorGPF || vno == VectorSNP){
171                                         sp[0] = NULLSEL;
172                                         return;
173                                 }
174                         } else if(pc == _forkretiret){
175                                 if(vno == VectorGPF || vno == VectorSNP){
176                                         sp[1] = UESEL;  /* CS */
177                                         sp[4] = UDSEL;  /* SS */
178                                         return;
179                                 }
180                         } else if(pc == _rdmsrinst || pc == _wrmsrinst){
181                                 if(vno == VectorGPF){
182                                         ureg->bp = -1;
183                                         ureg->pc += 2;
184                                         return;
185                                 }
186                         } else if(pc == _peekinst){
187                                 if(vno == VectorGPF){
188                                         ureg->pc += 2;
189                                         return;
190                                 }
191                         }
192
193                         /* early fault before trapinit() */
194                         if(vno == VectorPF)
195                                 fault386(ureg, 0);
196                 }
197
198                 dumpregs(ureg);
199                 if(!user){
200                         ureg->sp = (ulong)&ureg->sp;
201                         _dumpstack(ureg);
202                 }
203                 if(vno < nelem(excname))
204                         panic("%s", excname[vno]);
205                 panic("unknown trap/intr: %d", vno);
206         }
207         splhi();
208
209         if(user){
210                 if(up->procctl || up->nnote)
211                         notify(ureg);
212                 kexit(ureg);
213         }
214 }
215
216 /*
217  *  dump registers
218  */
219 void
220 dumpregs2(Ureg* ureg)
221 {
222         if(up)
223                 iprint("cpu%d: registers for %s %lud\n",
224                         m->machno, up->text, up->pid);
225         else
226                 iprint("cpu%d: registers for kernel\n", m->machno);
227         iprint("FLAGS=%luX TRAP=%luX ECODE=%luX PC=%luX",
228                 ureg->flags, ureg->trap, ureg->ecode, ureg->pc);
229         if(userureg(ureg))
230                 iprint(" SS=%4.4luX USP=%luX\n", ureg->ss & 0xFFFF, ureg->usp);
231         else
232                 iprint(" SP=%luX\n", (ulong)&ureg->sp);
233         iprint("  AX %8.8luX  BX %8.8luX  CX %8.8luX  DX %8.8luX\n",
234                 ureg->ax, ureg->bx, ureg->cx, ureg->dx);
235         iprint("  SI %8.8luX  DI %8.8luX  BP %8.8luX\n",
236                 ureg->si, ureg->di, ureg->bp);
237         iprint("  CS %4.4luX  DS %4.4luX  ES %4.4luX  FS %4.4luX  GS %4.4luX\n",
238                 ureg->cs & 0xFFFF, ureg->ds & 0xFFFF, ureg->es & 0xFFFF,
239                 ureg->fs & 0xFFFF, ureg->gs & 0xFFFF);
240 }
241
242 void
243 dumpregs(Ureg* ureg)
244 {
245         dumpregs2(ureg);
246
247         /*
248          * Processor control registers.
249          * If machine check exception, time stamp counter, page size extensions
250          * or enhanced virtual 8086 mode extensions are supported, there is a
251          * CR4. If there is a CR4 and machine check extensions, read the machine
252          * check address and machine check type registers if RDMSR supported.
253          */
254         iprint("  CR0 %8.8lux CR2 %8.8lux CR3 %8.8lux",
255                 getcr0(), getcr2(), getcr3());
256         if(m->cpuiddx & (Mce|Tsc|Pse|Vmex)){
257                 iprint(" CR4 %8.8lux\n", getcr4());
258                 if(ureg->trap == 18)
259                         dumpmcregs();
260         }
261         iprint("\n  ur %#p up %#p\n", ureg, up);
262 }
263
264
265 /*
266  * Fill in enough of Ureg to get a stack trace, and call a function.
267  * Used by debugging interface rdb.
268  */
269 void
270 callwithureg(void (*fn)(Ureg*))
271 {
272         Ureg ureg;
273         ureg.pc = getcallerpc(&fn);
274         ureg.sp = (ulong)&fn;
275         fn(&ureg);
276 }
277
278 static void
279 _dumpstack(Ureg *ureg)
280 {
281         uintptr l, v, i, estack;
282         extern ulong etext;
283         int x;
284         char *s;
285
286         if((s = getconf("*nodumpstack")) != nil && strcmp(s, "0") != 0){
287                 iprint("dumpstack disabled\n");
288                 return;
289         }
290         iprint("dumpstack\n");
291
292         x = 0;
293         x += iprint("ktrace /kernel/path %.8lux %.8lux <<EOF\n", ureg->pc, ureg->sp);
294         i = 0;
295         if(up
296         && (uintptr)&l >= (uintptr)up->kstack
297         && (uintptr)&l <= (uintptr)up->kstack+KSTACK)
298                 estack = (uintptr)up->kstack+KSTACK;
299         else if((uintptr)&l >= (uintptr)m->stack
300         && (uintptr)&l <= (uintptr)m+MACHSIZE)
301                 estack = (uintptr)m+MACHSIZE;
302         else
303                 return;
304         x += iprint("estackx %p\n", estack);
305
306         for(l = (uintptr)&l; l < estack; l += sizeof(uintptr)){
307                 v = *(uintptr*)l;
308                 if((KTZERO < v && v < (uintptr)&etext) || estack-l < 32){
309                         /*
310                          * Could Pick off general CALL (((uchar*)v)[-5] == 0xE8)
311                          * and CALL indirect through AX
312                          * (((uchar*)v)[-2] == 0xFF && ((uchar*)v)[-2] == 0xD0),
313                          * but this is too clever and misses faulting address.
314                          */
315                         x += iprint("%.8p=%.8p ", l, v);
316                         i++;
317                 }
318                 if(i == 4){
319                         i = 0;
320                         x += iprint("\n");
321                 }
322         }
323         if(i)
324                 iprint("\n");
325         iprint("EOF\n");
326
327         if(ureg->trap != VectorNMI)
328                 return;
329
330         i = 0;
331         for(l = (uintptr)&l; l < estack; l += sizeof(uintptr)){
332                 iprint("%.8p ", *(uintptr*)l);
333                 if(++i == 8){
334                         i = 0;
335                         iprint("\n");
336                 }
337         }
338         if(i)
339                 iprint("\n");
340 }
341
342 void
343 dumpstack(void)
344 {
345         callwithureg(_dumpstack);
346 }
347
348 static void
349 debugexc(Ureg *ureg, void *)
350 {
351         u32int dr6, m;
352         char buf[ERRMAX];
353         char *p, *e;
354         int i;
355
356         dr6 = getdr6();
357         if(up == nil)
358                 panic("kernel debug exception dr6=%#.8ux", dr6);
359         putdr6(up->dr[6]);
360         if(userureg(ureg))
361                 qlock(&up->debug);
362         else if(!canqlock(&up->debug))
363                 return;
364         m = up->dr[7];
365         m = (m >> 4 | m >> 3) & 8 | (m >> 3 | m >> 2) & 4 | (m >> 2 | m >> 1) & 2 | (m >> 1 | m) & 1;
366         m &= dr6;
367         if(m == 0){
368                 sprint(buf, "sys: debug exception dr6=%#.8ux", dr6);
369                 postnote(up, 0, buf, NDebug);
370         }else{
371                 p = buf;
372                 e = buf + sizeof(buf);
373                 p = seprint(p, e, "sys: watchpoint ");
374                 for(i = 0; i < 4; i++)
375                         if((m & 1<<i) != 0)
376                                 p = seprint(p, e, "%d%s", i, (m >> i + 1 != 0) ? "," : "");
377                 postnote(up, 0, buf, NDebug);
378         }
379         qunlock(&up->debug);
380 }
381
382 static void
383 debugbpt(Ureg* ureg, void*)
384 {
385         char buf[ERRMAX];
386
387         if(up == 0)
388                 panic("kernel bpt");
389         /* restore pc to instruction that caused the trap */
390         ureg->pc--;
391         sprint(buf, "sys: breakpoint");
392         postnote(up, 1, buf, NDebug);
393 }
394
395 static void
396 doublefault(Ureg*, void*)
397 {
398         panic("double fault");
399 }
400
401 static void
402 unexpected(Ureg* ureg, void*)
403 {
404         print("unexpected trap %lud; ignoring\n", ureg->trap);
405 }
406
407 extern void checkpages(void);
408 extern void checkfault(ulong, ulong);
409 static void
410 fault386(Ureg* ureg, void*)
411 {
412         ulong addr;
413         int read, user, n, insyscall;
414         char buf[ERRMAX];
415
416         addr = getcr2();
417         read = !(ureg->ecode & 2);
418
419         user = userureg(ureg);
420         if(!user){
421                 if(vmapsync(addr))
422                         return;
423                 {
424                         extern void _peekinst(void);
425                         if((void(*)(void))ureg->pc == _peekinst){
426                                 ureg->pc += 2;
427                                 return;
428                         }
429                 }
430                 if(addr >= USTKTOP)
431                         panic("kernel fault: bad address pc=0x%.8lux addr=0x%.8lux", ureg->pc, addr);
432                 if(up == nil)
433                         panic("kernel fault: no user process pc=0x%.8lux addr=0x%.8lux", ureg->pc, addr);
434         }
435         if(up == nil)
436                 panic("user fault: up=0 pc=0x%.8lux addr=0x%.8lux", ureg->pc, addr);
437
438         insyscall = up->insyscall;
439         up->insyscall = 1;
440         n = fault(addr, ureg->pc, read);
441         if(n < 0){
442                 if(!user){
443                         dumpregs(ureg);
444                         panic("fault: 0x%lux", addr);
445                 }
446                 checkpages();
447                 checkfault(addr, ureg->pc);
448                 sprint(buf, "sys: trap: fault %s addr=0x%lux",
449                         read ? "read" : "write", addr);
450                 postnote(up, 1, buf, NDebug);
451         }
452         up->insyscall = insyscall;
453 }
454
455 /*
456  *  system calls
457  */
458 #include "../port/systab.h"
459
460 /*
461  *  Syscall is called directly from assembler without going through trap().
462  */
463 void
464 syscall(Ureg* ureg)
465 {
466         char *e;
467         ulong   sp;
468         long    ret;
469         int     i, s;
470         ulong scallnr;
471         vlong startns, stopns;
472
473         if(!kenter(ureg))
474                 panic("syscall: cs 0x%4.4luX", ureg->cs);
475
476         m->syscall++;
477         up->insyscall = 1;
478         up->pc = ureg->pc;
479
480         sp = ureg->usp;
481         scallnr = ureg->ax;
482         up->scallnr = scallnr;
483
484         spllo();
485
486         up->nerrlab = 0;
487         ret = -1;
488         if(!waserror()){
489                 if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-sizeof(Sargs)-BY2WD))
490                         validaddr(sp, sizeof(Sargs)+BY2WD, 0);
491
492                 up->s = *((Sargs*)(sp+BY2WD));
493
494                 if(up->procctl == Proc_tracesyscall){
495                         syscallfmt(scallnr, ureg->pc, (va_list)up->s.args);
496                         s = splhi();
497                         up->procctl = Proc_stopme;
498                         procctl();
499                         splx(s);
500                         startns = todget(nil);
501                 }
502
503                 if(scallnr >= nsyscall || systab[scallnr] == 0){
504                         pprint("bad sys call number %lud pc %lux\n",
505                                 scallnr, ureg->pc);
506                         postnote(up, 1, "sys: bad sys call", NDebug);
507                         error(Ebadarg);
508                 }
509                 up->psstate = sysctab[scallnr];
510                 ret = systab[scallnr]((va_list)up->s.args);
511                 poperror();
512         }else{
513                 /* failure: save the error buffer for errstr */
514                 e = up->syserrstr;
515                 up->syserrstr = up->errstr;
516                 up->errstr = e;
517                 if(0 && up->pid == 1)
518                         print("syscall %lud error %s\n", scallnr, up->syserrstr);
519         }
520         if(up->nerrlab){
521                 print("bad errstack [%lud]: %d extra\n", scallnr, up->nerrlab);
522                 for(i = 0; i < NERR; i++)
523                         print("sp=%lux pc=%lux\n",
524                                 up->errlab[i].sp, up->errlab[i].pc);
525                 panic("error stack");
526         }
527
528         /*
529          *  Put return value in frame.  On the x86 the syscall is
530          *  just another trap and the return value from syscall is
531          *  ignored.  On other machines the return value is put into
532          *  the results register by caller of syscall.
533          */
534         ureg->ax = ret;
535
536         if(up->procctl == Proc_tracesyscall){
537                 stopns = todget(nil);
538                 sysretfmt(scallnr, (va_list)up->s.args, ret, startns, stopns);
539                 s = splhi();
540                 up->procctl = Proc_stopme;
541                 procctl();
542                 splx(s);
543         }
544
545         up->insyscall = 0;
546         up->psstate = 0;
547
548         if(scallnr == NOTED)
549                 noted(ureg, *((ulong*)up->s.args));
550
551         if(scallnr!=RFORK && (up->procctl || up->nnote)){
552                 splhi();
553                 notify(ureg);
554         }
555         /* if we delayed sched because we held a lock, sched now */
556         if(up->delaysched)
557                 sched();
558         kexit(ureg);
559 }
560
561 /*
562  *  Call user, if necessary, with note.
563  *  Pass user the Ureg struct and the note on his stack.
564  */
565 int
566 notify(Ureg* ureg)
567 {
568         int l;
569         ulong s, sp;
570         Note *n;
571
572         if(up->procctl)
573                 procctl();
574         if(up->nnote == 0)
575                 return 0;
576
577         if(up->fpstate == FPactive){
578                 fpsave(up->fpsave);
579                 up->fpstate = FPinactive;
580         }
581         up->fpstate |= FPillegal;
582
583         s = spllo();
584         qlock(&up->debug);
585         up->notepending = 0;
586         n = &up->note[0];
587         if(strncmp(n->msg, "sys:", 4) == 0){
588                 l = strlen(n->msg);
589                 if(l > ERRMAX-15)       /* " pc=0x12345678\0" */
590                         l = ERRMAX-15;
591                 sprint(n->msg+l, " pc=0x%.8lux", ureg->pc);
592         }
593
594         if(n->flag!=NUser && (up->notified || up->notify==0)){
595                 qunlock(&up->debug);
596                 if(n->flag == NDebug)
597                         pprint("suicide: %s\n", n->msg);
598                 pexit(n->msg, n->flag!=NDebug);
599         }
600
601         if(up->notified){
602                 qunlock(&up->debug);
603                 splhi();
604                 return 0;
605         }
606
607         if(!up->notify){
608                 qunlock(&up->debug);
609                 pexit(n->msg, n->flag!=NDebug);
610         }
611         sp = ureg->usp;
612         sp -= 256;      /* debugging: preserve context causing problem */
613         sp -= sizeof(Ureg);
614 if(0) print("%s %lud: notify %.8lux %.8lux %.8lux %s\n",
615         up->text, up->pid, ureg->pc, ureg->usp, sp, n->msg);
616
617         if(!okaddr((uintptr)up->notify, 1, 0)
618         || !okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1)){
619                 qunlock(&up->debug);
620                 pprint("suicide: bad address in notify\n");
621                 pexit("Suicide", 0);
622         }
623
624         memmove((Ureg*)sp, ureg, sizeof(Ureg));
625         *(Ureg**)(sp-BY2WD) = up->ureg; /* word under Ureg is old up->ureg */
626         up->ureg = (void*)sp;
627         sp -= BY2WD+ERRMAX;
628         memmove((char*)sp, up->note[0].msg, ERRMAX);
629         sp -= 3*BY2WD;
630         *(ulong*)(sp+2*BY2WD) = sp+3*BY2WD;             /* arg 2 is string */
631         *(ulong*)(sp+1*BY2WD) = (ulong)up->ureg;        /* arg 1 is ureg* */
632         *(ulong*)(sp+0*BY2WD) = 0;                      /* arg 0 is pc */
633         ureg->usp = sp;
634         ureg->pc = (ulong)up->notify;
635         ureg->cs = UESEL;
636         ureg->ss = ureg->ds = ureg->es = UDSEL;
637         up->notified = 1;
638         up->nnote--;
639         memmove(&up->lastnote, &up->note[0], sizeof(Note));
640         memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note));
641
642         qunlock(&up->debug);
643         splx(s);
644         return 1;
645 }
646
647 /*
648  *   Return user to state before notify()
649  */
650 void
651 noted(Ureg* ureg, ulong arg0)
652 {
653         Ureg *nureg;
654         ulong oureg, sp;
655
656         qlock(&up->debug);
657         if(arg0!=NRSTR && !up->notified) {
658                 qunlock(&up->debug);
659                 pprint("call to noted() when not notified\n");
660                 pexit("Suicide", 0);
661         }
662         up->notified = 0;
663
664         nureg = up->ureg;       /* pointer to user returned Ureg struct */
665
666         up->fpstate &= ~FPillegal;
667
668         /* sanity clause */
669         oureg = (ulong)nureg;
670         if(!okaddr(oureg-BY2WD, BY2WD+sizeof(Ureg), 0)){
671                 qunlock(&up->debug);
672                 pprint("bad ureg in noted or call to noted when not notified\n");
673                 pexit("Suicide", 0);
674         }
675
676         /* don't let user change system flags */
677         nureg->flags = (ureg->flags & ~0xCD5) | (nureg->flags & 0xCD5);
678         nureg->cs |= 3;
679         nureg->ss |= 3;
680
681         memmove(ureg, nureg, sizeof(Ureg));
682
683         switch(arg0){
684         case NCONT:
685         case NRSTR:
686 if(0) print("%s %lud: noted %.8lux %.8lux\n",
687         up->text, up->pid, nureg->pc, nureg->usp);
688                 if(!okaddr(nureg->pc, 1, 0) || !okaddr(nureg->usp, BY2WD, 0)){
689                         qunlock(&up->debug);
690                         pprint("suicide: trap in noted\n");
691                         pexit("Suicide", 0);
692                 }
693                 up->ureg = (Ureg*)(*(ulong*)(oureg-BY2WD));
694                 qunlock(&up->debug);
695                 break;
696
697         case NSAVE:
698                 if(!okaddr(nureg->pc, BY2WD, 0)
699                 || !okaddr(nureg->usp, BY2WD, 0)){
700                         qunlock(&up->debug);
701                         pprint("suicide: trap in noted\n");
702                         pexit("Suicide", 0);
703                 }
704                 qunlock(&up->debug);
705                 sp = oureg-4*BY2WD-ERRMAX;
706                 splhi();
707                 ureg->sp = sp;
708                 ((ulong*)sp)[1] = oureg;        /* arg 1 0(FP) is ureg* */
709                 ((ulong*)sp)[0] = 0;            /* arg 0 is pc */
710                 break;
711
712         default:
713                 up->lastnote.flag = NDebug;
714                 /* fall through */
715
716         case NDFLT:
717                 qunlock(&up->debug);
718                 if(up->lastnote.flag == NDebug)
719                         pprint("suicide: %s\n", up->lastnote.msg);
720                 pexit(up->lastnote.msg, up->lastnote.flag!=NDebug);
721         }
722 }
723
724 uintptr
725 execregs(uintptr entry, ulong ssize, ulong nargs)
726 {
727         ulong *sp;
728         Ureg *ureg;
729
730         sp = (ulong*)(USTKTOP - ssize);
731         *--sp = nargs;
732
733         ureg = up->dbgreg;
734         ureg->usp = (ulong)sp;
735         ureg->pc = entry;
736         ureg->cs = UESEL;
737         ureg->ss = ureg->ds = ureg->es = UDSEL;
738         ureg->fs = ureg->gs = NULLSEL;
739         return USTKTOP-sizeof(Tos);             /* address of kernel/user shared data */
740 }
741
742 /*
743  *  return the userpc the last exception happened at
744  */
745 uintptr
746 userpc(void)
747 {
748         Ureg *ureg;
749
750         ureg = (Ureg*)up->dbgreg;
751         return ureg->pc;
752 }
753
754 /* This routine must save the values of registers the user is not permitted
755  * to write from devproc and then restore the saved values before returning.
756  */
757 void
758 setregisters(Ureg* ureg, char* pureg, char* uva, int n)
759 {
760         ulong flags;
761
762         flags = ureg->flags;
763         memmove(pureg, uva, n);
764         ureg->flags = (ureg->flags & 0xCD5) | (flags & ~0xCD5);
765         ureg->cs |= 3;
766         ureg->ss |= 3;
767 }
768
769 void
770 kprocchild(Proc *p, void (*entry)(void))
771 {
772         /*
773          * gotolabel() needs a word on the stack in
774          * which to place the return PC used to jump
775          * to linkproc().
776          */
777         p->sched.pc = (ulong)entry;
778         p->sched.sp = (ulong)p->kstack+KSTACK-BY2WD;
779 }
780
781 void
782 forkchild(Proc *p, Ureg *ureg)
783 {
784         Ureg *cureg;
785
786         /*
787          * Add 2*BY2WD to the stack to account for
788          *  - the return PC
789          *  - trap's argument (ur)
790          */
791         p->sched.sp = (ulong)p->kstack+KSTACK-(sizeof(Ureg)+2*BY2WD);
792         p->sched.pc = (ulong)forkret;
793
794         cureg = (Ureg*)(p->sched.sp+2*BY2WD);
795         memmove(cureg, ureg, sizeof(Ureg));
796         /* return value of syscall in child */
797         cureg->ax = 0;
798 }
799
800 /* Give enough context in the ureg to produce a kernel stack for
801  * a sleeping process
802  */
803 void
804 setkernur(Ureg* ureg, Proc* p)
805 {
806         ureg->pc = p->sched.pc;
807         ureg->sp = p->sched.sp+4;
808 }
809
810 ulong
811 dbgpc(Proc *p)
812 {
813         Ureg *ureg;
814
815         ureg = p->dbgreg;
816         if(ureg == 0)
817                 return 0;
818
819         return ureg->pc;
820 }