19a747e4fSDavid du Colombier #include "u.h"
29a747e4fSDavid du Colombier #include "../port/lib.h"
39a747e4fSDavid du Colombier #include "mem.h"
49a747e4fSDavid du Colombier #include "dat.h"
59a747e4fSDavid du Colombier #include "fns.h"
69a747e4fSDavid du Colombier #include "ureg.h"
79a747e4fSDavid du Colombier #include "io.h"
8e288d156SDavid du Colombier #include "tos.h"
99a747e4fSDavid du Colombier #include "../port/error.h"
109a747e4fSDavid du Colombier
119a747e4fSDavid du Colombier static Lock vctllock;
129a747e4fSDavid du Colombier static Vctl *vctl[256];
139a747e4fSDavid du Colombier
149a747e4fSDavid du Colombier void
hwintrinit(void)159a747e4fSDavid du Colombier hwintrinit(void)
169a747e4fSDavid du Colombier {
179a747e4fSDavid du Colombier i8259init();
189a747e4fSDavid du Colombier mpicenable(0, nil); /* 8259 interrupts are routed through MPIC intr 0 */
199a747e4fSDavid du Colombier }
209a747e4fSDavid du Colombier
219a747e4fSDavid du Colombier static int
hwintrenable(Vctl * v)229a747e4fSDavid du Colombier hwintrenable(Vctl *v)
239a747e4fSDavid du Colombier {
249a747e4fSDavid du Colombier int vec, irq;
259a747e4fSDavid du Colombier
269a747e4fSDavid du Colombier irq = v->irq;
279a747e4fSDavid du Colombier if(BUSTYPE(v->tbdf) == BusPCI) { /* MPIC? */
289a747e4fSDavid du Colombier if(irq > 15) {
299a747e4fSDavid du Colombier print("intrenable: pci irq %d out of range\n", v->irq);
309a747e4fSDavid du Colombier return -1;
319a747e4fSDavid du Colombier }
329a747e4fSDavid du Colombier vec = irq;
339a747e4fSDavid du Colombier mpicenable(vec, v);
349a747e4fSDavid du Colombier }
359a747e4fSDavid du Colombier else {
369a747e4fSDavid du Colombier if(irq > MaxIrqPIC) {
379a747e4fSDavid du Colombier print("intrenable: irq %d out of range\n", v->irq);
389a747e4fSDavid du Colombier return -1;
399a747e4fSDavid du Colombier }
409a747e4fSDavid du Colombier vec = irq+VectorPIC;
419a747e4fSDavid du Colombier if(i8259enable(v) == -1)
429a747e4fSDavid du Colombier return -1;
439a747e4fSDavid du Colombier }
449a747e4fSDavid du Colombier return vec;
459a747e4fSDavid du Colombier }
469a747e4fSDavid du Colombier
479a747e4fSDavid du Colombier static int
hwintrdisable(Vctl * v)489a747e4fSDavid du Colombier hwintrdisable(Vctl *v)
499a747e4fSDavid du Colombier {
509a747e4fSDavid du Colombier int vec, irq;
519a747e4fSDavid du Colombier
529a747e4fSDavid du Colombier irq = v->irq;
539a747e4fSDavid du Colombier if(BUSTYPE(v->tbdf) == BusPCI) { /* MPIC? */
549a747e4fSDavid du Colombier if(irq > 15) {
559a747e4fSDavid du Colombier print("intrdisable: pci irq %d out of range\n", v->irq);
569a747e4fSDavid du Colombier return -1;
579a747e4fSDavid du Colombier }
589a747e4fSDavid du Colombier vec = irq;
599a747e4fSDavid du Colombier mpicdisable(vec);
609a747e4fSDavid du Colombier }
619a747e4fSDavid du Colombier else {
629a747e4fSDavid du Colombier if(irq > MaxIrqPIC) {
639a747e4fSDavid du Colombier print("intrdisable: irq %d out of range\n", v->irq);
649a747e4fSDavid du Colombier return -1;
659a747e4fSDavid du Colombier }
669a747e4fSDavid du Colombier vec = irq+VectorPIC;
679a747e4fSDavid du Colombier if(i8259disable(irq) == -1)
689a747e4fSDavid du Colombier return -1;
699a747e4fSDavid du Colombier }
709a747e4fSDavid du Colombier return vec;
719a747e4fSDavid du Colombier }
729a747e4fSDavid du Colombier
739a747e4fSDavid du Colombier static int
hwvecno(int irq,int tbdf)749a747e4fSDavid du Colombier hwvecno(int irq, int tbdf)
759a747e4fSDavid du Colombier {
769a747e4fSDavid du Colombier if(BUSTYPE(tbdf) == BusPCI) /* MPIC? */
779a747e4fSDavid du Colombier return irq;
789a747e4fSDavid du Colombier else
799a747e4fSDavid du Colombier return irq+VectorPIC;
809a747e4fSDavid du Colombier }
819a747e4fSDavid du Colombier
829a747e4fSDavid du Colombier void
intrenable(int irq,void (* f)(Ureg *,void *),void * a,int tbdf,char * name)839a747e4fSDavid du Colombier intrenable(int irq, void (*f)(Ureg*, void*), void* a, int tbdf, char *name)
849a747e4fSDavid du Colombier {
859a747e4fSDavid du Colombier int vno;
869a747e4fSDavid du Colombier Vctl *v;
879a747e4fSDavid du Colombier
889a747e4fSDavid du Colombier if(f == nil){
899a747e4fSDavid du Colombier print("intrenable: nil handler for %d, tbdf 0x%uX for %s\n",
909a747e4fSDavid du Colombier irq, tbdf, name);
919a747e4fSDavid du Colombier return;
929a747e4fSDavid du Colombier }
939a747e4fSDavid du Colombier
949a747e4fSDavid du Colombier v = xalloc(sizeof(Vctl));
959a747e4fSDavid du Colombier v->isintr = 1;
969a747e4fSDavid du Colombier v->irq = irq;
979a747e4fSDavid du Colombier v->tbdf = tbdf;
989a747e4fSDavid du Colombier v->f = f;
999a747e4fSDavid du Colombier v->a = a;
1009a747e4fSDavid du Colombier strncpy(v->name, name, KNAMELEN-1);
1019a747e4fSDavid du Colombier v->name[KNAMELEN-1] = 0;
1029a747e4fSDavid du Colombier
1039a747e4fSDavid du Colombier ilock(&vctllock);
1049a747e4fSDavid du Colombier vno = hwintrenable(v);
1059a747e4fSDavid du Colombier if(vno == -1){
1069a747e4fSDavid du Colombier iunlock(&vctllock);
1079a747e4fSDavid du Colombier print("intrenable: couldn't enable irq %d, tbdf 0x%uX for %s\n",
1089a747e4fSDavid du Colombier irq, tbdf, v->name);
1099a747e4fSDavid du Colombier xfree(v);
1109a747e4fSDavid du Colombier return;
1119a747e4fSDavid du Colombier }
1129a747e4fSDavid du Colombier if(vctl[vno]){
1139a747e4fSDavid du Colombier if(vctl[vno]->isr != v->isr || vctl[vno]->eoi != v->eoi)
114c9b6d007SDavid du Colombier panic("intrenable: handler: %s %s %#p %#p %#p %#p",
1159a747e4fSDavid du Colombier vctl[vno]->name, v->name,
1169a747e4fSDavid du Colombier vctl[vno]->isr, v->isr, vctl[vno]->eoi, v->eoi);
1179a747e4fSDavid du Colombier v->next = vctl[vno];
1189a747e4fSDavid du Colombier }
1199a747e4fSDavid du Colombier vctl[vno] = v;
1209a747e4fSDavid du Colombier iunlock(&vctllock);
1219a747e4fSDavid du Colombier }
1229a747e4fSDavid du Colombier
1239a747e4fSDavid du Colombier void
intrdisable(int irq,void (* f)(Ureg *,void *),void * a,int tbdf,char * name)1249a747e4fSDavid du Colombier intrdisable(int irq, void (*f)(Ureg *, void *), void *a, int tbdf, char *name)
1259a747e4fSDavid du Colombier {
1269a747e4fSDavid du Colombier Vctl **pv, *v;
1279a747e4fSDavid du Colombier int vno;
1289a747e4fSDavid du Colombier
1299a747e4fSDavid du Colombier vno = hwvecno(irq, tbdf);
1309a747e4fSDavid du Colombier ilock(&vctllock);
1319a747e4fSDavid du Colombier pv = &vctl[vno];
1329a747e4fSDavid du Colombier while (*pv &&
1339a747e4fSDavid du Colombier ((*pv)->irq != irq || (*pv)->tbdf != tbdf || (*pv)->f != f || (*pv)->a != a ||
1349a747e4fSDavid du Colombier strcmp((*pv)->name, name)))
1359a747e4fSDavid du Colombier pv = &((*pv)->next);
1369a747e4fSDavid du Colombier assert(*pv);
1379a747e4fSDavid du Colombier
1389a747e4fSDavid du Colombier v = *pv;
1399a747e4fSDavid du Colombier *pv = (*pv)->next; /* Link out the entry */
1409a747e4fSDavid du Colombier
1419a747e4fSDavid du Colombier if(vctl[vno] == nil)
1429a747e4fSDavid du Colombier hwintrdisable(v);
1439a747e4fSDavid du Colombier iunlock(&vctllock);
1449a747e4fSDavid du Colombier xfree(v);
1459a747e4fSDavid du Colombier }
1469a747e4fSDavid du Colombier
1479a747e4fSDavid du Colombier void syscall(Ureg*);
1489a747e4fSDavid du Colombier void noted(Ureg*, ulong);
1499a747e4fSDavid du Colombier static void _dumpstack(Ureg*);
1509a747e4fSDavid du Colombier
1519a747e4fSDavid du Colombier char *excname[] =
1529a747e4fSDavid du Colombier {
1539a747e4fSDavid du Colombier "reserved 0",
1549a747e4fSDavid du Colombier "system reset",
1559a747e4fSDavid du Colombier "machine check",
1569a747e4fSDavid du Colombier "data access",
1579a747e4fSDavid du Colombier "instruction access",
1589a747e4fSDavid du Colombier "external interrupt",
1599a747e4fSDavid du Colombier "alignment",
1609a747e4fSDavid du Colombier "program exception",
1619a747e4fSDavid du Colombier "floating-point unavailable",
1629a747e4fSDavid du Colombier "decrementer",
1639a747e4fSDavid du Colombier "reserved A",
1649a747e4fSDavid du Colombier "reserved B",
1659a747e4fSDavid du Colombier "system call",
1669a747e4fSDavid du Colombier "trace trap",
1679a747e4fSDavid du Colombier "floating point assist",
1689a747e4fSDavid du Colombier "reserved F",
1699a747e4fSDavid du Colombier "reserved 10",
1709a747e4fSDavid du Colombier "reserved 11",
1719a747e4fSDavid du Colombier "reserved 12",
1729a747e4fSDavid du Colombier "instruction address breakpoint",
1739a747e4fSDavid du Colombier "system management interrupt",
1749a747e4fSDavid du Colombier };
1759a747e4fSDavid du Colombier
1769a747e4fSDavid du Colombier char *fpcause[] =
1779a747e4fSDavid du Colombier {
1789a747e4fSDavid du Colombier "inexact operation",
1799a747e4fSDavid du Colombier "division by zero",
1809a747e4fSDavid du Colombier "underflow",
1819a747e4fSDavid du Colombier "overflow",
1829a747e4fSDavid du Colombier "invalid operation",
1839a747e4fSDavid du Colombier };
1849a747e4fSDavid du Colombier char *fpexcname(Ureg*, ulong, char*);
1859a747e4fSDavid du Colombier #define FPEXPMASK 0xfff80300 /* Floating exception bits in fpscr */
1869a747e4fSDavid du Colombier
1879a747e4fSDavid du Colombier
1889a747e4fSDavid du Colombier char *regname[]={
1899a747e4fSDavid du Colombier "CAUSE", "SRR1",
1909a747e4fSDavid du Colombier "PC", "GOK",
1919a747e4fSDavid du Colombier "LR", "CR",
1929a747e4fSDavid du Colombier "XER", "CTR",
1939a747e4fSDavid du Colombier "R0", "R1",
1949a747e4fSDavid du Colombier "R2", "R3",
1959a747e4fSDavid du Colombier "R4", "R5",
1969a747e4fSDavid du Colombier "R6", "R7",
1979a747e4fSDavid du Colombier "R8", "R9",
1989a747e4fSDavid du Colombier "R10", "R11",
1999a747e4fSDavid du Colombier "R12", "R13",
2009a747e4fSDavid du Colombier "R14", "R15",
2019a747e4fSDavid du Colombier "R16", "R17",
2029a747e4fSDavid du Colombier "R18", "R19",
2039a747e4fSDavid du Colombier "R20", "R21",
2049a747e4fSDavid du Colombier "R22", "R23",
2059a747e4fSDavid du Colombier "R24", "R25",
2069a747e4fSDavid du Colombier "R26", "R27",
2079a747e4fSDavid du Colombier "R28", "R29",
2089a747e4fSDavid du Colombier "R30", "R31",
2099a747e4fSDavid du Colombier };
2109a747e4fSDavid du Colombier
2119a747e4fSDavid du Colombier void
trap(Ureg * ureg)2129a747e4fSDavid du Colombier trap(Ureg *ureg)
2139a747e4fSDavid du Colombier {
2149a747e4fSDavid du Colombier ulong dsisr;
2159a747e4fSDavid du Colombier int ecode, user;
2169a747e4fSDavid du Colombier char buf[ERRMAX], *s;
2179a747e4fSDavid du Colombier
2189a747e4fSDavid du Colombier ecode = (ureg->cause >> 8) & 0xff;
2199a747e4fSDavid du Colombier user = (ureg->srr1 & MSR_PR) != 0;
2209a747e4fSDavid du Colombier if(user)
2219a747e4fSDavid du Colombier up->dbgreg = ureg;
2229a747e4fSDavid du Colombier
2239a747e4fSDavid du Colombier if(ureg->status & MSR_RI == 0)
2249a747e4fSDavid du Colombier print("double fault?: ecode = %d\n", ecode);
2259a747e4fSDavid du Colombier
2269a747e4fSDavid du Colombier switch(ecode) {
2279a747e4fSDavid du Colombier case CEI:
2289a747e4fSDavid du Colombier intr(ureg);
2299a747e4fSDavid du Colombier break;
2309a747e4fSDavid du Colombier case CDEC:
2319a747e4fSDavid du Colombier clockintr(ureg);
2329a747e4fSDavid du Colombier break;
2339a747e4fSDavid du Colombier case CSYSCALL:
2349a747e4fSDavid du Colombier if(!user)
235c9b6d007SDavid du Colombier panic("syscall in kernel: srr1 0x%4.4luX", ureg->srr1);
2369a747e4fSDavid du Colombier syscall(ureg);
2379a747e4fSDavid du Colombier return; /* syscall() calls notify itself, don't do it again */
2389a747e4fSDavid du Colombier case CFPU:
2399a747e4fSDavid du Colombier if(!user || up == nil) {
2409a747e4fSDavid du Colombier dumpregs(ureg);
2419a747e4fSDavid du Colombier panic("floating point in kernel");
2429a747e4fSDavid du Colombier }
2439a747e4fSDavid du Colombier switch(up->fpstate){
2449a747e4fSDavid du Colombier case FPinit:
2459a747e4fSDavid du Colombier fprestore(&initfp);
2469a747e4fSDavid du Colombier up->fpstate = FPactive;
2479a747e4fSDavid du Colombier break;
2489a747e4fSDavid du Colombier case FPinactive:
2499a747e4fSDavid du Colombier fprestore(&up->fpsave);
2509a747e4fSDavid du Colombier up->fpstate = FPactive;
2519a747e4fSDavid du Colombier break;
2529a747e4fSDavid du Colombier default:
2539a747e4fSDavid du Colombier panic("fpstate");
2549a747e4fSDavid du Colombier }
2559a747e4fSDavid du Colombier ureg->srr1 |= MSR_FP;
2569a747e4fSDavid du Colombier break;
2579a747e4fSDavid du Colombier case CISI:
2589a747e4fSDavid du Colombier faultpower(ureg, ureg->pc, 1);
2599a747e4fSDavid du Colombier break;
2609a747e4fSDavid du Colombier case CDSI:
2619a747e4fSDavid du Colombier dsisr = getdsisr();
2629a747e4fSDavid du Colombier if(dsisr & BIT(6))
2639a747e4fSDavid du Colombier faultpower(ureg, getdar(), 0);
2649a747e4fSDavid du Colombier else
2659a747e4fSDavid du Colombier faultpower(ureg, getdar(), 1);
2669a747e4fSDavid du Colombier break;
2679a747e4fSDavid du Colombier case CPROG:
2689a747e4fSDavid du Colombier if(ureg->status & (1<<19))
2699a747e4fSDavid du Colombier s = "floating point exception";
2709a747e4fSDavid du Colombier else if(ureg->status & (1<<18))
2719a747e4fSDavid du Colombier s = "illegal instruction";
2729a747e4fSDavid du Colombier else if(ureg->status & (1<<17))
2739a747e4fSDavid du Colombier s = "privileged instruction";
2749a747e4fSDavid du Colombier else
2759a747e4fSDavid du Colombier s = "undefined program exception";
2769a747e4fSDavid du Colombier if(user){
2779a747e4fSDavid du Colombier spllo();
2789a747e4fSDavid du Colombier sprint(buf, "sys: trap: %s", s);
2799a747e4fSDavid du Colombier postnote(up, 1, buf, NDebug);
2809a747e4fSDavid du Colombier break;
2819a747e4fSDavid du Colombier }
2829a747e4fSDavid du Colombier dumpregs(ureg);
2839a747e4fSDavid du Colombier panic(s);
2849a747e4fSDavid du Colombier break;
2859a747e4fSDavid du Colombier default:
2862615514eSDavid du Colombier if(ecode < nelem(excname) && user){
2879a747e4fSDavid du Colombier spllo();
2889a747e4fSDavid du Colombier sprint(buf, "sys: trap: %s", excname[ecode]);
2899a747e4fSDavid du Colombier postnote(up, 1, buf, NDebug);
2909a747e4fSDavid du Colombier break;
2919a747e4fSDavid du Colombier }
2929a747e4fSDavid du Colombier dumpregs(ureg);
2939a747e4fSDavid du Colombier if(ecode < nelem(excname))
2949a747e4fSDavid du Colombier panic("%s", excname[ecode]);
295c9b6d007SDavid du Colombier panic("unknown trap/intr: %d", ecode);
2969a747e4fSDavid du Colombier }
2979a747e4fSDavid du Colombier
2989a747e4fSDavid du Colombier /* restoreureg must execute at high IPL */
2999a747e4fSDavid du Colombier splhi();
300da51d93aSDavid du Colombier
301da51d93aSDavid du Colombier /* delaysched set because we held a lock or because our quantum ended */
3022009dc88SDavid du Colombier if(up && up->delaysched && ecode == CDEC){
303da51d93aSDavid du Colombier sched();
304da51d93aSDavid du Colombier splhi();
305da51d93aSDavid du Colombier }
306da51d93aSDavid du Colombier
3079a747e4fSDavid du Colombier if(user) {
3089a747e4fSDavid du Colombier notify(ureg);
3099a747e4fSDavid du Colombier if(up->fpstate == FPinactive)
3109a747e4fSDavid du Colombier ureg->srr1 &= ~MSR_FP;
311da51d93aSDavid du Colombier kexit(ureg);
3129a747e4fSDavid du Colombier }
3139a747e4fSDavid du Colombier }
3149a747e4fSDavid du Colombier
3159a747e4fSDavid du Colombier void
faultpower(Ureg * ureg,ulong addr,int read)3169a747e4fSDavid du Colombier faultpower(Ureg *ureg, ulong addr, int read)
3179a747e4fSDavid du Colombier {
3189a747e4fSDavid du Colombier int user, insyscall, n;
3199a747e4fSDavid du Colombier char buf[ERRMAX];
3209a747e4fSDavid du Colombier
3219a747e4fSDavid du Colombier user = (ureg->srr1 & MSR_PR) != 0;
3229a747e4fSDavid du Colombier insyscall = up->insyscall;
3239a747e4fSDavid du Colombier up->insyscall = 1;
3249a747e4fSDavid du Colombier n = fault(addr, read);
3259a747e4fSDavid du Colombier if(n < 0){
3269a747e4fSDavid du Colombier if(!user){
3279a747e4fSDavid du Colombier dumpregs(ureg);
3289a747e4fSDavid du Colombier panic("fault: 0x%lux", addr);
3299a747e4fSDavid du Colombier }
3309a747e4fSDavid du Colombier sprint(buf, "sys: trap: fault %s addr=0x%lux", read? "read" : "write", addr);
3319a747e4fSDavid du Colombier postnote(up, 1, buf, NDebug);
3329a747e4fSDavid du Colombier }
3339a747e4fSDavid du Colombier up->insyscall = insyscall;
3349a747e4fSDavid du Colombier }
3359a747e4fSDavid du Colombier
3369a747e4fSDavid du Colombier void
sethvec(int v,void (* r)(void))3379a747e4fSDavid du Colombier sethvec(int v, void (*r)(void))
3389a747e4fSDavid du Colombier {
3399a747e4fSDavid du Colombier ulong *vp, pa, o;
3409a747e4fSDavid du Colombier
3419a747e4fSDavid du Colombier vp = KADDR(v);
3429a747e4fSDavid du Colombier vp[0] = 0x7c1043a6; /* MOVW R0, SPR(SPRG0) */
3439a747e4fSDavid du Colombier vp[1] = 0x7c0802a6; /* MOVW LR, R0 */
3449a747e4fSDavid du Colombier vp[2] = 0x7c1243a6; /* MOVW R0, SPR(SPRG2) */
3459a747e4fSDavid du Colombier pa = PADDR(r);
3469a747e4fSDavid du Colombier o = pa >> 25;
3479a747e4fSDavid du Colombier if(o != 0 && o != 0x7F){
3489a747e4fSDavid du Colombier /* a branch too far */
3499a747e4fSDavid du Colombier vp[3] = (15<<26)|(pa>>16); /* MOVW $r&~0xFFFF, R0 */
3509a747e4fSDavid du Colombier vp[4] = (24<<26)|(pa&0xFFFF); /* OR $r&0xFFFF, R0 */
3519a747e4fSDavid du Colombier vp[5] = 0x7c0803a6; /* MOVW R0, LR */
3529a747e4fSDavid du Colombier vp[6] = 0x4e800021; /* BL (LR) */
3539a747e4fSDavid du Colombier }else
3549a747e4fSDavid du Colombier vp[3] = (18<<26)|(pa&0x3FFFFFC)|3; /* bla */
3559a747e4fSDavid du Colombier dcflush(vp, 8*sizeof(ulong));
3569a747e4fSDavid du Colombier }
3579a747e4fSDavid du Colombier
3589a747e4fSDavid du Colombier void
trapinit(void)3599a747e4fSDavid du Colombier trapinit(void)
3609a747e4fSDavid du Colombier {
3619a747e4fSDavid du Colombier int i;
3629a747e4fSDavid du Colombier
3639a747e4fSDavid du Colombier /*
3649a747e4fSDavid du Colombier * set all exceptions to trap
3659a747e4fSDavid du Colombier */
3669a747e4fSDavid du Colombier for(i = 0; i < 0x2000; i += 0x100)
3679a747e4fSDavid du Colombier sethvec(i, trapvec);
3689a747e4fSDavid du Colombier
3699a747e4fSDavid du Colombier putmsr(getmsr() & ~MSR_IP);
3709a747e4fSDavid du Colombier }
3719a747e4fSDavid du Colombier
3729a747e4fSDavid du Colombier void
intr(Ureg * ureg)3739a747e4fSDavid du Colombier intr(Ureg *ureg)
3749a747e4fSDavid du Colombier {
3759a747e4fSDavid du Colombier int vno;
3769a747e4fSDavid du Colombier Vctl *ctl, *v;
3779a747e4fSDavid du Colombier
3789a747e4fSDavid du Colombier vno = mpicintack();
3799a747e4fSDavid du Colombier if(vno == 0) { /* 8259, wired through MPIC vec 0 */
3809a747e4fSDavid du Colombier vno = i8259intack();
3819a747e4fSDavid du Colombier mpiceoi(0);
3829a747e4fSDavid du Colombier }
3839a747e4fSDavid du Colombier
3849a747e4fSDavid du Colombier if(vno > nelem(vctl) || (ctl = vctl[vno]) == 0) {
3859a747e4fSDavid du Colombier panic("spurious intr %d", vno);
3869a747e4fSDavid du Colombier return;
3879a747e4fSDavid du Colombier }
3889a747e4fSDavid du Colombier
3899a747e4fSDavid du Colombier if(ctl->isr)
3909a747e4fSDavid du Colombier ctl->isr(vno);
3919a747e4fSDavid du Colombier for(v = ctl; v != nil; v = v->next){
3929a747e4fSDavid du Colombier if(v->f)
3939a747e4fSDavid du Colombier v->f(ureg, v->a);
3949a747e4fSDavid du Colombier }
3959a747e4fSDavid du Colombier if(ctl->eoi)
3969a747e4fSDavid du Colombier ctl->eoi(vno);
3979a747e4fSDavid du Colombier
3982009dc88SDavid du Colombier if(up)
399a6a9e072SDavid du Colombier preempted();
4009a747e4fSDavid du Colombier }
4019a747e4fSDavid du Colombier
4029a747e4fSDavid du Colombier char*
fpexcname(Ureg * ur,ulong fpscr,char * buf)4039a747e4fSDavid du Colombier fpexcname(Ureg *ur, ulong fpscr, char *buf)
4049a747e4fSDavid du Colombier {
4059a747e4fSDavid du Colombier int i;
4069a747e4fSDavid du Colombier char *s;
4079a747e4fSDavid du Colombier ulong fppc;
4089a747e4fSDavid du Colombier
4099a747e4fSDavid du Colombier fppc = ur->pc;
4109a747e4fSDavid du Colombier s = 0;
4119a747e4fSDavid du Colombier fpscr >>= 3; /* trap enable bits */
4129a747e4fSDavid du Colombier fpscr &= (fpscr>>22); /* anded with exceptions */
4139a747e4fSDavid du Colombier for(i=0; i<5; i++)
4149a747e4fSDavid du Colombier if(fpscr & (1<<i))
4159a747e4fSDavid du Colombier s = fpcause[i];
4169a747e4fSDavid du Colombier if(s == 0)
4179a747e4fSDavid du Colombier return "no floating point exception";
4189a747e4fSDavid du Colombier sprint(buf, "%s fppc=0x%lux", s, fppc);
4199a747e4fSDavid du Colombier return buf;
4209a747e4fSDavid du Colombier }
4219a747e4fSDavid du Colombier
4229a747e4fSDavid du Colombier /*
4239a747e4fSDavid du Colombier * Fill in enough of Ureg to get a stack trace, and call a function.
4249a747e4fSDavid du Colombier * Used by debugging interface rdb.
4259a747e4fSDavid du Colombier */
4269a747e4fSDavid du Colombier
4279a747e4fSDavid du Colombier static void
getpcsp(ulong * pc,ulong * sp)4289a747e4fSDavid du Colombier getpcsp(ulong *pc, ulong *sp)
4299a747e4fSDavid du Colombier {
4309a747e4fSDavid du Colombier *pc = getcallerpc(&pc);
4319a747e4fSDavid du Colombier *sp = (ulong)&pc-4;
4329a747e4fSDavid du Colombier }
4339a747e4fSDavid du Colombier
4349a747e4fSDavid du Colombier void
callwithureg(void (* fn)(Ureg *))4359a747e4fSDavid du Colombier callwithureg(void (*fn)(Ureg*))
4369a747e4fSDavid du Colombier {
4379a747e4fSDavid du Colombier Ureg ureg;
4389a747e4fSDavid du Colombier
4399a747e4fSDavid du Colombier getpcsp((ulong*)&ureg.pc, (ulong*)&ureg.sp);
4409a747e4fSDavid du Colombier ureg.lr = getcallerpc(&fn);
4419a747e4fSDavid du Colombier fn(&ureg);
4429a747e4fSDavid du Colombier }
4439a747e4fSDavid du Colombier
4449a747e4fSDavid du Colombier static void
_dumpstack(Ureg * ureg)4459a747e4fSDavid du Colombier _dumpstack(Ureg *ureg)
4469a747e4fSDavid du Colombier {
4479a747e4fSDavid du Colombier ulong l, sl, el, v;
4489a747e4fSDavid du Colombier int i;
4499a747e4fSDavid du Colombier
4509a747e4fSDavid du Colombier l = (ulong)&l;
4519a747e4fSDavid du Colombier if(up == 0){
4529a747e4fSDavid du Colombier el = (ulong)m+BY2PG;
4539a747e4fSDavid du Colombier sl = el-KSTACK;
4549a747e4fSDavid du Colombier }
4559a747e4fSDavid du Colombier else{
4569a747e4fSDavid du Colombier sl = (ulong)up->kstack;
4579a747e4fSDavid du Colombier el = sl + KSTACK;
4589a747e4fSDavid du Colombier }
4599a747e4fSDavid du Colombier if(l > el || l < sl){
4609a747e4fSDavid du Colombier el = (ulong)m+BY2PG;
4619a747e4fSDavid du Colombier sl = el-KSTACK;
4629a747e4fSDavid du Colombier }
4639a747e4fSDavid du Colombier if(l > el || l < sl)
4649a747e4fSDavid du Colombier return;
4659a747e4fSDavid du Colombier print("ktrace /kernel/path %.8lux %.8lux %.8lux\n", ureg->pc, ureg->sp, ureg->lr);
4669a747e4fSDavid du Colombier i = 0;
4679a747e4fSDavid du Colombier for(; l < el; l += 4){
4689a747e4fSDavid du Colombier v = *(ulong*)l;
4699a747e4fSDavid du Colombier if(KTZERO < v && v < (ulong)etext){
4709a747e4fSDavid du Colombier print("%.8lux=%.8lux ", l, v);
4719a747e4fSDavid du Colombier if(i++ == 4){
4729a747e4fSDavid du Colombier print("\n");
4739a747e4fSDavid du Colombier i = 0;
4749a747e4fSDavid du Colombier }
4759a747e4fSDavid du Colombier }
4769a747e4fSDavid du Colombier }
4779a747e4fSDavid du Colombier }
4789a747e4fSDavid du Colombier
4799a747e4fSDavid du Colombier void
dumpstack(void)4809a747e4fSDavid du Colombier dumpstack(void)
4819a747e4fSDavid du Colombier {
4829a747e4fSDavid du Colombier callwithureg(_dumpstack);
4839a747e4fSDavid du Colombier }
4849a747e4fSDavid du Colombier
4859a747e4fSDavid du Colombier void
dumpregs(Ureg * ur)4869a747e4fSDavid du Colombier dumpregs(Ureg *ur)
4879a747e4fSDavid du Colombier {
4889a747e4fSDavid du Colombier int i;
4899a747e4fSDavid du Colombier ulong *l;
4909a747e4fSDavid du Colombier
4919a747e4fSDavid du Colombier if(up) {
4929a747e4fSDavid du Colombier print("registers for %s %ld\n", up->text, up->pid);
4939a747e4fSDavid du Colombier if(ur->srr1 & MSR_PR == 0)
4949a747e4fSDavid du Colombier if(ur->usp < (ulong)up->kstack || ur->usp > (ulong)up->kstack+KSTACK)
4959a747e4fSDavid du Colombier print("invalid stack ptr\n");
4969a747e4fSDavid du Colombier }
4979a747e4fSDavid du Colombier else
4989a747e4fSDavid du Colombier print("registers for kernel\n");
4999a747e4fSDavid du Colombier
5009a747e4fSDavid du Colombier print("dsisr\t%.8lux\tdar\t%.8lux\n", getdsisr(), getdar());
5019a747e4fSDavid du Colombier l = &ur->cause;
5029a747e4fSDavid du Colombier for(i=0; i<sizeof regname/sizeof(char*); i+=2, l+=2)
5039a747e4fSDavid du Colombier print("%s\t%.8lux\t%s\t%.8lux\n", regname[i], l[0], regname[i+1], l[1]);
5049a747e4fSDavid du Colombier }
5059a747e4fSDavid du Colombier
5069a747e4fSDavid du Colombier static void
linkproc(void)5079a747e4fSDavid du Colombier linkproc(void)
5089a747e4fSDavid du Colombier {
5099a747e4fSDavid du Colombier spllo();
5109a747e4fSDavid du Colombier (*up->kpfun)(up->kparg);
5119a747e4fSDavid du Colombier pexit("", 0);
5129a747e4fSDavid du Colombier }
5139a747e4fSDavid du Colombier
5149a747e4fSDavid du Colombier void
kprocchild(Proc * p,void (* func)(void *),void * arg)5159a747e4fSDavid du Colombier kprocchild(Proc *p, void (*func)(void*), void *arg)
5169a747e4fSDavid du Colombier {
5179a747e4fSDavid du Colombier p->sched.pc = (ulong)linkproc;
5189a747e4fSDavid du Colombier p->sched.sp = (ulong)p->kstack+KSTACK;
5199a747e4fSDavid du Colombier
5209a747e4fSDavid du Colombier p->kpfun = func;
5219a747e4fSDavid du Colombier p->kparg = arg;
5229a747e4fSDavid du Colombier }
5239a747e4fSDavid du Colombier
5249a747e4fSDavid du Colombier /*
525*fac6300fSDavid du Colombier * called in syscallfmt.c, sysfile.c, sysproc.c
5269a747e4fSDavid du Colombier */
5279a747e4fSDavid du Colombier void
validalign(uintptr addr,unsigned align)528*fac6300fSDavid du Colombier validalign(uintptr addr, unsigned align)
5299a747e4fSDavid du Colombier {
530*fac6300fSDavid du Colombier /*
531*fac6300fSDavid du Colombier * Plan 9 is a 32-bit O/S, and the hardware it runs on
532*fac6300fSDavid du Colombier * does not usually have instructions which move 64-bit
533*fac6300fSDavid du Colombier * quantities directly, synthesizing the operations
534*fac6300fSDavid du Colombier * with 32-bit move instructions. Therefore, the compiler
535*fac6300fSDavid du Colombier * (and hardware) usually only enforce 32-bit alignment,
536*fac6300fSDavid du Colombier * if at all.
537*fac6300fSDavid du Colombier *
538*fac6300fSDavid du Colombier * Take this out if the architecture warrants it.
539*fac6300fSDavid du Colombier */
540*fac6300fSDavid du Colombier if(align == sizeof(vlong))
541*fac6300fSDavid du Colombier align = sizeof(long);
542*fac6300fSDavid du Colombier
543*fac6300fSDavid du Colombier /*
544*fac6300fSDavid du Colombier * Check align is a power of 2, then addr alignment.
545*fac6300fSDavid du Colombier */
546*fac6300fSDavid du Colombier if((align != 0 && !(align & (align-1))) && !(addr & (align-1)))
547*fac6300fSDavid du Colombier return;
5489a747e4fSDavid du Colombier postnote(up, 1, "sys: odd address", NDebug);
5499a747e4fSDavid du Colombier error(Ebadarg);
550*fac6300fSDavid du Colombier /*NOTREACHED*/
5519a747e4fSDavid du Colombier }
5529a747e4fSDavid du Colombier
5539a747e4fSDavid du Colombier long
execregs(ulong entry,ulong ssize,ulong nargs)5549a747e4fSDavid du Colombier execregs(ulong entry, ulong ssize, ulong nargs)
5559a747e4fSDavid du Colombier {
5569a747e4fSDavid du Colombier ulong *sp;
5579a747e4fSDavid du Colombier Ureg *ureg;
5589a747e4fSDavid du Colombier
5599a747e4fSDavid du Colombier sp = (ulong*)(USTKTOP - ssize);
5609a747e4fSDavid du Colombier *--sp = nargs;
5619a747e4fSDavid du Colombier
5629a747e4fSDavid du Colombier ureg = up->dbgreg;
5639a747e4fSDavid du Colombier ureg->usp = (ulong)sp;
5649a747e4fSDavid du Colombier ureg->pc = entry;
5659a747e4fSDavid du Colombier ureg->srr1 &= ~MSR_FP;
566e288d156SDavid du Colombier return USTKTOP-sizeof(Tos); /* address of kernel/user shared data */
5679a747e4fSDavid du Colombier }
5689a747e4fSDavid du Colombier
5699a747e4fSDavid du Colombier void
forkchild(Proc * p,Ureg * ur)5709a747e4fSDavid du Colombier forkchild(Proc *p, Ureg *ur)
5719a747e4fSDavid du Colombier {
5729a747e4fSDavid du Colombier Ureg *cur;
5739a747e4fSDavid du Colombier
5749a747e4fSDavid du Colombier p->sched.sp = (ulong)p->kstack+KSTACK-UREGSIZE;
5759a747e4fSDavid du Colombier p->sched.pc = (ulong)forkret;
5769a747e4fSDavid du Colombier
5779a747e4fSDavid du Colombier cur = (Ureg*)(p->sched.sp+2*BY2WD);
5789a747e4fSDavid du Colombier memmove(cur, ur, sizeof(Ureg));
5799a747e4fSDavid du Colombier cur->r3 = 0;
5809a747e4fSDavid du Colombier
5819a747e4fSDavid du Colombier /* Things from bottom of syscall we never got to execute */
5829a747e4fSDavid du Colombier p->psstate = 0;
5839a747e4fSDavid du Colombier p->insyscall = 0;
5849a747e4fSDavid du Colombier }
5859a747e4fSDavid du Colombier
5869a747e4fSDavid du Colombier ulong
userpc(void)5879a747e4fSDavid du Colombier userpc(void)
5889a747e4fSDavid du Colombier {
5899a747e4fSDavid du Colombier Ureg *ureg;
5909a747e4fSDavid du Colombier
5919a747e4fSDavid du Colombier ureg = (Ureg*)up->dbgreg;
5929a747e4fSDavid du Colombier return ureg->pc;
5939a747e4fSDavid du Colombier }
5949a747e4fSDavid du Colombier
5959a747e4fSDavid du Colombier
5969a747e4fSDavid du Colombier /* This routine must save the values of registers the user is not
5979a747e4fSDavid du Colombier * permitted to write from devproc and then restore the saved values
5989a747e4fSDavid du Colombier * before returning
5999a747e4fSDavid du Colombier */
6009a747e4fSDavid du Colombier void
setregisters(Ureg * xp,char * pureg,char * uva,int n)6019a747e4fSDavid du Colombier setregisters(Ureg *xp, char *pureg, char *uva, int n)
6029a747e4fSDavid du Colombier {
6039a747e4fSDavid du Colombier ulong status;
6049a747e4fSDavid du Colombier
6059a747e4fSDavid du Colombier status = xp->status;
6069a747e4fSDavid du Colombier memmove(pureg, uva, n);
6079a747e4fSDavid du Colombier xp->status = status;
6089a747e4fSDavid du Colombier }
6099a747e4fSDavid du Colombier
6109a747e4fSDavid du Colombier /* Give enough context in the ureg to produce a kernel stack for
6119a747e4fSDavid du Colombier * a sleeping process
6129a747e4fSDavid du Colombier */
6139a747e4fSDavid du Colombier void
setkernur(Ureg * ureg,Proc * p)6149a747e4fSDavid du Colombier setkernur(Ureg* ureg, Proc* p)
6159a747e4fSDavid du Colombier {
6169a747e4fSDavid du Colombier ureg->pc = p->sched.pc;
6179a747e4fSDavid du Colombier ureg->sp = p->sched.sp+4;
6189a747e4fSDavid du Colombier }
6199a747e4fSDavid du Colombier
6209a747e4fSDavid du Colombier ulong
dbgpc(Proc * p)6219a747e4fSDavid du Colombier dbgpc(Proc *p)
6229a747e4fSDavid du Colombier {
6239a747e4fSDavid du Colombier Ureg *ureg;
6249a747e4fSDavid du Colombier
6259a747e4fSDavid du Colombier ureg = p->dbgreg;
6269a747e4fSDavid du Colombier if(ureg == 0)
6279a747e4fSDavid du Colombier return 0;
6289a747e4fSDavid du Colombier
6299a747e4fSDavid du Colombier return ureg->pc;
6309a747e4fSDavid du Colombier }
6319a747e4fSDavid du Colombier
6329a747e4fSDavid du Colombier /*
6339a747e4fSDavid du Colombier * system calls
6349a747e4fSDavid du Colombier */
6359a747e4fSDavid du Colombier #include "../port/systab.h"
6369a747e4fSDavid du Colombier
6379a747e4fSDavid du Colombier /* TODO: make this trap a separate asm entry point, like on other RISC architectures */
6389a747e4fSDavid du Colombier void
syscall(Ureg * ureg)6399a747e4fSDavid du Colombier syscall(Ureg* ureg)
6409a747e4fSDavid du Colombier {
6419a747e4fSDavid du Colombier int i;
6429a747e4fSDavid du Colombier char *e;
6439a747e4fSDavid du Colombier long ret;
6449a747e4fSDavid du Colombier ulong sp, scallnr;
6459a747e4fSDavid du Colombier
6469a747e4fSDavid du Colombier m->syscall++;
6479a747e4fSDavid du Colombier up->insyscall = 1;
6489a747e4fSDavid du Colombier up->pc = ureg->pc;
6499a747e4fSDavid du Colombier up->dbgreg = ureg;
6509a747e4fSDavid du Colombier
6519a747e4fSDavid du Colombier scallnr = ureg->r3;
6529a747e4fSDavid du Colombier up->scallnr = ureg->r3;
6539a747e4fSDavid du Colombier spllo();
6549a747e4fSDavid du Colombier
6559a747e4fSDavid du Colombier sp = ureg->usp;
6569a747e4fSDavid du Colombier up->nerrlab = 0;
6579a747e4fSDavid du Colombier ret = -1;
6589a747e4fSDavid du Colombier if(!waserror()){
6599a747e4fSDavid du Colombier if(scallnr >= nsyscall || systab[scallnr] == nil){
6609b7bf7dfSDavid du Colombier pprint("bad sys call number %lud pc %lux\n",
6619b7bf7dfSDavid du Colombier scallnr, ureg->pc);
6629a747e4fSDavid du Colombier postnote(up, 1, "sys: bad sys call", NDebug);
6639a747e4fSDavid du Colombier error(Ebadarg);
6649a747e4fSDavid du Colombier }
6659a747e4fSDavid du Colombier
6669a747e4fSDavid du Colombier if(sp<(USTKTOP-BY2PG) || sp>(USTKTOP-sizeof(Sargs)-BY2WD))
6679a747e4fSDavid du Colombier validaddr(sp, sizeof(Sargs)+BY2WD, 0);
6689a747e4fSDavid du Colombier
6699a747e4fSDavid du Colombier up->s = *((Sargs*)(sp+BY2WD));
6709a747e4fSDavid du Colombier up->psstate = sysctab[scallnr];
6719a747e4fSDavid du Colombier
6729a747e4fSDavid du Colombier ret = systab[scallnr](up->s.args);
6739a747e4fSDavid du Colombier poperror();
6749a747e4fSDavid du Colombier }else{
6759a747e4fSDavid du Colombier /* failure: save the error buffer for errstr */
6769a747e4fSDavid du Colombier e = up->syserrstr;
6779a747e4fSDavid du Colombier up->syserrstr = up->errstr;
6789a747e4fSDavid du Colombier up->errstr = e;
6799a747e4fSDavid du Colombier }
6809a747e4fSDavid du Colombier if(up->nerrlab){
6819a747e4fSDavid du Colombier print("bad errstack [%uld]: %d extra\n", scallnr, up->nerrlab);
6829a747e4fSDavid du Colombier print("scall %s lr =%lux\n", sysctab[scallnr], ureg->lr);
6839a747e4fSDavid du Colombier for(i = 0; i < NERR; i++)
6849a747e4fSDavid du Colombier print("sp=%lux pc=%lux\n", up->errlab[i].sp, up->errlab[i].pc);
6859a747e4fSDavid du Colombier panic("error stack");
6869a747e4fSDavid du Colombier }
6879a747e4fSDavid du Colombier
6889a747e4fSDavid du Colombier up->insyscall = 0;
6899a747e4fSDavid du Colombier up->psstate = 0;
6909a747e4fSDavid du Colombier
6919a747e4fSDavid du Colombier /*
6929a747e4fSDavid du Colombier * Put return value in frame. On the x86 the syscall is
6939a747e4fSDavid du Colombier * just another trap and the return value from syscall is
6949a747e4fSDavid du Colombier * ignored. On other machines the return value is put into
6959a747e4fSDavid du Colombier * the results register by caller of syscall.
6969a747e4fSDavid du Colombier */
6979a747e4fSDavid du Colombier ureg->r3 = ret;
6989a747e4fSDavid du Colombier
6999a747e4fSDavid du Colombier if(scallnr == NOTED)
7009a747e4fSDavid du Colombier noted(ureg, *(ulong*)(sp+BY2WD));
7019a747e4fSDavid du Colombier
7029a747e4fSDavid du Colombier /* restoreureg must execute at high IPL */
7039a747e4fSDavid du Colombier splhi();
7049a747e4fSDavid du Colombier if(scallnr!=RFORK)
7059a747e4fSDavid du Colombier notify(ureg);
7069a747e4fSDavid du Colombier if(up->fpstate == FPinactive)
7079a747e4fSDavid du Colombier ureg->srr1 &= ~MSR_FP;
7089a747e4fSDavid du Colombier }
7099a747e4fSDavid du Colombier
7109a747e4fSDavid du Colombier /*
7119a747e4fSDavid du Colombier * Call user, if necessary, with note.
7129a747e4fSDavid du Colombier * Pass user the Ureg struct and the note on his stack.
7139a747e4fSDavid du Colombier */
7149a747e4fSDavid du Colombier int
notify(Ureg * ur)7159a747e4fSDavid du Colombier notify(Ureg* ur)
7169a747e4fSDavid du Colombier {
7179a747e4fSDavid du Colombier int l;
7189a747e4fSDavid du Colombier ulong s, sp;
7199a747e4fSDavid du Colombier Note *n;
7209a747e4fSDavid du Colombier
7219a747e4fSDavid du Colombier if(up->procctl)
7229a747e4fSDavid du Colombier procctl(up);
7239a747e4fSDavid du Colombier if(up->nnote == 0)
7249a747e4fSDavid du Colombier return 0;
7259a747e4fSDavid du Colombier
7269a747e4fSDavid du Colombier s = spllo();
7279a747e4fSDavid du Colombier qlock(&up->debug);
7289a747e4fSDavid du Colombier up->notepending = 0;
7299a747e4fSDavid du Colombier n = &up->note[0];
7309a747e4fSDavid du Colombier if(strncmp(n->msg, "sys:", 4) == 0){
7319a747e4fSDavid du Colombier l = strlen(n->msg);
7329a747e4fSDavid du Colombier if(l > ERRMAX-15) /* " pc=0x12345678\0" */
7339a747e4fSDavid du Colombier l = ERRMAX-15;
7349a747e4fSDavid du Colombier sprint(n->msg+l, " pc=0x%.8lux", ur->pc);
7359a747e4fSDavid du Colombier }
7369a747e4fSDavid du Colombier
7379a747e4fSDavid du Colombier if(n->flag!=NUser && (up->notified || up->notify==0)){
7389a747e4fSDavid du Colombier if(n->flag == NDebug)
7399a747e4fSDavid du Colombier pprint("suicide: %s\n", n->msg);
7409a747e4fSDavid du Colombier qunlock(&up->debug);
7419a747e4fSDavid du Colombier pexit(n->msg, n->flag!=NDebug);
7429a747e4fSDavid du Colombier }
7439a747e4fSDavid du Colombier
7449a747e4fSDavid du Colombier if(up->notified) {
7459a747e4fSDavid du Colombier qunlock(&up->debug);
7469a747e4fSDavid du Colombier splhi();
7479a747e4fSDavid du Colombier return 0;
7489a747e4fSDavid du Colombier }
7499a747e4fSDavid du Colombier
7509a747e4fSDavid du Colombier if(!up->notify) {
7519a747e4fSDavid du Colombier qunlock(&up->debug);
7529a747e4fSDavid du Colombier pexit(n->msg, n->flag!=NDebug);
7539a747e4fSDavid du Colombier }
7549a747e4fSDavid du Colombier sp = ur->usp & ~(BY2V-1);
7559a747e4fSDavid du Colombier sp -= sizeof(Ureg);
7569a747e4fSDavid du Colombier
7579a747e4fSDavid du Colombier if(!okaddr((ulong)up->notify, BY2WD, 0) ||
7589a747e4fSDavid du Colombier !okaddr(sp-ERRMAX-4*BY2WD, sizeof(Ureg)+ERRMAX+4*BY2WD, 1)) {
7599a747e4fSDavid du Colombier pprint("suicide: bad address or sp in notify\n");
7609a747e4fSDavid du Colombier qunlock(&up->debug);
7619a747e4fSDavid du Colombier pexit("Suicide", 0);
7629a747e4fSDavid du Colombier }
7639a747e4fSDavid du Colombier
7649a747e4fSDavid du Colombier memmove((Ureg*)sp, ur, sizeof(Ureg));
7659a747e4fSDavid du Colombier *(Ureg**)(sp-BY2WD) = up->ureg; /* word under Ureg is old up->ureg */
7669a747e4fSDavid du Colombier up->ureg = (void*)sp;
7679a747e4fSDavid du Colombier sp -= BY2WD+ERRMAX;
7689a747e4fSDavid du Colombier memmove((char*)sp, up->note[0].msg, ERRMAX);
7699a747e4fSDavid du Colombier sp -= 3*BY2WD;
7709a747e4fSDavid du Colombier *(ulong*)(sp+2*BY2WD) = sp+3*BY2WD; /* arg 2 is string */
7719a747e4fSDavid du Colombier ur->r1 = (long)up->ureg; /* arg 1 is ureg* */
7729a747e4fSDavid du Colombier ((ulong*)sp)[1] = (ulong)up->ureg; /* arg 1 0(FP) is ureg* */
7739a747e4fSDavid du Colombier ((ulong*)sp)[0] = 0; /* arg 0 is pc */
7749a747e4fSDavid du Colombier ur->usp = sp;
7759a747e4fSDavid du Colombier ur->pc = (ulong)up->notify;
7769a747e4fSDavid du Colombier up->notified = 1;
7779a747e4fSDavid du Colombier up->nnote--;
7789a747e4fSDavid du Colombier memmove(&up->lastnote, &up->note[0], sizeof(Note));
7799a747e4fSDavid du Colombier memmove(&up->note[0], &up->note[1], up->nnote*sizeof(Note));
7809a747e4fSDavid du Colombier
7819a747e4fSDavid du Colombier qunlock(&up->debug);
7829a747e4fSDavid du Colombier splx(s);
7839a747e4fSDavid du Colombier return 1;
7849a747e4fSDavid du Colombier }
7859a747e4fSDavid du Colombier
7869a747e4fSDavid du Colombier
7879a747e4fSDavid du Colombier /*
7889a747e4fSDavid du Colombier * Return user to state before notify()
7899a747e4fSDavid du Colombier */
7909a747e4fSDavid du Colombier void
noted(Ureg * ureg,ulong arg0)7919a747e4fSDavid du Colombier noted(Ureg* ureg, ulong arg0)
7929a747e4fSDavid du Colombier {
7939a747e4fSDavid du Colombier Ureg *nureg;
7949a747e4fSDavid du Colombier ulong oureg, sp;
7959a747e4fSDavid du Colombier
7969a747e4fSDavid du Colombier qlock(&up->debug);
7979a747e4fSDavid du Colombier if(arg0!=NRSTR && !up->notified) {
7989a747e4fSDavid du Colombier qunlock(&up->debug);
7999a747e4fSDavid du Colombier pprint("call to noted() when not notified\n");
8009a747e4fSDavid du Colombier pexit("Suicide", 0);
8019a747e4fSDavid du Colombier }
8029a747e4fSDavid du Colombier up->notified = 0;
8039a747e4fSDavid du Colombier
8049a747e4fSDavid du Colombier nureg = up->ureg; /* pointer to user returned Ureg struct */
8059a747e4fSDavid du Colombier
8069a747e4fSDavid du Colombier /* sanity clause */
8079a747e4fSDavid du Colombier oureg = (ulong)nureg;
8089a747e4fSDavid du Colombier if(!okaddr((ulong)oureg-BY2WD, BY2WD+sizeof(Ureg), 0)){
8099a747e4fSDavid du Colombier pprint("bad ureg in noted or call to noted when not notified\n");
8109a747e4fSDavid du Colombier qunlock(&up->debug);
8119a747e4fSDavid du Colombier pexit("Suicide", 0);
8129a747e4fSDavid du Colombier }
8139a747e4fSDavid du Colombier
8149a747e4fSDavid du Colombier memmove(ureg, nureg, sizeof(Ureg));
8159a747e4fSDavid du Colombier
8169a747e4fSDavid du Colombier switch(arg0){
8179a747e4fSDavid du Colombier case NCONT:
8189a747e4fSDavid du Colombier case NRSTR:
8199a747e4fSDavid du Colombier if(!okaddr(nureg->pc, 1, 0) || !okaddr(nureg->usp, BY2WD, 0)){
8209a747e4fSDavid du Colombier pprint("suicide: trap in noted\n");
8219a747e4fSDavid du Colombier qunlock(&up->debug);
8229a747e4fSDavid du Colombier pexit("Suicide", 0);
8239a747e4fSDavid du Colombier }
8249a747e4fSDavid du Colombier up->ureg = (Ureg*)(*(ulong*)(oureg-BY2WD));
8259a747e4fSDavid du Colombier qunlock(&up->debug);
8269a747e4fSDavid du Colombier break;
8279a747e4fSDavid du Colombier
8289a747e4fSDavid du Colombier case NSAVE:
8299a747e4fSDavid du Colombier if(!okaddr(nureg->pc, BY2WD, 0)
8309a747e4fSDavid du Colombier || !okaddr(nureg->usp, BY2WD, 0)){
8319a747e4fSDavid du Colombier pprint("suicide: trap in noted\n");
8329a747e4fSDavid du Colombier qunlock(&up->debug);
8339a747e4fSDavid du Colombier pexit("Suicide", 0);
8349a747e4fSDavid du Colombier }
8359a747e4fSDavid du Colombier qunlock(&up->debug);
8369a747e4fSDavid du Colombier sp = oureg-4*BY2WD-ERRMAX;
8379a747e4fSDavid du Colombier splhi();
8389a747e4fSDavid du Colombier ureg->sp = sp;
8399a747e4fSDavid du Colombier ((ulong*)sp)[1] = oureg; /* arg 1 0(FP) is ureg* */
8409a747e4fSDavid du Colombier ((ulong*)sp)[0] = 0; /* arg 0 is pc */
8419a747e4fSDavid du Colombier break;
8429a747e4fSDavid du Colombier
8439a747e4fSDavid du Colombier default:
8449a747e4fSDavid du Colombier pprint("unknown noted arg 0x%lux\n", arg0);
8459a747e4fSDavid du Colombier up->lastnote.flag = NDebug;
8469a747e4fSDavid du Colombier /* fall through */
8479a747e4fSDavid du Colombier
8489a747e4fSDavid du Colombier case NDFLT:
8499a747e4fSDavid du Colombier if(up->lastnote.flag == NDebug)
8509a747e4fSDavid du Colombier pprint("suicide: %s\n", up->lastnote.msg);
8519a747e4fSDavid du Colombier qunlock(&up->debug);
8529a747e4fSDavid du Colombier pexit(up->lastnote.msg, up->lastnote.flag!=NDebug);
8539a747e4fSDavid du Colombier }
8549a747e4fSDavid du Colombier }
855