]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc64/trap.c
pc64: check if vmap() range fits in VMAPLEN window, remove unneeded vmapsync(), renam...
[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 faultamd64(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, 0x0C|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, faultamd64, 0, "faultamd64");
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                 /* faultamd64 can give a better error message */
319                 if(ureg->type == VectorPF)
320                         faultamd64(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 < MAXMACH; i++){
398                                 if(active.machs[i] == 0)
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: nmi PC %#p, status %ux\n",
420                                 m->machno, ureg->pc, inb(0x61));
421                         while(m->machno != 0)
422                                 ;
423                 }
424
425                 if(!user){
426                         void (*pc)(void);
427
428                         extern void _rdmsrinst(void);
429                         extern void _wrmsrinst(void);
430
431                         pc = (void*)ureg->pc;
432                         if(pc == _rdmsrinst || pc == _wrmsrinst){
433                                 if(vno == VectorGPF){
434                                         ureg->bp = -1;
435                                         ureg->pc += 2;
436                                         return;
437                                 }
438                         }
439                 }
440
441                 dumpregs(ureg);
442                 if(!user){
443                         ureg->sp = (uintptr)&ureg->sp;
444                         _dumpstack(ureg);
445                 }
446                 if(vno < nelem(excname))
447                         panic("%s", excname[vno]);
448                 panic("unknown trap/intr: %d", vno);
449         }
450         splhi();
451
452         /* delaysched set because we held a lock or because our quantum ended */
453         if(up && up->delaysched && clockintr){
454                 sched();
455                 splhi();
456         }
457
458         if(user){
459                 if(up->procctl || up->nnote)
460                         notify(ureg);
461                 kexit(ureg);
462         }
463 }
464
465 void
466 dumpregs(Ureg* ureg)
467 {
468         if(up)
469                 iprint("cpu%d: registers for %s %lud\n",
470                         m->machno, up->text, up->pid);
471         else
472                 iprint("cpu%d: registers for kernel\n", m->machno);
473
474         iprint("  AX %.16lluX  BX %.16lluX  CX %.16lluX\n",
475                 ureg->ax, ureg->bx, ureg->cx);
476         iprint("  DX %.16lluX  SI %.16lluX  DI %.16lluX\n",
477                 ureg->dx, ureg->si, ureg->di);
478         iprint("  BP %.16lluX  R8 %.16lluX  R9 %.16lluX\n",
479                 ureg->bp, ureg->r8, ureg->r9);
480         iprint(" R10 %.16lluX R11 %.16lluX R12 %.16lluX\n",
481                 ureg->r10, ureg->r11, ureg->r12);
482         iprint(" R13 %.16lluX R14 %.16lluX R15 %.16lluX\n",
483                 ureg->r13, ureg->r14, ureg->r15);
484         iprint("  CS %.4lluX   SS %.4lluX    PC %.16lluX  SP %.16lluX\n",
485                 ureg->cs & 0xffff, ureg->ss & 0xffff, ureg->pc, ureg->sp);
486         iprint("TYPE %.2lluX  ERROR %.4lluX FLAGS %.8lluX\n",
487                 ureg->type & 0xff, ureg->error & 0xffff, ureg->flags & 0xffffffff);
488
489         /*
490          * Processor control registers.
491          * If machine check exception, time stamp counter, page size extensions
492          * or enhanced virtual 8086 mode extensions are supported, there is a
493          * CR4. If there is a CR4 and machine check extensions, read the machine
494          * check address and machine check type registers if RDMSR supported.
495          */
496         iprint(" CR0 %8.8llux CR2 %16.16llux CR3 %16.16llux",
497                 getcr0(), getcr2(), getcr3());
498         if(m->cpuiddx & (Mce|Tsc|Pse|Vmex)){
499                 iprint(" CR4 %16.16llux\n", getcr4());
500                 if(ureg->type == 18)
501                         dumpmcregs();
502         }
503         iprint("  ur %#p up %#p\n", ureg, up);
504 }
505
506
507 /*
508  * Fill in enough of Ureg to get a stack trace, and call a function.
509  * Used by debugging interface rdb.
510  */
511 void
512 callwithureg(void (*fn)(Ureg*))
513 {
514         Ureg ureg;
515         ureg.pc = getcallerpc(&fn);
516         ureg.sp = (uintptr)&fn;
517         fn(&ureg);
518 }
519
520 static void
521 _dumpstack(Ureg *ureg)
522 {
523         uintptr l, v, i, estack;
524         extern ulong etext;
525         int x;
526         char *s;
527
528         if((s = getconf("*nodumpstack")) != nil && strcmp(s, "0") != 0){
529                 iprint("dumpstack disabled\n");
530                 return;
531         }
532         iprint("dumpstack\n");
533
534         x = 0;
535         x += iprint("ktrace /kernel/path %#p %#p <<EOF\n", ureg->pc, ureg->sp);
536         i = 0;
537         if(up
538         && (uintptr)&l >= (uintptr)up->kstack
539         && (uintptr)&l <= (uintptr)up->kstack+KSTACK)
540                 estack = (uintptr)up->kstack+KSTACK;
541         else if((uintptr)&l >= (uintptr)m->stack
542         && (uintptr)&l <= (uintptr)m+MACHSIZE)
543                 estack = (uintptr)m+MACHSIZE;
544         else
545                 return;
546         x += iprint("estackx %p\n", estack);
547
548         for(l = (uintptr)&l; l < estack; l += sizeof(uintptr)){
549                 v = *(uintptr*)l;
550                 if((KTZERO < v && v < (uintptr)&etext) || estack-l < 32){
551                         /*
552                          * Could Pick off general CALL (((uchar*)v)[-5] == 0xE8)
553                          * and CALL indirect through AX
554                          * (((uchar*)v)[-2] == 0xFF && ((uchar*)v)[-2] == 0xD0),
555                          * but this is too clever and misses faulting address.
556                          */
557                         x += iprint("%.8lux=%.8lux ", (ulong)l, (ulong)v);
558                         i++;
559                 }
560                 if(i == 4){
561                         i = 0;
562                         x += iprint("\n");
563                 }
564         }
565         if(i)
566                 iprint("\n");
567         iprint("EOF\n");
568
569         if(ureg->type != VectorNMI)
570                 return;
571
572         i = 0;
573         for(l = (uintptr)&l; l < estack; l += sizeof(uintptr)){
574                 iprint("%.8p ", *(uintptr*)l);
575                 if(++i == 8){
576                         i = 0;
577                         iprint("\n");
578                 }
579         }
580         if(i)
581                 iprint("\n");
582 }
583
584 void
585 dumpstack(void)
586 {
587         callwithureg(_dumpstack);
588 }
589
590 static void
591 debugbpt(Ureg* ureg, void*)
592 {
593         char buf[ERRMAX];
594
595         if(up == 0)
596                 panic("kernel bpt");
597         /* restore pc to instruction that caused the trap */
598         ureg->pc--;
599         sprint(buf, "sys: breakpoint");
600         postnote(up, 1, buf, NDebug);
601 }
602
603 static void
604 doublefault(Ureg*, void*)
605 {
606         panic("double fault");
607 }
608
609 static void
610 unexpected(Ureg* ureg, void*)
611 {
612         print("unexpected trap %llud; ignoring\n", ureg->type);
613 }
614
615 extern void checkpages(void);
616 static void
617 faultamd64(Ureg* ureg, void*)
618 {
619         uintptr addr;
620         int read, user, n, insyscall;
621         char buf[ERRMAX];
622
623         addr = getcr2();
624         read = !(ureg->error & 2);
625         user = userureg(ureg);
626         if(!user){
627                 if(addr >= USTKTOP)
628                         panic("kernel fault: bad address pc=%#p addr=%#p", ureg->pc, addr);
629                 if(up == nil)
630                         panic("kernel fault: no user process pc=%#p addr=%#p", ureg->pc, addr);
631         }
632         if(up == nil)
633                 panic("user fault: up=0 pc=%#p addr=%#p", ureg->pc, addr);
634
635         insyscall = up->insyscall;
636         up->insyscall = 1;
637         n = fault(addr, read);
638         if(n < 0){
639                 if(!user){
640                         dumpregs(ureg);
641                         panic("fault: %#p", addr);
642                 }
643                 checkpages();
644                 sprint(buf, "sys: trap: fault %s addr=%#p",
645                         read ? "read" : "write", addr);
646                 postnote(up, 1, buf, NDebug);
647         }
648         up->insyscall = insyscall;
649 }
650
651 /*
652  *  system calls
653  */
654 #include "../port/systab.h"
655
656 /*
657  *  Syscall is called directly from assembler without going through trap().
658  */
659 void
660 syscall(Ureg* ureg)
661 {
662         char *e;
663         uintptr sp;
664         long long ret;
665         int     i, s;
666         ulong scallnr;
667         vlong startns, stopns;
668
669         if(!userureg(ureg))
670                 panic("syscall: cs 0x%4.4lluX", ureg->cs);
671
672         cycles(&up->kentry);
673
674         m->syscall++;
675         up->insyscall = 1;
676         up->pc = ureg->pc;
677         up->dbgreg = ureg;
678
679         sp = ureg->sp;
680         scallnr = ureg->bp;     /* RARG */
681         up->scallnr = scallnr;
682
683         spllo();
684         startns = 0;
685         up->nerrlab = 0;
686         ret = -1;
687         if(!waserror()){
688                 if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-sizeof(Sargs)-BY2WD))
689                         validaddr(sp, sizeof(Sargs)+BY2WD, 0);
690
691                 up->s = *((Sargs*)(sp+BY2WD));
692                 if(0){
693                         syscallfmt(scallnr, ureg->pc, (va_list)up->s.args);
694                         print("syscall: %s\n", up->syscalltrace);
695                 }
696
697                 if(up->procctl == Proc_tracesyscall){
698                         syscallfmt(scallnr, ureg->pc, (va_list)up->s.args);
699                         s = splhi();
700                         up->procctl = Proc_stopme;
701                         procctl();
702                         splx(s);
703                         startns = todget(nil);
704                 }
705                 if(scallnr >= nsyscall || systab[scallnr] == 0){
706                         pprint("bad sys call number %lud pc %#p\n",
707                                 scallnr, ureg->pc);
708                         postnote(up, 1, "sys: bad sys call", NDebug);
709                         error(Ebadarg);
710                 }
711                 up->psstate = sysctab[scallnr];
712                 ret = systab[scallnr]((va_list)up->s.args);
713                 poperror();
714         }else{
715                 /* failure: save the error buffer for errstr */
716                 e = up->syserrstr;
717                 up->syserrstr = up->errstr;
718                 up->errstr = e;
719                 if(0 && up->pid == 1)
720                         print("syscall %lud error %s\n", scallnr, up->syserrstr);
721         }
722         if(up->nerrlab){
723                 print("bad errstack [%lud]: %d extra\n", scallnr, up->nerrlab);
724                 for(i = 0; i < NERR; i++)
725                         print("sp=%#p pc=%#p\n",
726                                 up->errlab[i].sp, up->errlab[i].pc);
727                 panic("error stack");
728         }
729         ureg->ax = ret;
730
731         if(0){
732                 print("syscallret: %lud %s %s ret=%lld\n", 
733                         up->pid, up->text, sysctab[scallnr], ret);
734         }
735
736         if(up->procctl == Proc_tracesyscall){
737                 stopns = todget(nil);
738                 sysretfmt(scallnr, (va_list)up->s.args, ret, startns, stopns);
739                 s = splhi();
740                 up->procctl = Proc_stopme;
741                 procctl();
742                 splx(s);
743         }
744
745         up->insyscall = 0;
746         up->psstate = 0;
747
748         if(scallnr == NOTED){
749                 noted(ureg, *((ulong*)up->s.args));
750
751                 /*
752                  * normally, syscall() returns to forkret()
753                  * not restoring general registers when going
754                  * to userspace. to completely restore the
755                  * interrupted context, we have to return thru
756                  * noteret(). we override return pc to jump to
757                  * to it when returning form syscall()
758                  */
759                 ((void**)&ureg)[-1] = (void*)noteret;
760         }
761
762         if(scallnr!=RFORK && (up->procctl || up->nnote)){
763                 splhi();
764                 notify(ureg);
765                 ((void**)&ureg)[-1] = (void*)noteret;   /* loads RARG */
766         }
767         /* if we delayed sched because we held a lock, sched now */
768         if(up->delaysched)
769                 sched();
770         kexit(ureg);
771 }
772
773 /*
774  *  Call user, if necessary, with note.
775  *  Pass user the Ureg struct and the note on his stack.
776  */
777 int
778 notify(Ureg* ureg)
779 {
780         int l, s;
781         uintptr sp;
782         Note *n;
783
784         if(up->procctl)
785                 procctl();
786         if(up->nnote == 0)
787                 return 0;
788
789         if(up->fpstate == FPactive){
790                 fpsave(&up->fpsave);
791                 up->fpstate = FPinactive;
792         }
793         up->fpstate |= FPillegal;
794
795         s = spllo();
796         qlock(&up->debug);
797         up->notepending = 0;
798         n = &up->note[0];
799         if(strncmp(n->msg, "sys:", 4) == 0){
800                 l = strlen(n->msg);
801                 if(l > ERRMAX-15)       /* " pc=0x12345678\0" */
802                         l = ERRMAX-15;
803                 sprint(n->msg+l, " pc=%#p", ureg->pc);
804         }
805
806         if(n->flag!=NUser && (up->notified || up->notify==0)){
807                 qunlock(&up->debug);
808                 if(n->flag == NDebug)
809                         pprint("suicide: %s\n", n->msg);
810                 pexit(n->msg, n->flag!=NDebug);
811         }
812
813         if(up->notified){
814                 qunlock(&up->debug);
815                 splhi();
816                 return 0;
817         }
818
819         if(!up->notify){
820                 qunlock(&up->debug);
821                 pexit(n->msg, n->flag!=NDebug);
822         }
823         sp = ureg->sp;
824         sp -= 256;      /* debugging: preserve context causing problem */
825         sp -= sizeof(Ureg);
826 if(0) print("%s %lud: notify %#p %#p %#p %s\n",
827         up->text, up->pid, ureg->pc, ureg->sp, sp, n->msg);
828
829         if(!okaddr((uintptr)up->notify, 1, 0)
830         || !okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1)){
831                 qunlock(&up->debug);
832                 pprint("suicide: bad address in notify\n");
833                 pexit("Suicide", 0);
834         }
835
836         memmove((Ureg*)sp, ureg, sizeof(Ureg));
837         *(Ureg**)(sp-BY2WD) = up->ureg; /* word under Ureg is old up->ureg */
838         up->ureg = (void*)sp;
839         sp -= BY2WD+ERRMAX;
840         memmove((char*)sp, up->note[0].msg, ERRMAX);
841         sp -= 3*BY2WD;
842         ((uintptr*)sp)[2] = sp + 3*BY2WD;       /* arg2 string */
843         ((uintptr*)sp)[1] = (uintptr)up->ureg;  /* arg1 is ureg* */
844         ((uintptr*)sp)[0] = 0;                  /* arg0 is pc */
845         ureg->sp = sp;
846         ureg->pc = (uintptr)up->notify;
847         ureg->bp = (uintptr)up->ureg;           /* arg1 passed in RARG */
848         ureg->cs = UESEL;
849         ureg->ss = UDSEL;
850         up->notified = 1;
851         up->nnote--;
852         memmove(&up->lastnote, &up->note[0], sizeof(Note));
853         memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note));
854
855         qunlock(&up->debug);
856         splx(s);
857         return 1;
858
859 }
860
861 /*
862  *   Return user to state before notify()
863  */
864 void
865 noted(Ureg* ureg, ulong arg0)
866 {
867         Ureg *nureg;
868         uintptr oureg, sp;
869
870         qlock(&up->debug);
871         if(arg0!=NRSTR && !up->notified) {
872                 qunlock(&up->debug);
873                 pprint("call to noted() when not notified\n");
874                 pexit("Suicide", 0);
875         }
876         up->notified = 0;
877
878         nureg = up->ureg;       /* pointer to user returned Ureg struct */
879
880         up->fpstate &= ~FPillegal;
881
882         /* sanity clause */
883         oureg = (uintptr)nureg;
884         if(!okaddr(oureg-BY2WD, BY2WD+sizeof(Ureg), 0)){
885                 qunlock(&up->debug);
886                 pprint("bad ureg in noted or call to noted when not notified\n");
887                 pexit("Suicide", 0);
888         }
889
890         /* don't let user change system flags or segment registers */
891         setregisters(ureg, (char*)ureg, (char*)nureg, sizeof(Ureg));
892
893         switch(arg0){
894         case NCONT:
895         case NRSTR:
896 if(0) print("%s %lud: noted %#p %#p\n",
897         up->text, up->pid, nureg->pc, nureg->sp);
898                 if(!okaddr(nureg->pc, 1, 0) || !okaddr(nureg->sp, BY2WD, 0)){
899                         qunlock(&up->debug);
900                         pprint("suicide: trap in noted\n");
901                         pexit("Suicide", 0);
902                 }
903                 up->ureg = (Ureg*)(*(uintptr*)(oureg-BY2WD));
904                 qunlock(&up->debug);
905                 break;
906
907         case NSAVE:
908                 if(!okaddr(nureg->pc, 1, 0)
909                 || !okaddr(nureg->sp, BY2WD, 0)){
910                         qunlock(&up->debug);
911                         pprint("suicide: trap in noted\n");
912                         pexit("Suicide", 0);
913                 }
914                 qunlock(&up->debug);
915                 sp = oureg-4*BY2WD-ERRMAX;
916                 splhi();
917                 ureg->sp = sp;
918                 ureg->bp = oureg;               /* arg 1 passed in RARG */
919                 ((uintptr*)sp)[1] = oureg;      /* arg 1 0(FP) is ureg* */
920                 ((uintptr*)sp)[0] = 0;          /* arg 0 is pc */
921                 break;
922
923         default:
924                 up->lastnote.flag = NDebug;
925                 /* fall through */
926
927         case NDFLT:
928                 qunlock(&up->debug);
929                 if(up->lastnote.flag == NDebug)
930                         pprint("suicide: %s\n", up->lastnote.msg);
931                 pexit(up->lastnote.msg, up->lastnote.flag!=NDebug);
932         }
933 }
934
935 uintptr
936 execregs(uintptr entry, ulong ssize, ulong nargs)
937 {
938         uintptr *sp;
939         Ureg *ureg;
940
941         sp = (uintptr*)(USTKTOP - ssize);
942         *--sp = nargs;
943         ureg = up->dbgreg;
944         ureg->sp = (uintptr)sp;
945         ureg->pc = entry;
946         ureg->cs = UESEL;
947         ureg->ss = UDSEL;
948         ureg->r14 = ureg->r15 = 0;      /* extern user registers */
949         return (uintptr)USTKTOP-sizeof(Tos);            /* address of kernel/user shared data */
950 }
951
952 /*
953  *  return the userpc the last exception happened at
954  */
955 uintptr
956 userpc(void)
957 {
958         Ureg *ureg;
959
960         ureg = (Ureg*)up->dbgreg;
961         return ureg->pc;
962 }
963
964 /* This routine must save the values of registers the user is not permitted
965  * to write from devproc and noted() and then restore the saved values before returning.
966  */
967 void
968 setregisters(Ureg* ureg, char* pureg, char* uva, int n)
969 {
970         u64int flags;
971
972         flags = ureg->flags;
973         memmove(pureg, uva, n);
974         ureg->cs = UESEL;
975         ureg->ss = UDSEL;
976         ureg->flags = (ureg->flags & 0x00ff) | (flags & 0xff00);
977         ureg->pc &= UADDRMASK;
978 }
979
980 static void
981 linkproc(void)
982 {
983         spllo();
984         up->kpfun(up->kparg);
985         pexit("kproc dying", 0);
986 }
987
988 void
989 kprocchild(Proc* p, void (*func)(void*), void* arg)
990 {
991         /*
992          * gotolabel() needs a word on the stack in
993          * which to place the return PC used to jump
994          * to linkproc().
995          */
996         p->sched.pc = (uintptr)linkproc;
997         p->sched.sp = (uintptr)p->kstack+KSTACK-BY2WD;
998
999         p->kpfun = func;
1000         p->kparg = arg;
1001 }
1002
1003 void
1004 forkchild(Proc *p, Ureg *ureg)
1005 {
1006         Ureg *cureg;
1007
1008         /*
1009          * Add 2*BY2WD to the stack to account for
1010          *  - the return PC
1011          *  - trap's argument (ur)
1012          */
1013         p->sched.sp = (uintptr)p->kstack+KSTACK-(sizeof(Ureg)+2*BY2WD);
1014         p->sched.pc = (uintptr)forkret;
1015
1016         cureg = (Ureg*)(p->sched.sp+2*BY2WD);
1017         memmove(cureg, ureg, sizeof(Ureg));
1018
1019         cureg->ax = 0;
1020
1021         /* Things from bottom of syscall which were never executed */
1022         p->psstate = 0;
1023         p->insyscall = 0;
1024 }
1025
1026 /* Give enough context in the ureg to produce a kernel stack for
1027  * a sleeping process
1028  */
1029 void
1030 setkernur(Ureg* ureg, Proc* p)
1031 {
1032         ureg->pc = p->sched.pc;
1033         ureg->sp = p->sched.sp+8;
1034         ureg->r14 = (uintptr)p;
1035 }
1036
1037 uintptr
1038 dbgpc(Proc *p)
1039 {
1040         Ureg *ureg;
1041
1042         ureg = p->dbgreg;
1043         if(ureg == nil)
1044                 return 0;
1045         return ureg->pc;
1046 }