1 #include "u.h"
2 #include "../port/lib.h"
3 #include "mem.h"
4 #include "dat.h"
5 #include "fns.h"
6 #include "ureg.h"
7 #include "../port/error.h"
8 #include "tos.h"
9 #include <trace.h>
10
11 static Lock vctllock;
12 Vctl *vctl[256];
13
14 int intrstack[5];
15 uvlong intrtime[5];
16 vlong lastoffset;
17 int inintr;
18 int nintr[10];
19 int nintro;
20 int dblintr[64];
21 ulong thisto[32];
22 ulong thistoo;
23 vlong vnot[64];
24 ulong vnon[64];
25
26 void
intrenable(int irq,void (* f)(Ureg *,void *),void * a,char * name)27 intrenable(int irq, void (*f)(Ureg*, void*), void* a, char *name)
28 {
29 int vno;
30 Vctl *v;
31
32 if(f == nil){
33 print("intrenable: nil handler for %d for %s\n",
34 irq, name);
35 return;
36 }
37
38 v = xalloc(sizeof(Vctl));
39 v->isintr = 1;
40 v->irq = irq;
41 v->f = f;
42 v->a = a;
43 strncpy(v->name, name, KNAMELEN-1);
44 v->name[KNAMELEN-1] = 0;
45
46 ilock(&vctllock);
47 vno = vectorenable(v);
48 if(vno == -1){
49 iunlock(&vctllock);
50 print("intrenable: couldn't enable irq %d for %s\n",
51 irq, v->name);
52 xfree(v);
53 return;
54 }
55 v->next = vctl[vno];
56 vctl[vno] = v;
57 iunlock(&vctllock);
58 }
59
60 void
intrdisable(int irq,void (* f)(Ureg *,void *),void * a,char * name)61 intrdisable(int irq, void (*f)(Ureg *, void *), void *a, char *name)
62 {
63 Vctl **pv, *v;
64
65 ilock(&vctllock);
66 pv = &vctl[irq];
67 while (*pv &&
68 ((*pv)->irq != irq || (*pv)->f != f || (*pv)->a != a ||
69 strcmp((*pv)->name, name)))
70 pv = &((*pv)->next);
71
72 if(*pv == nil){
73 print("intrdisable: irq %d not found\n", irq);
74 iunlock(&vctllock);
75 return;
76 }
77
78 v = *pv;
79 *pv = (*pv)->next; /* Link out the entry */
80
81 if(vctl[irq] == nil)
82 vectordisable(v);
83 iunlock(&vctllock);
84 xfree(v);
85 }
86
87 void syscall(Ureg*);
88 void noted(Ureg*, ulong);
89 static void _dumpstack(Ureg*);
90
91 char *excname[] =
92 {
93 "reserved 0",
94 "system reset",
95 "machine check",
96 "data access",
97 "instruction access",
98 "external interrupt",
99 "alignment",
100 "program exception",
101 "floating-point unavailable",
102 "decrementer",
103 "reserved A",
104 "reserved B",
105 "system call",
106 "trace trap",
107 "floating point assist",
108 "reserved F",
109 "reserved 10",
110 "data load translation miss",
111 "data store translation miss",
112 "instruction address breakpoint",
113 "system management interrupt",
114 };
115
116 char *fpcause[] =
117 {
118 "inexact operation",
119 "division by zero",
120 "underflow",
121 "overflow",
122 "invalid operation",
123 };
124 char *fpexcname(Ureg*, ulong, char*);
125 #define FPEXPMASK 0xfff80300 /* Floating exception bits in fpscr */
126
127
128 char *regname[]={
129 "CAUSE", "SRR1",
130 "PC", "GOK",
131 "LR", "CR",
132 "XER", "CTR",
133 "R0", "R1",
134 "R2", "R3",
135 "R4", "R5",
136 "R6", "R7",
137 "R8", "R9",
138 "R10", "R11",
139 "R12", "R13",
140 "R14", "R15",
141 "R16", "R17",
142 "R18", "R19",
143 "R20", "R21",
144 "R22", "R23",
145 "R24", "R25",
146 "R26", "R27",
147 "R28", "R29",
148 "R30", "R31",
149 "DCMP", "ICMP",
150 "DMISS", "IMISS",
151 "HASH1", "HASH2",
152 "DAR", "DSISR",
153 };
154
155 void
kexit(Ureg *)156 kexit(Ureg*)
157 {
158 uvlong t;
159 Tos *tos;
160
161 /* precise time accounting, kernel exit */
162 tos = (Tos*)(USTKTOP-sizeof(Tos));
163 cycles(&t);
164 tos->kcycles += t - up->kentry;
165 tos->pcycles = up->pcycles;
166 tos->pid = up->pid;
167 }
168
169 void
trap(Ureg * ureg)170 trap(Ureg *ureg)
171 {
172 int ecode, user;
173 char buf[ERRMAX], *s;
174 extern FPsave initfp;
175
176 ecode = (ureg->cause >> 8) & 0xff;
177 user = (ureg->srr1 & MSR_PR) != 0;
178 if(user){
179 cycles(&up->kentry);
180 up->dbgreg = ureg;
181 }
182 if(ureg->status & MSR_RI == 0)
183 print("double fault?: ecode = %d\n", ecode);
184
185 switch(ecode) {
186 case CEI:
187 m->intr++;
188 intr(ureg);
189 break;
190 case CDEC:
191 clockintr(ureg);
192 break;
193 case CDSI:
194 m->pfault++;
195 if (up == nil){
196 dumpregs(ureg);
197 panic("kernel fault");
198 }
199 up->mmureg = ureg;
200 faultpower(ureg, ureg->dar, (ureg->dsisr & BIT(6)) == 0);
201 break;
202 case CISI:
203 m->pfault++;
204 if (up == nil){
205 dumpregs(ureg);
206 panic("kernel fault");
207 }
208 up->mmureg = ureg;
209 faultpower(ureg, ureg->pc, 1);
210 break;
211 case CIMISS: /* instruction miss */
212 if (up == nil){
213 dumpregs(ureg);
214 panic("kernel fault");
215 }
216 up->mmureg = ureg;
217 faultpower(ureg, ureg->imiss, 1);
218 break;
219 case CLMISS: /* data load miss */
220 if (up == nil){
221 dumpregs(ureg);
222 panic("kernel fault");
223 }
224 up->mmureg = ureg;
225 faultpower(ureg, ureg->dmiss, 1);
226 break;
227 case CSMISS: /* data store miss */
228 if (up == nil){
229 dumpregs(ureg);
230 panic("kernel fault");
231 }
232 up->mmureg = ureg;
233 faultpower(ureg, ureg->dmiss, 0);
234 break;
235
236 case CSYSCALL:
237 if(!user)
238 panic("syscall in kernel: srr1 0x%4.4luX\n", ureg->srr1);
239 syscall(ureg);
240 if (up->delaysched){
241 sched();
242 splhi();
243 }
244 kexit(ureg);
245 return; /* syscall() calls notify itself, don't do it again */
246
247 case CFPU:
248 if(!user || up == nil) {
249 dumpregs(ureg);
250 panic("floating point in kernel");
251 }
252 switch(up->fpstate){
253 case FPinit:
254 fprestore(&initfp);
255 up->fpstate = FPactive;
256 break;
257 case FPinactive:
258 fprestore(&up->fpsave);
259 up->fpstate = FPactive;
260 break;
261 case FPactive:
262 print("up->fpstate %d\n", up->fpstate);
263 delay(100);
264 dumpregs(ureg);
265 delay(200);
266 panic("fpstate");
267 break;
268 default:
269 if(user){
270 spllo();
271 sprint(buf, "sys: floating point in note handler:");
272 postnote(up, 1, buf, NDebug);
273 break;
274 }
275 panic("kernel fpstate illegal");
276 }
277 ureg->srr1 |= MSR_FP;
278 break;
279 case CPROG:
280 if(ureg->status & (1<<19))
281 s = "floating point exception";
282 else if(ureg->status & (1<<18))
283 s = "illegal instruction";
284 else if(ureg->status & (1<<17))
285 s = "privileged instruction";
286 else
287 s = "undefined program exception";
288 if(user){
289 spllo();
290 sprint(buf, "sys: trap: %s", s);
291 postnote(up, 1, buf, NDebug);
292 break;
293 }
294 dumpregs(ureg);
295 panic(s);
296 break;
297 default:
298 if(ecode < nelem(excname) && user){
299 spllo();
300 sprint(buf, "sys: trap: %s", excname[ecode]);
301 postnote(up, 1, buf, NDebug);
302 break;
303 }
304 dumpregs(ureg);
305 if(ecode < nelem(excname))
306 panic("%s", excname[ecode]);
307 panic("unknown trap/intr: %d\n", ecode);
308 }
309
310 /* restoreureg must execute at high IPL */
311 splhi();
312
313 /* delaysched set because we held a lock or because our quantum ended */
314 if(up && up->delaysched && ecode == CDEC){
315 sched();
316 splhi();
317 }
318
319 if(user) {
320 if (up->fpstate == FPactive && (ureg->srr1 & MSR_FP) == 0){
321 postnote(up, 1, buf, NDebug);
322 }
323 notify(ureg);
324 if(up->fpstate != FPactive)
325 ureg->srr1 &= ~MSR_FP;
326 kexit(ureg);
327 }
328 }
329
330 void
faultpower(Ureg * ureg,ulong addr,int read)331 faultpower(Ureg *ureg, ulong addr, int read)
332 {
333 int user, insyscall, n;
334 char buf[ERRMAX];
335
336 user = (ureg->srr1 & MSR_PR) != 0;
337 insyscall = up->insyscall;
338 up->insyscall = 1;
339 n = fault(addr, read);
340 if(n < 0){
341 if(!user){
342 dumpregs(ureg);
343 panic("fault: 0x%lux", addr);
344 }
345 sprint(buf, "sys: trap: fault %s addr=0x%lux", read? "read" : "write", addr);
346 postnote(up, 1, buf, NDebug);
347 }
348 up->insyscall = insyscall;
349 }
350
351 void
sethvec(int v,void (* r)(void))352 sethvec(int v, void (*r)(void))
353 {
354 ulong *vp, pa, o;
355
356 vp = KADDR(v);
357 vp[0] = 0x7c1043a6; /* MOVW R0, SPR(SPRG0) */
358 vp[1] = 0x7c0802a6; /* MOVW LR, R0 */
359 vp[2] = 0x7c1243a6; /* MOVW R0, SPR(SPRG2) */
360 pa = PADDR(r);
361 o = pa >> 25;
362 if(o != 0 && o != 0x7F){
363 /* a branch too far */
364 vp[3] = (15<<26)|(pa>>16); /* MOVW $r&~0xFFFF, R0 */
365 vp[4] = (24<<26)|(pa&0xFFFF); /* OR $r&0xFFFF, R0 */
366 vp[5] = 0x7c0803a6; /* MOVW R0, LR */
367 vp[6] = 0x4e800021; /* BL (LR) */
368 }else
369 vp[3] = (18<<26)|(pa&0x3FFFFFC)|3; /* bla */
370 }
371
372 void
setmvec(int v,void (* r)(void),void (* t)(void))373 setmvec(int v, void (*r)(void), void (*t)(void))
374 {
375 ulong *vp, pa, o, n;
376
377 vp = KADDR(v);
378 n = 0;
379 vp[n++] = 0x7c1043a6; /* MOVW R0, SPR(SPRG0) */
380 vp[n++] = 0x7c0802a6; /* MOVW LR, R0 */
381 vp[n++] = 0x7c1243a6; /* MOVW R0, SPR(SPRG2) */
382 pa = PADDR(r);
383 o = pa >> 25;
384 if(o != 0 && o != 0x7F){
385 /* a branch too far */
386 vp[n++] = (15<<26)|(pa>>16); /* MOVW $r&~0xFFFF, R0 */
387 vp[n++] = (24<<26)|(pa&0xFFFF); /* OR $r&0xFFFF, R0 */
388 vp[n++] = 0x7c0803a6; /* MOVW R0, LR */
389 vp[n++] = 0x4e800021; /* BL (LR) */
390 }else
391 vp[n++] = (18<<26)|(pa&0x3FFFFFC)|3; /* bla */
392 pa = PADDR(t);
393 o = pa >> 25;
394 if(o != 0 && o != 0x7F){
395 /* a branch too far */
396 vp[n++] = (15<<26)|(pa>>16); /* MOVW $r&~0xFFFF, R0 */
397 vp[n++] = (24<<26)|(pa&0xFFFF); /* OR $r&0xFFFF, R0 */
398 vp[n++] = 0x7c0803a6; /* MOVW R0, LR */
399 vp[n] = 0x4e800021; /* BL (LR) */
400 }else
401 vp[n] = (18<<26)|(pa&0x3FFFFFC)|3; /* bla */
402 }
403
404
405 void
intr(Ureg * ureg)406 intr(Ureg *ureg)
407 {
408 int vno, pvno, i;
409 Vctl *ctl, *v;
410 void (*pt)(Proc*, int, vlong);
411 uvlong tt, x;
412
413 cycles(&tt);
414 pt = proctrace;
415 pvno = -1;
416 for(i = 0; i < 64; i++){
417 vno = intvec();
418 if(vno == 0)
419 break;
420 cycles(&x);
421 vnot[vno] -= x;
422 if(vno == pvno)
423 dblintr[vno]++;
424 pvno = vno;
425 if(pt && up && up->trace)
426 pt(up, (vno << 16) | SInts, 0);
427
428 if(vno > nelem(vctl) || (ctl = vctl[vno]) == 0) {
429 iprint("spurious intr %d\n", vno);
430 return;
431 }
432
433 for(v = ctl; v != nil; v = v->next)
434 if(v->f)
435 v->f(ureg, v->a);
436
437 intend(vno); /* reenable the interrupt */
438
439 if(pt && up && up->trace)
440 pt(up, (vno << 16) | SInte, 0);
441 cycles(&x);
442 vnot[vno] += x;
443 vnon[vno]++;
444 }
445 if(i < nelem(nintr))
446 nintr[i]++;
447 else
448 nintro++;
449 cycles(&x);
450 tt = x - tt;
451 i = tt / 3600; /* 100 microseconds units */
452 if(i < nelem(thisto))
453 thisto[i]++;
454 else
455 thistoo++;
456
457 if(up)
458 preempted();
459 }
460
461 char*
fpexcname(Ureg * ur,ulong fpscr,char * buf)462 fpexcname(Ureg *ur, ulong fpscr, char *buf)
463 {
464 int i;
465 char *s;
466 ulong fppc;
467
468 fppc = ur->pc;
469 s = 0;
470 fpscr >>= 3; /* trap enable bits */
471 fpscr &= (fpscr>>22); /* anded with exceptions */
472 for(i=0; i<5; i++)
473 if(fpscr & (1<<i))
474 s = fpcause[i];
475 if(s == 0)
476 return "no floating point exception";
477 sprint(buf, "%s fppc=0x%lux", s, fppc);
478 return buf;
479 }
480
481 /*
482 * Fill in enough of Ureg to get a stack trace, and call a function.
483 * Used by debugging interface rdb.
484 */
485
486 static void
getpcsp(ulong * pc,ulong * sp)487 getpcsp(ulong *pc, ulong *sp)
488 {
489 *pc = getcallerpc(&pc);
490 *sp = (ulong)&pc-4;
491 }
492
493 void
callwithureg(void (* fn)(Ureg *))494 callwithureg(void (*fn)(Ureg*))
495 {
496 Ureg ureg;
497
498 getpcsp((ulong*)&ureg.pc, (ulong*)&ureg.sp);
499 ureg.lr = getcallerpc(&fn);
500 fn(&ureg);
501 }
502
503 static void
_dumpstack(Ureg * ureg)504 _dumpstack(Ureg *ureg)
505 {
506 ulong l, sl, el, v;
507 int i;
508
509 l = (ulong)&l;
510 if(up == 0){
511 el = (ulong)m+BY2PG;
512 sl = el-KSTACK;
513 }
514 else{
515 sl = (ulong)up->kstack;
516 el = sl + KSTACK;
517 }
518 if(l > el || l < sl){
519 el = (ulong)m+BY2PG;
520 sl = el-KSTACK;
521 }
522 if(l > el || l < sl)
523 return;
524 print("ktrace /kernel/path %.8lux %.8lux %.8lux\n", ureg->pc, ureg->sp, ureg->lr);
525 i = 0;
526 for(; l < el; l += 4){
527 v = *(ulong*)l;
528 if(KTZERO < v && v < (ulong)etext){
529 print("%.8lux=%.8lux ", l, v);
530 if(i++ == 4){
531 print("\n");
532 i = 0;
533 }
534 }
535 }
536 }
537
538 void
dumpstack(void)539 dumpstack(void)
540 {
541 callwithureg(_dumpstack);
542 }
543
544 void
dumpregs(Ureg * ur)545 dumpregs(Ureg *ur)
546 {
547 int i;
548 ulong *l;
549
550 if(up) {
551 print("registers for %s %ld\n", up->text, up->pid);
552 if(ur->srr1 & MSR_PR == 0)
553 if(ur->usp < (ulong)up->kstack || ur->usp > (ulong)up->kstack+KSTACK)
554 print("invalid stack ptr\n");
555 }
556 else
557 print("registers for kernel\n");
558
559 for(i=0; i<16; i+=2)
560 print("sr[%x]\t0x%.8lux\tsr[%x]\t0x%.8lux\n", i, getsr(i<<28), i+1, getsr((i+1)<<28));
561 l = &ur->cause;
562 for(i=0; i<sizeof regname/sizeof(char*); i+=2, l+=2)
563 print("%s\t0x%.8lux\t%s\t0x%.8lux\n", regname[i], l[0], regname[i+1], l[1]);
564 delay(500);
565 }
566
567 static void
linkproc(void)568 linkproc(void)
569 {
570 spllo();
571 (*up->kpfun)(up->kparg);
572 pexit("", 0);
573 }
574
575 void
kprocchild(Proc * p,void (* func)(void *),void * arg)576 kprocchild(Proc *p, void (*func)(void*), void *arg)
577 {
578 p->sched.pc = (ulong)linkproc;
579 p->sched.sp = (ulong)p->kstack+KSTACK;
580
581 p->kpfun = func;
582 p->kparg = arg;
583 }
584
585 /*
586 * called in syscallfmt.c, sysfile.c, sysproc.c
587 */
588 void
validalign(uintptr addr,unsigned align)589 validalign(uintptr addr, unsigned align)
590 {
591 /*
592 * Plan 9 is a 32-bit O/S, and the hardware it runs on
593 * does not usually have instructions which move 64-bit
594 * quantities directly, synthesizing the operations
595 * with 32-bit move instructions. Therefore, the compiler
596 * (and hardware) usually only enforce 32-bit alignment,
597 * if at all.
598 *
599 * Take this out if the architecture warrants it.
600 */
601 if(align == sizeof(vlong))
602 align = sizeof(long);
603
604 /*
605 * Check align is a power of 2, then addr alignment.
606 */
607 if((align != 0 && !(align & (align-1))) && !(addr & (align-1)))
608 return;
609 postnote(up, 1, "sys: odd address", NDebug);
610 error(Ebadarg);
611 /*NOTREACHED*/
612 }
613
614 long
execregs(ulong entry,ulong ssize,ulong nargs)615 execregs(ulong entry, ulong ssize, ulong nargs)
616 {
617 ulong *sp;
618 Ureg *ureg;
619
620 sp = (ulong*)(USTKTOP - ssize);
621 *--sp = nargs;
622
623 ureg = up->dbgreg;
624 ureg->usp = (ulong)sp;
625 ureg->pc = entry;
626 ureg->srr1 &= ~MSR_FP; /* disable floating point */
627 up->fpstate = FPinit;
628 return USTKTOP-sizeof(Tos); /* address of kernel/user shared data */
629 }
630
631 void
forkchild(Proc * p,Ureg * ur)632 forkchild(Proc *p, Ureg *ur)
633 {
634 Ureg *cur;
635
636 p->sched.sp = (ulong)p->kstack+KSTACK-UREGSIZE;
637 p->sched.pc = (ulong)forkret;
638
639 cur = (Ureg*)(p->sched.sp+2*BY2WD);
640 memmove(cur, ur, sizeof(Ureg));
641 cur->r3 = 0;
642
643 /* Things from bottom of syscall we never got to execute */
644 p->psstate = 0;
645 p->insyscall = 0;
646 }
647
648 ulong
userpc(void)649 userpc(void)
650 {
651 Ureg *ureg;
652
653 ureg = (Ureg*)up->dbgreg;
654 return ureg->pc;
655 }
656
657
658 /* This routine must save the values of registers the user is not
659 * permitted to write from devproc and then restore the saved values
660 * before returning
661 */
662 void
setregisters(Ureg * xp,char * pureg,char * uva,int n)663 setregisters(Ureg *xp, char *pureg, char *uva, int n)
664 {
665 ulong status;
666
667 status = xp->status;
668 memmove(pureg, uva, n);
669 xp->status = status;
670 }
671
672 /* Give enough context in the ureg to produce a kernel stack for
673 * a sleeping process
674 */
675 void
setkernur(Ureg * ureg,Proc * p)676 setkernur(Ureg* ureg, Proc* p)
677 {
678 ureg->pc = p->sched.pc;
679 ureg->sp = p->sched.sp+4;
680 }
681
682 ulong
dbgpc(Proc * p)683 dbgpc(Proc *p)
684 {
685 Ureg *ureg;
686
687 ureg = p->dbgreg;
688 if(ureg == 0)
689 return 0;
690
691 return ureg->pc;
692 }
693
694 /*
695 * system calls
696 */
697 #include "../port/systab.h"
698
699 /* TODO: make this trap a separate asm entry point, like on other RISC architectures */
700 void
syscall(Ureg * ureg)701 syscall(Ureg* ureg)
702 {
703 int i;
704 char *e;
705 long ret;
706 ulong sp, scallnr;
707
708 m->syscall++;
709 up->insyscall = 1;
710 up->pc = ureg->pc;
711 up->dbgreg = ureg;
712
713 if (up->fpstate == FPactive && (ureg->srr1 & MSR_FP) == 0){
714 print("fpstate check, entry syscall\n");
715 delay(200);
716 dumpregs(ureg);
717 print("fpstate check, entry syscall\n");
718 }
719
720 scallnr = ureg->r3;
721 up->scallnr = ureg->r3;
722 if(scallnr == RFORK && up->fpstate == FPactive){
723 fpsave(&up->fpsave);
724 up->fpstate = FPinactive;
725 }
726 spllo();
727
728 sp = ureg->usp;
729 up->nerrlab = 0;
730 ret = -1;
731 if(!waserror()){
732 if(scallnr >= nsyscall || systab[scallnr] == nil){
733 pprint("bad sys call number %ld pc %lux\n", scallnr, ureg->pc);
734 postnote(up, 1, "sys: bad sys call", NDebug);
735 error(Ebadarg);
736 }
737
738 if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-sizeof(Sargs)-BY2WD))
739 validaddr(sp, sizeof(Sargs)+BY2WD, 0);
740
741 up->s = *((Sargs*)(sp+BY2WD));
742 up->psstate = sysctab[scallnr];
743
744 ret = systab[scallnr](up->s.args);
745 poperror();
746 }else{
747 /* failure: save the error buffer for errstr */
748 e = up->syserrstr;
749 up->syserrstr = up->errstr;
750 up->errstr = e;
751 }
752 if(up->nerrlab){
753 print("bad errstack [%uld]: %d extra\n", scallnr, up->nerrlab);
754 print("scall %s lr =%lux\n", sysctab[scallnr], ureg->lr);
755 for(i = 0; i < NERR; i++)
756 print("sp=%lux pc=%lux\n", up->errlab[i].sp, up->errlab[i].pc);
757 panic("error stack");
758 }
759
760 up->insyscall = 0;
761 up->psstate = 0;
762
763 /*
764 * Put return value in frame. On the x86 the syscall is
765 * just another trap and the return value from syscall is
766 * ignored. On other machines the return value is put into
767 * the results register by caller of syscall.
768 */
769 ureg->r3 = ret;
770
771 if(scallnr == NOTED)
772 noted(ureg, *(ulong*)(sp+BY2WD));
773
774 /* restoreureg must execute at high IPL */
775 splhi();
776 if(scallnr!=RFORK)
777 notify(ureg);
778
779 if (up->fpstate == FPactive && (ureg->srr1 & MSR_FP) == 0){
780 print("fpstate check, exit syscall nr %lud, pid %lud\n", scallnr, up->pid);
781 dumpregs(ureg);
782 }
783 if(up->fpstate != FPactive)
784 ureg->srr1 &= ~MSR_FP;
785 }
786
787 /*
788 * Call user, if necessary, with note.
789 * Pass user the Ureg struct and the note on his stack.
790 */
791 int
notify(Ureg * ur)792 notify(Ureg* ur)
793 {
794 int l;
795 ulong s, sp;
796 Note *n;
797
798 if(up->procctl)
799 procctl(up);
800 if(up->nnote == 0)
801 return 0;
802
803 s = spllo();
804 qlock(&up->debug);
805 up->notepending = 0;
806 n = &up->note[0];
807 if(strncmp(n->msg, "sys:", 4) == 0){
808 l = strlen(n->msg);
809 if(l > ERRMAX-15) /* " pc=0x12345678\0" */
810 l = ERRMAX-15;
811 sprint(n->msg+l, " pc=0x%.8lux", ur->pc);
812 }
813
814 if(n->flag!=NUser && (up->notified || up->notify==0)){
815 if(n->flag == NDebug)
816 pprint("suicide: %s\n", n->msg);
817 qunlock(&up->debug);
818 pexit(n->msg, n->flag!=NDebug);
819 }
820
821 if(up->notified) {
822 qunlock(&up->debug);
823 splhi();
824 return 0;
825 }
826
827 if(!up->notify) {
828 qunlock(&up->debug);
829 pexit(n->msg, n->flag!=NDebug);
830 }
831
832 if(up->fpstate == FPactive){
833 fpsave(&up->fpsave);
834 up->fpstate = FPinactive;
835 }
836 up->fpstate |= FPillegal;
837
838 sp = ur->usp & ~(BY2V-1);
839 sp -= sizeof(Ureg);
840
841 if(!okaddr((ulong)up->notify, BY2WD, 0) ||
842 !okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1)) {
843 pprint("suicide: bad address or sp in notify\n");
844 qunlock(&up->debug);
845 pexit("Suicide", 0);
846 }
847
848 memmove((Ureg*)sp, ur, sizeof(Ureg));
849 *(Ureg**)(sp-BY2WD) = up->ureg; /* word under Ureg is old up->ureg */
850 up->ureg = (void*)sp;
851 sp -= BY2WD+ERRMAX;
852 memmove((char*)sp, up->note[0].msg, ERRMAX);
853 sp -= 3*BY2WD;
854 *(ulong*)(sp+2*BY2WD) = sp+3*BY2WD; /* arg 2 is string */
855 ur->r1 = (long)up->ureg; /* arg 1 is ureg* */
856 ((ulong*)sp)[1] = (ulong)up->ureg; /* arg 1 0(FP) is ureg* */
857 ((ulong*)sp)[0] = 0; /* arg 0 is pc */
858 ur->usp = sp;
859 ur->pc = (ulong)up->notify;
860 up->notified = 1;
861 up->nnote--;
862 memmove(&up->lastnote, &up->note[0], sizeof(Note));
863 memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note));
864
865 qunlock(&up->debug);
866 splx(s);
867 return 1;
868 }
869
870
871 /*
872 * Return user to state before notify()
873 */
874 void
noted(Ureg * ureg,ulong arg0)875 noted(Ureg* ureg, ulong arg0)
876 {
877 Ureg *nureg;
878 ulong oureg, sp;
879
880 qlock(&up->debug);
881 if(arg0!=NRSTR && !up->notified) {
882 qunlock(&up->debug);
883 pprint("call to noted() when not notified\n");
884 pexit("Suicide", 0);
885 }
886 up->notified = 0;
887
888 nureg = up->ureg; /* pointer to user returned Ureg struct */
889
890 /* sanity clause */
891 oureg = (ulong)nureg;
892 if(!okaddr((ulong)oureg-BY2WD, BY2WD+sizeof(Ureg), 0)){
893 pprint("bad ureg in noted or call to noted when not notified\n");
894 qunlock(&up->debug);
895 pexit("Suicide", 0);
896 }
897
898 memmove(ureg, nureg, sizeof(Ureg));
899
900 switch(arg0){
901 case NCONT:
902 case NRSTR:
903 if(!okaddr(nureg->pc, 1, 0) || !okaddr(nureg->usp, BY2WD, 0)){
904 pprint("suicide: trap in noted\n");
905 qunlock(&up->debug);
906 pexit("Suicide", 0);
907 }
908 up->ureg = (Ureg*)(*(ulong*)(oureg-BY2WD));
909 qunlock(&up->debug);
910 break;
911
912 case NSAVE:
913 if(!okaddr(nureg->pc, BY2WD, 0)
914 || !okaddr(nureg->usp, BY2WD, 0)){
915 pprint("suicide: trap in noted\n");
916 qunlock(&up->debug);
917 pexit("Suicide", 0);
918 }
919 qunlock(&up->debug);
920 sp = oureg-4*BY2WD-ERRMAX;
921 splhi();
922 ureg->sp = sp;
923 ((ulong*)sp)[1] = oureg; /* arg 1 0(FP) is ureg* */
924 ((ulong*)sp)[0] = 0; /* arg 0 is pc */
925 break;
926
927 default:
928 pprint("unknown noted arg 0x%lux\n", arg0);
929 up->lastnote.flag = NDebug;
930 /* fall through */
931
932 case NDFLT:
933 if(up->lastnote.flag == NDebug)
934 pprint("suicide: %s\n", up->lastnote.msg);
935 qunlock(&up->debug);
936 pexit(up->lastnote.msg, up->lastnote.flag!=NDebug);
937 }
938 up->fpstate &= ~FPillegal;
939 if (up->fpstate == FPactive)
940 ureg->srr1 |= MSR_FP;
941 else
942 ureg->srr1 &= ~MSR_FP;
943 }
944