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