From 0ce142868970528ddfa6f5e0d90abb5a43456db5 Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Sat, 23 Jan 1999 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 1999-01-23 --- mpc/clock.c | 14 +- mpc/devuart.c | 18 +- mpc/l.s | 34 +--- mpc/main.c | 20 +- mpc/mem.h | 24 ++- mpc/trap.c | 522 +++++++++++++++++++++++++++++++++++++++++++++----- 6 files changed, 526 insertions(+), 106 deletions(-) diff --git a/mpc/clock.c b/mpc/clock.c index 1beabcc2b724d9c0cec39d3571867673fbb54ec4..2263ca33b600dad96049a30ae93c2213e0b6d09c 100644 --- a/mpc/clock.c +++ b/mpc/clock.c @@ -70,7 +70,7 @@ clockinit(void) { long x, est; - est = m->cpuhz/1000; /* initial estimate */ + est = m->clockgen/1000; /* initial estimate */ m->delayloop = est; do { x = gettbl(); @@ -105,9 +105,13 @@ clockintr(Ureg *ur) } putdec(clkreload-v); + // keep alive for watchdog + m->iomem->swsr = 0x556c; + m->iomem->swsr = 0xaa39; + m->ticks++; // if(m->ticks%MS2TK(1000) == 0) -// m->bcsr[4] ^= DisableLamp; +// *(uchar*)(NIMMEM+0x2200) = (m->ticks/MS2TK(1000))&2; if(up) up->pc = ur->pc; @@ -130,12 +134,6 @@ clockintr(Ureg *ur) } } -void -clockcheck(void) -{ - /* called by ../port/taslock.c: reset watchdog here, if it's enabled */ -} - void clkprint(void) { diff --git a/mpc/devuart.c b/mpc/devuart.c index e58d71878b2e44671a775c65dae5128d1d5190b1..6b58071a26620914eb9ac4630e2825e6d7414f0b 100644 --- a/mpc/devuart.c +++ b/mpc/devuart.c @@ -297,7 +297,7 @@ smcsetup(Uart *up) smc->smcm = BSY|RXB|TXB; /* enable all possible interrupts */ up->smc = smc; smc->smcmr = ((1+8+1-1)<<11)|(2<<4); /* 8-bit, 1 stop, no parity; UART mode */ -// intrenable(VectorCPIC+4, smcuintr, up, BUSUNKNOWN); + intrenable(VectorCPIC+4, smcuintr, up, BUSUNKNOWN); smc->smcmr |= 3; /* enable rx/tx */ } @@ -763,10 +763,12 @@ static void txstart(Uart *p) { Block *b; - int n, flags; + int n, flags, s; + if(!p->cts || p->blocked || p->txb->status & BDReady) return; + if((b = p->outb) == nil){ if((b = qget(p->oq)) == nil) return; @@ -785,8 +787,8 @@ txstart(Uart *p) } } n = BLEN(b); - if(n <= 0) - print("txstart: 0\n"); +// if(n <= 0) +// print("txstart: 0\n"); if(p->bpc > 8){ /* half-word alignment and length if chars are long */ if(PADDR(b->rp)&1){ /* must be even if chars are long */ @@ -810,11 +812,8 @@ txstart(Uart *p) p->txb->addr = PADDR(b->rp); p->txb->length = n; eieio(); - p->txb->status = (p->txb->status & BDWrap) | flags | BDReady/*|BDInt */; + p->txb->status = (p->txb->status & BDWrap) | flags | BDReady | BDInt; eieio(); - - while(p->txb->status & BDReady) - flash(); } /* @@ -991,11 +990,11 @@ uartintr(Uart *p, int events) int dokick; BD *bd; Block *b; - if(events & BSY) p->overrun++; p->interrupts++; dokick = 0; +/* while(p->rxb != nil && ((bd = &p->rxb[p->rdrx])->status & BDEmpty) == 0){ if(p->mode) framedinput(p, bd); @@ -1006,6 +1005,7 @@ uartintr(Uart *p, int events) bd->status = (bd->status & BDWrap) | BDEmpty|BDInt; p->rdrx ^= 1; } +*/ if((bd = p->txb) != nil){ if((bd->status & BDReady) == 0){ ilock(&p->plock); diff --git a/mpc/l.s b/mpc/l.s index d1fc39849375a49d9e162953070caf0f6b346b73..2496cb8767ce689181eeb7f413001094daf74d33 100644 --- a/mpc/l.s +++ b/mpc/l.s @@ -131,6 +131,9 @@ clrmach: CMP R3, R4 BNE clrmach + MOVW R0, R(USER) + MOVW R0, 0(R(MACH)) + MOVW $edata(SB), R3 MOVW $end(SB), R4 ADD $4, R4 @@ -295,10 +298,10 @@ TEXT saveureg(SB), $-4 MOVW $0, R0 /* compiler/linker expect R0 to be zero */ MOVW MSR, R5 - OR $(MSR_IR|MSR_DR), R5 /* enable MMU */ +/* OR $(MSR_IR|MSR_DR), R5 /* enable MMU */ MOVW R5, SPR(SRR1) MOVW LR, R31 - OR $KZERO, R31 /* return PC in KSEG0 */ +/* OR $KZERO, R31 /* return PC in KSEG0 */ MOVW R31, SPR(SRR0) SYNC ISYNC @@ -527,22 +530,9 @@ TEXT trapvec(SB), $-4 traps: MOVW LR, R0 -pagefault: - -/* - * map data virtually and make space to save - */ MOVW R0, SPR(SAVEXX) /* vector */ MOVW R1, SPR(SAVER1) - SYNC - ISYNC - MOVW MSR, R0 - OR $(MSR_DR|MSR_ME), R0 /* make data space usable */ - SYNC - MOVW R0, MSR - MSRSYNC SUB $UREGSPACE, R1 - MOVW SPR(SRR0), R0 /* save SRR0/SRR1 now, since DLTB might be missing stack page */ MOVW R0, LR MOVW SPR(SRR1), R0 @@ -614,20 +604,6 @@ restoreureg: MOVW SPR(SAVER0), R0 RFI -TEXT powerdownled(SB), $0 - - MOVW $0x10002200,R11 - MOVW $0,R7 - MOVW R7,0(R11) - RETURN - -TEXT powerupled(SB), $0 - - MOVW $0x10002200,R11 - MOVW $2,R7 - MOVW R7,0(R11) - RETURN - GLOBL mach0+0(SB), $MACHSIZE GLOBL spltbl+0(SB), $4 GLOBL intrtbl+0(SB), $4 diff --git a/mpc/main.c b/mpc/main.c index 9ce763493885f1f08dd9b6cb78ab5f3f115a2eea..e9aded694b9f2975e2353c8ba20003099eb0dee1 100644 --- a/mpc/main.c +++ b/mpc/main.c @@ -30,21 +30,24 @@ flash(void) void main(void) { + int i; + machinit(); + clockinit(); confinit(); xinit(); + trapinit(); printinit(); cpminit(); uartinstall(); - print("hello world\n"); - - delay(100); +delay(500); + spllo(); + for(i=0; ; i++) { + print("hello again %d\n", i); + delay(100); + } reset(); - - *(uchar*)0 = 0; - for(;;) - ; } void @@ -133,7 +136,8 @@ iprint(char *fmt, ...) n = doprint(buf, buf+sizeof(buf), fmt, arg) - buf; va_end(arg); - print("%s", buf); +// putstrn(buf, n); +// uartwait(); return n; } diff --git a/mpc/mem.h b/mpc/mem.h index 3255302707299187649f8eda67c1d6f734fc4c43..243309f8f1b82579c9671d361dd2589759fcaf99 100644 --- a/mpc/mem.h +++ b/mpc/mem.h @@ -50,8 +50,30 @@ #define MSR_LE (1<<0) /* Little-Endian enable */ /* - * Traps + * Exception codes (trap vectors) */ +#define CRESET 0x01 +#define CMCHECK 0x02 +#define CDSI 0x03 +#define CISI 0x04 +#define CEI 0x05 +#define CALIGN 0x06 +#define CPROG 0x07 +#define CFPU 0x08 +#define CDEC 0x09 +#define CSYSCALL 0x0C +#define CTRACE 0x0D +#define CFPA 0x0E +/* rest are power-implementation dependent */ +#define CEMU 0x10 +#define CIMISS 0x11 +#define CDMISS 0x12 +#define CITLBE 0x13 +#define CDTLBE 0x14 +#define CDBREAK 0x1C +#define CIBREAK 0x1D +#define CPBREAK 0x1E +#define CDPORT 0x1F /* * Magic registers diff --git a/mpc/trap.c b/mpc/trap.c index f0e709558cfc5d232acc72d787c3184a0e3d8e93..5569e3d4daeb4a3b9e837fcd586fdfdf6fb47337 100644 --- a/mpc/trap.c +++ b/mpc/trap.c @@ -3,73 +3,439 @@ #include "mem.h" #include "dat.h" #include "fns.h" -#include "io.h" #include "ureg.h" +#include "io.h" #include "../port/error.h" -/* Give enough context in the ureg to produce a kernel stack for - * a sleeping process - */ +enum +{ + Maxhandler= 32+16, /* max number of interrupt handlers */ +}; + +typedef struct Handler Handler; +struct Handler +{ + void (*r)(Ureg*, void*); + void *arg; + Handler *next; + int edge; + int nintr; + ulong ticks; + int maxtick; +}; + +struct +{ + Handler *ivec[128]; + Handler h[Maxhandler]; + int free; +} halloc; + +void kernfault(Ureg*, int); + +char *excname[] = +{ + "reserved 0", + "system reset", + "machine check", + "data access", + "instruction access", + "external interrupt", + "alignment", + "program exception", + "floating-point unavailable", + "decrementer", + "i/o controller interface error", + "reserved B", + "system call", + "trace trap", + "floating point assist", + "reserved F", + "software emulation", + "ITLB miss", + "DTLB miss", + "ITLB error", + "DTLB error", + "reserved 15", + "reserved 16", + "reserved 17", + "reserved 18", + "reserved 19", + "reserved 1A", + "reserved 1B", + "data breakpoint", + "instruction breakpoint", + "peripheral breakpoint", + "development port", + /* the following are made up on a program exception */ + "floating point exception", /* 20: FPEXC */ + "illegal instruction", /* 21 */ + "privileged instruction", /* 22 */ + "trap", /* 23 */ + "illegal operation", /* 24 */ + "breakpoint", /* 25 */ +}; + +char *fpcause[] = +{ + "inexact operation", + "division by zero", + "underflow", + "overflow", + "invalid operation", +}; +char *fpexcname(Ureg*, ulong, char*); +#define FPEXPMASK 0xfff80300 /* Floating exception bits in fpscr */ + + +char *regname[]={ + "CAUSE", "SRR1", + "PC", "GOK", + "LR", "CR", + "XER", "CTR", + "R0", "R1", + "R2", "R3", + "R4", "R5", + "R6", "R7", + "R8", "R9", + "R10", "R11", + "R12", "R13", + "R14", "R15", + "R16", "R17", + "R18", "R19", + "R20", "R21", + "R22", "R23", + "R24", "R25", + "R26", "R27", + "R28", "R29", + "R30", "R31", +}; + void -setkernur(Ureg* ureg, Proc* p) +sethvec(int v, void (*r)(void)) { - ureg->pc = p->sched.pc; - ureg->sp = p->sched.sp+4; + ulong *vp, pa, o; + + vp = (ulong*)(0xfff00000+v); + vp[0] = 0x7c1043a6; /* MOVW R0, SPR(SPRG0) */ + vp[1] = 0x7c0802a6; /* MOVW LR, R0 */ + vp[2] = 0x7c1243a6; /* MOVW R0, SPR(SPRG2) */ + pa = PADDR(r); + o = pa >> 25; + if(o != 0 && o != 0x7F){ + /* a branch too far */ + vp[3] = (15<<26)|(pa>>16); /* MOVW $r&~0xFFFF, R0 */ + vp[4] = (24<<26)|(pa&0xFFFF); /* OR $r&0xFFFF, R0 */ + vp[5] = 0x7c0803a6; /* MOVW R0, LR */ + vp[6] = 0x4e800021; /* BL (LR) */ + }else + vp[3] = (18<<26)|(pa&0x3FFFFFC)|3; /* bla */ + dcflush(vp, 8*sizeof(ulong)); } -/* This routine must save the values of registers the user is not permitted to write - * from devproc and then restore the saved values before returning - */ void -setregisters(Ureg* ureg, char* pureg, char* uva, int n) +sethvec2(int v, void (*r)(void)) { - USED(ureg, pureg, uva, n); - panic("not done"); + ulong *vp; + + vp = (ulong*)KADDR(v); + vp[0] = (18<<26)|(PADDR(r))|2; /* ba */ + dcflush(vp, sizeof(*vp)); } void -dumpregs(Ureg* ureg) +trap(Ureg *ur) { - USED(ureg); - panic("not done"); + int ecode; + static struct {int callsched;} c = {1}; + + ecode = (ur->cause >> 8) & 0xff; + if(ecode < 0 || ecode >= 0x1F) + ecode = 0x1F; + switch(ecode){ + case CEI: + intr(ur); + break; + + case CDEC: + clockintr(ur); + break; + + case CMCHECK: + case CDSI: + case CISI: + case CIMISS: + case CDMISS: + case CITLBE: + case CDTLBE: + goto Default; + break; + + case CEMU: + print("pc=#%lux op=#%8.8lux\n", ur->pc, *(ulong*)ur->pc); + goto Default; + break; + + case CPROG: + if(ur->status & (1<<19)) + ecode = 0x20; + if(ur->status & (1<<18)) + ecode = 0x21; + if(ur->status & (1<<17)) + ecode = 0x22; + goto Default; + + Default: + default: + print("kernel %s pc=0x%lux\n", excname[ecode], ur->pc); + dumpregs(ur); + dumpstack(); + if(m->machno == 0) + spllo(); + exit(1); + } + + splhi(); } void -dumpstack(void) +spurious(Ureg *ur, void *a) { - panic("not done"); + USED(a); + print("SPURIOUS interrupt pc=0x%lux cause=0x%lux\n", + ur->pc, ur->cause); + panic("bad interrupt"); } -ulong -userpc(void) +#define LEV(n) (((n)<<1)|1) +#define IRQ(n) (((n)<<1)|0) + +Lock veclock; + +void +trapinit(void) { - Ureg *ureg; + int i; + IMM *io; - ureg = (Ureg*)up->dbgreg; - return ureg->pc; + + io = m->iomem; + io->sypcr &= ~(1<<3); /* disable watchdog (821/823) */ + io->simask = 0; /* mask all */ + io->siel = ~0; /* edge sensitive, wake on all */ + io->cicr = 0; /* disable CPM interrupts */ + io->cipr = ~0; /* clear all interrupts */ + io->cimr = 0; /* mask all events */ + io->cicr = (0xE1<<16)|(CPIClevel<<13)|(0x1F<<8); + io->cicr |= 1 << 7; /* enable */ + io->tbscr = 1; /* TBE */ + io->simask |= 1<<(31-LEV(CPIClevel)); /* CPM's level */ + eieio(); + putdec(~0); + + /* + * set all exceptions to trap + */ + for(i = 0x0; i < 0x3000; i += 0x100) + sethvec(i, trapvec); + + //sethvec(CEI<<8, intrvec); + //sethvec2(CIMISS<<8, itlbmiss); + //sethvec2(CDMISS<<8, dtlbmiss); } -ulong -dbgpc(Proc *p) +void +intrenable(int v, void (*r)(Ureg*, void*), void *arg, int) { - Ureg *ureg; + Handler *h; + IMM *io; - ureg = p->dbgreg; - if(ureg == 0) - return 0; + if(halloc.free >= Maxhandler) + panic("out of interrupt handlers"); + v -= VectorPIC; + if(v < 0 || v >= nelem(halloc.ivec)) + panic("intrenable(%d)", v+VectorPIC); + ilock(&veclock); + if(v < VectorCPIC || (h = halloc.ivec[v]) == nil){ + h = &halloc.h[halloc.free++]; + h->next = halloc.ivec[v]; + halloc.ivec[v] = h; + } + h->r = r; + h->arg = arg; - return ureg->pc; + /* + * enable corresponding interrupt in SIU/CPM + */ + + eieio(); + io = m->iomem; + if(v >= VectorCPIC){ + v -= VectorCPIC; + io->cimr |= 1<<(v&0x1F); + } + else if(v >= VectorIRQ) + io->simask |= 1<<(31-IRQ(v&7)); + else + io->simask |= 1<<(31-LEV(v)); + eieio(); + iunlock(&veclock); +} + +/* + * called directly by l.s:/intrvec + */ +void +intr(Ureg *ur) +{ + int b, v; + IMM *io; + Handler *h; + long t0; + + ur->cause &= ~0xff; + io = m->iomem; + b = io->sivec>>2; + v = b>>1; + if(b & 1) { + if(v == CPIClevel){ + io->civr = 1; + eieio(); + v = VectorCPIC+(io->civr>>11); + } + }else + v += VectorIRQ; + ur->cause |= v; + h = halloc.ivec[v]; + if(h == nil){ + print("unknown interrupt %d pc=0x%lux\n", v, ur->pc); + uartwait(); + return; + } + if(h->edge){ + io->sipend |= 1<<(31-b); + eieio(); + } + /* + * call the interrupt handlers + */ + do { + h->nintr++; + t0 = getdec(); + (*h->r)(ur, h->arg); + t0 -= getdec(); + h->ticks += t0; + if(h->maxtick < t0) + h->maxtick = t0; + h = h->next; + } while(h != nil); + if(v >= VectorCPIC) + io->cisr |= 1<<(v-VectorCPIC); + eieio(); +} + +int +intrstats(char *buf, int bsize) +{ + Handler *h; + int i, n; + + n = 0; + for(i=0; inintr) + n += snprint(buf+n, bsize-n, "%3d %lud %lud %lud\n", i, h->nintr, h->ticks, h->maxtick); + return n; +} + +char* +fpexcname(Ureg *ur, ulong fpscr, char *buf) +{ + int i; + char *s; + ulong fppc; + + fppc = ur->pc; + s = 0; + fpscr >>= 3; /* trap enable bits */ + fpscr &= (fpscr>>22); /* anded with exceptions */ + for(i=0; i<5; i++) + if(fpscr & (1<status, ur->pc, ur->sp); + dumpregs(ur); + l.sp = ur->sp; + l.pc = ur->pc; + dumpstack(); + for(;;) + sched(); +} + +void +dumpstack(void) +{ + ulong l, v; + int i; + + if(up == 0) + return; + i = 0; + for(l=(ulong)&l; l<(ulong)(up->kstack+KSTACK); l+=4){ + v = *(ulong*)l; + if(KTZERO < v && v < (ulong)etext){ + print("%lux=%lux, ", l, v); + if(i++ == 4){ + print("\n"); + i = 0; + } + } + } +} + +void +dumpregs(Ureg *ur) +{ + int i; + ulong *l; + if(up) { + print("registers for %s %d\n", up->text, up->pid); + if(ur->usp < (ulong)up->kstack || + ur->usp > (ulong)up->kstack+KSTACK) + print("invalid stack ptr\n"); + } + else + print("registers for kernel\n"); + + print("dsisr\t%.8lux\tdar\t%.8lux\n", getdsisr(), getdar()); + l = &ur->cause; + for(i=0; ikpfun(up->kparg); + (*up->kpfun)(up->kparg); + pexit("", 0); } void -kprocchild(Proc* p, void (*func)(void*), void* arg) +kprocchild(Proc *p, void (*func)(void*), void *arg) { p->sched.pc = (ulong)linkproc; p->sched.sp = (ulong)p->kstack+KSTACK; @@ -78,10 +444,28 @@ kprocchild(Proc* p, void (*func)(void*), void* arg) p->kparg = arg; } +int +isvalid_pc(ulong pc) +{ + return KERNPC(pc) && (pc&3) == 0; +} + +void +dumplongs(char*, ulong*, int) +{ +} + void -forkchild(Proc *p, Ureg *ureg) +reset(void) { - USED(p, ureg); + IMM *io; + + io = m->iomem; + io->plprcrk = KEEP_ALIVE_KEY; // unlock + io->plprcr |= IBIT(24); // enable checkstop reset + putmsr(getmsr() & ~MSR_ME); + // cause checkstop -> causes reset + *(ulong*)(0) = 0; } /* @@ -112,35 +496,71 @@ execregs(ulong entry, ulong ssize, ulong nargs) } void -trap(Ureg *ur) +forkchild(Proc *p, Ureg *ur) { - USED(ur); + Ureg *cur; + + p->sched.sp = (ulong)p->kstack+KSTACK-UREGSIZE; + p->sched.pc = (ulong)forkret; + + cur = (Ureg*)(p->sched.sp+2*BY2WD); + memmove(cur, ur, sizeof(Ureg)); + + cur->pc += 4; + + /* Things from bottom of syscall we never got to execute */ + p->psstate = 0; + p->insyscall = 0; } -/* - * called directly by l.s:/intrvec +ulong +userpc(void) +{ + Ureg *ureg; + + ureg = (Ureg*)up->dbgreg; + return ureg->pc; +} + + +// need to be in l.s +void +forkret(void) +{ + panic("forkret"); +} +/* This routine must save the values of registers the user is not + * permitted to write from devproc and then restore the saved values + * before returning */ void -intr(Ureg *ur) +setregisters(Ureg *xp, char *pureg, char *uva, int n) { - USED(ur); + ulong status; + + status = xp->status; + memmove(pureg, uva, n); + xp->status = status; } +/* Give enough context in the ureg to produce a kernel stack for + * a sleeping process + */ void -intrenable(int v, void (*r)(Ureg*, void*), void *arg, int) +setkernur(Ureg* ureg, Proc* p) { - USED(v, r, arg); + ureg->pc = p->sched.pc; + ureg->sp = p->sched.sp+4; } -void -reset(void) +ulong +dbgpc(Proc *p) { - IMM *io; + Ureg *ureg; - io = m->iomem; - io->plprcrk = KEEP_ALIVE_KEY; // unlock - io->plprcr |= IBIT(24); // enable checkstop reset - putmsr(getmsr() & ~MSR_ME); - // cause checkstop -> causes reset - *(ulong*)(0) = 0; + ureg = p->dbgreg; + if(ureg == 0) + return 0; + + return ureg->pc; }