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