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