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