From 551d878a4d92a0f60889d81b0ca8b228a8781d79 Mon Sep 17 00:00:00 2001 From: David du Colombier <0intro@gmail.com> Date: Thu, 21 Jan 1999 00:00:00 +0000 Subject: [PATCH] Plan 9 from Bell Labs 1999-01-21 --- carrera/l.s | 1 + mpc/clock.c | 152 ++++++++++++ mpc/cpm.c | 563 +++++++++++++++++++++++++++++++++++++++++ mpc/dat.h | 217 ++++++++++++++++ mpc/devether.c | 447 +++++++++++++++++++++++++++++++++ mpc/devrtc.c | 180 ++++++++++++++ mpc/etherif.h | 28 +++ mpc/fns.h | 91 +++++++ mpc/io.h | 556 +++++++++++++++++++++++++++++++++++++++++ mpc/l.s | 663 +++++++++++++++++++++++++++++++++++++++++++++++++ mpc/main.c | 190 ++++++++++++++ mpc/mem.h | 156 ++++++++++++ mpc/mmu.c | 68 +++++ mpc/rmap.c | 106 ++++++++ mpc/segment.h | 8 + mpc/trap.c | 133 ++++++++++ 16 files changed, 3559 insertions(+) create mode 100644 mpc/clock.c create mode 100644 mpc/cpm.c create mode 100644 mpc/dat.h create mode 100644 mpc/devether.c create mode 100644 mpc/devrtc.c create mode 100644 mpc/etherif.h create mode 100644 mpc/fns.h create mode 100644 mpc/io.h create mode 100644 mpc/l.s create mode 100644 mpc/main.c create mode 100644 mpc/mem.h create mode 100644 mpc/mmu.c create mode 100644 mpc/rmap.c create mode 100644 mpc/segment.h create mode 100644 mpc/trap.c diff --git a/carrera/l.s b/carrera/l.s index c7e8594e438349c5b35d85afc9efacbfc438dcfb..39c583e516e59ae9a76836cda0908e2e307d7192 100644 --- a/carrera/l.s +++ b/carrera/l.s @@ -103,6 +103,7 @@ TEXT splhi(SB), $0 TEXT splx(SB), $0 MOVW R31, 12(R(MACH)) /* save PC in m->splpc */ + /* fall though */ TEXT splxpc(SB), $0 /* for iunlock */ MOVW M(STATUS), R2 diff --git a/mpc/clock.c b/mpc/clock.c new file mode 100644 index 0000000000000000000000000000000000000000..a4102af6f3cf8bd90a6f114304591fa510dbc32e --- /dev/null +++ b/mpc/clock.c @@ -0,0 +1,152 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" +#include "ureg.h" + +typedef struct Clock0link Clock0link; +typedef struct Clock0link { + void (*clock)(void); + Clock0link* link; +} Clock0link; + +static Clock0link *clock0link; +static Lock clock0lock; +ulong clkrelinq; +void (*kproftick)(ulong); /* set by devkprof.c when active */ +long clkvv; +ulong clkhigh; + +void +addclock0link(void (*clock)(void)) +{ + Clock0link *lp; + + if((lp = malloc(sizeof(Clock0link))) == 0){ + print("addclock0link: too many links\n"); + return; + } + ilock(&clock0lock); + lp->clock = clock; + lp->link = clock0link; + clock0link = lp; + iunlock(&clock0lock); +} + +void +delay(int l) +{ + ulong i, j; + + j = m->delayloop; + while(l-- > 0) + for(i=0; i < j; i++) + ; +} + +void +microdelay(int l) +{ + ulong i; + + l *= m->delayloop; + l /= 1000; + if(l <= 0) + l = 1; + for(i = 0; i < l; i++) + ; +} + +enum { + Timebase = 4, /* system clock cycles per time base cycle */ +}; + +static ulong clkreload; + +void +clockinit(void) +{ + long x, est; + + est = m->cpuhz/1000; /* initial estimate */ + m->delayloop = est; + do { + x = gettbl(); + delay(10); + x = gettbl() - x; + } while(x < 0); + + /* + * fix count + */ + m->delayloop = (m->delayloop*10*est)/(x*Timebase); + if(m->delayloop == 0) + m->delayloop = 1; + + clkreload = (m->clockgen/Timebase)/HZ-1; + putdec(clkreload); +} + +void +clockintr(Ureg *ur) +{ + Clock0link *lp; + long v; + + v = (clkvv = -getdec()); + if(v > clkreload) + clkhigh++; + if(v > clkreload/2){ + if(v > clkreload) + m->ticks += v/clkreload; + v = 0; + } + putdec(clkreload-v); + + m->ticks++; + if(m->ticks%MS2TK(1000) == 0) + m->bcsr[4] ^= DisableLamp; + + if(up) + up->pc = ur->pc; + + checkalarms(); + if(m->machno == 0) { + if(kproftick != nil) + (*kproftick)(ur->pc); + lock(&clock0lock); + for(lp = clock0link; lp; lp = lp->link) + lp->clock(); + unlock(&clock0lock); + } + + if(up && up->state == Running){ +// if(up->type == Interp && tready()) +// ur->cr |= 1<<(31-31); + if(nrdy > 0) + sched(); + } +} + +void +clockcheck(void) +{ + /* called by ../port/taslock.c: reset watchdog here, if it's enabled */ +} + +void +clkprint(void) +{ + print("clkr=%ld clkvv=%ld clkhigh=%lud\n", clkreload, clkvv, clkhigh); + print("\n"); +} + +uvlong +fastticks(uvlong *hz) +{ + if(hz) + *hz = HZ; + return m->ticks; +} diff --git a/mpc/cpm.c b/mpc/cpm.c new file mode 100644 index 0000000000000000000000000000000000000000..bbb94097447a0582371de8523500200de784e360 --- /dev/null +++ b/mpc/cpm.c @@ -0,0 +1,563 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" + +enum { + BDSIZE= 1024, /* IO memory reserved for buffer descriptors */ + CPMSIZE= 1024, /* IO memory reserved for other uses */ +}; + +static Map bdmapv[BDSIZE/sizeof(BD)]; +static RMap bdmap = {"buffer descriptors"}; + +static Map cpmmapv[CPMSIZE/sizeof(ulong)]; +static RMap cpmmap = {"CPM memory"}; + +static Lock cpmlock; + +static struct { + Lock; + ulong avail; +} brgens; + +static struct { + Lock; + ulong clash; /* disable bits for mutually-exclusive options */ + ulong active; /* disable bit for current owner, or 0 */ + void (*stop)(void*); + void* arg; +} scc2owner; + +static void i2cspireloc(void); + +/* + * initialise the communications processor module + * and associated device registers + */ +void +cpminit(void) +{ + IMM *io; + + io = m->iomem; + io->rccr = 0; + io->rmds = 0; + io->lccr &= ~1; /* disable LCD */ + io->sdcr = 1; + io->pcint = 0; /* disable all port C interrupts */ + io->pcso = 0; + io->pcdir =0; + io->pcpar = 0; + io->papar = 0; + io->padir = 0; + io->pbpar = 0; + io->pbdir = 0; + io->tgcr = 0x2222; /* reset timers, low-power stop */ + eieio(); + + for(io->cpcr = 0x8001; io->cpcr & 1;) /* reset all CPM channels */ + eieio(); + + mapinit(&bdmap, bdmapv, sizeof(bdmapv)); + mapfree(&bdmap, DPBASE, BDSIZE); + mapinit(&cpmmap, cpmmapv, sizeof(cpmmapv)); + mapfree(&cpmmap, DPBASE+BDSIZE, CPMSIZE); + + if(m->cputype == 0x50 && (getimmr() & 0xFFFF) <= 0x2001) + brgens.avail = 0x3; + else + brgens.avail = 0xF; + + scc2owner.clash = DisableEther|DisableIR|DisableRS232b; + + i2cspireloc(); +} + +/* + * issue a request to a CPM device + */ +void +cpmop(int op, int cno, int param) +{ + IMM *io; + + ilock(&cpmlock); + io = m->iomem; + while(io->cpcr & 1) + eieio(); + io->cpcr = (op<<8)|(cno<<4)|(param<<1)|1; + eieio(); + while(io->cpcr & 1) + eieio(); + iunlock(&cpmlock); +} + +/* + * lock the shared IO memory and return a reference to it + */ +IMM* +ioplock(void) +{ + ilock(&cpmlock); + return m->iomem; +} + +/* + * release the lock on the shared IO memory + */ +void +iopunlock(void) +{ + eieio(); + iunlock(&cpmlock); +} + +/* + * connect SCCx clocks in NSMI mode (x=1 for USB) + */ +void +sccnmsi(int x, int rcs, int tcs) +{ + IMM *io; + ulong v; + int sh; + + sh = (x-1)*8; /* each SCCx field in sicr is 8 bits */ + v = (((rcs&7)<<3) | (tcs&7)) << sh; + io = ioplock(); + io->sicr = (io->sicr & ~(0xFF<bcsr[1] & clash){ + if(!force){ + iunlock(&scc2owner); + return 0; + } + /* notify current owner */ + if(scc2owner.stop) + scc2owner.stop(scc2owner.arg); + m->bcsr[1] |= clash; + } + scc2owner.stop = stop; + scc2owner.arg = arg; + scc2owner.active = enable; + m->bcsr[1] &= ~enable; /* the bits are active low */ + iunlock(&scc2owner); + /* beware: someone else can claim it during the `successful' return */ + return 1; +} + +/* + * if SCC2 is currently enabled, shut it down + */ +void +scc2stop(void *a) +{ + SCC *scc; + + scc = a; + if(scc->gsmrl & (3<<4)){ + cpmop(GracefulStopTx, SCC2ID, 0); + cpmop(CloseRxBD, SCC2ID, 0); + delay(1); + scc->gsmrl &= ~(3<<4); /* disable current use */ + m->bcsr[1] |= scc2owner.clash; + } +} + +/* + * yield up control of SCC2 + */ +void +scc2free(void) +{ + ilock(&scc2owner); + m->bcsr[1] |= scc2owner.active; + scc2owner.active = 0; + iunlock(&scc2owner); +} + +/* + * allocate a buffer descriptor + */ +BD * +bdalloc(int n) +{ + ulong a; + + a = rmapalloc(&bdmap, 0, n*sizeof(BD), sizeof(BD)); + if(a == 0) + panic("bdalloc"); + return KADDR(a); +} + +/* + * free a buffer descriptor + */ +void +bdfree(BD *b, int n) +{ + if(b){ + eieio(); + mapfree(&bdmap, PADDR(b), n*sizeof(BD)); + } +} + +/* + * allocate memory from the shared IO memory space + */ +void * +cpmalloc(int n, int align) +{ + ulong a; + + a = rmapalloc(&cpmmap, 0, n, align); + if(a == 0) + panic("cpmalloc"); + return KADDR(a); +} + +/* + * free previously allocated shared memory + */ +void +cpmfree(void *p, int n) +{ + if(p != nil && n > 0){ + eieio(); + mapfree(&cpmmap, PADDR(p), n); + } +} + +/* + * allocate a baud rate generator, returning its index + * (or -1 if none is available) + */ +int +brgalloc(void) +{ + int n; + + lock(&brgens); + for(n=0; brgens.avail!=0; n++) + if(brgens.avail & (1<= 0){ + if(n > 3 || brgens.avail & (1<cpuhz+rate)/(2*rate) - 1; + if(d < 0) + d = 0; + if(d >= (1<<12)) + return ((d+15)>>(4-1))|1; /* divider too big: enable prescale by 16 */ + return d<<1; +} + +/* + * initialise receive and transmit buffer rings. + */ +int +ioringinit(Ring* r, int nrdre, int ntdre, int bufsize) +{ + int i, x; + + /* the ring entries must be aligned on sizeof(BD) boundaries */ + r->nrdre = nrdre; + if(r->rdr == nil) + r->rdr = bdalloc(nrdre); + if(r->rrb == nil) + r->rrb = malloc(nrdre*bufsize); + dcflush(r->rrb, nrdre*bufsize); + if(r->rdr == nil || r->rrb == nil) + return -1; + x = PADDR(r->rrb); + for(i = 0; i < nrdre; i++){ + r->rdr[i].length = 0; + r->rdr[i].addr = x; + r->rdr[i].status = BDEmpty|BDInt; + x += bufsize; + } + r->rdr[i-1].status |= BDWrap; + r->rdrx = 0; + + r->ntdre = ntdre; + if(r->tdr == nil) + r->tdr = bdalloc(ntdre); + if(r->txb == nil) + r->txb = malloc(ntdre*sizeof(Block*)); + if(r->tdr == nil || r->txb == nil) + return -1; + for(i = 0; i < ntdre; i++){ + r->txb[i] = nil; + r->tdr[i].addr = 0; + r->tdr[i].length = 0; + r->tdr[i].status = 0; + } + r->tdr[i-1].status |= BDWrap; + r->tdrh = 0; + r->tdri = 0; + r->ntq = 0; + return 0; +} + +/* + * Allocate a new parameter block for I2C or SPI, + * and plant a pointer to it for the microcode, + * returning the kernel address. + * See motorola errata and microcode package: + * the design botch is that the parameters for the SCC2 ethernet overlap the + * SPI/I2C parameter space; this compensates by relocating the latter. + * This routine may be used iff i2cspireloc is used (and it is, above). + */ +void* +cpmparam(ulong olda, int nb) +{ + void *p; + + if(olda < INTMEM) + olda += INTMEM; + if(olda != SPIP && olda != I2CP) + return KADDR(olda); + p = cpmalloc(nb, 32); /* ``RPBASE must be multiple of 32'' */ + if(p == nil) + return p; + *(ushort*)KADDR(olda+0x2C) = PADDR(p); /* set RPBASE */ + eieio(); + return p; +} + +/* + * I2C/SPI microcode package from Motorola + * (to relocate I2C/SPI parameters), which was distributed + * on their web site in S-record format. + * + * May 1998 + */ + +/*S00600004844521B*/ +static ulong ubase1 = 0x2000; +static ulong ucode1[] = { + /* #02202000 */ 0x7FFFEFD9, + /* #02202004 */ 0x3FFD0000, + /* #02202008 */ 0x7FFB49F7, + /* #0220200C */ 0x7FF90000, + /* #02202010 */ 0x5FEFADF7, + /* #02202014 */ 0x5F89ADF7, + /* #02202018 */ 0x5FEFAFF7, + /* #0220201C */ 0x5F89AFF7, + /* #02202020 */ 0x3A9CFBC8, + /* #02202024 */ 0xE7C0EDF0, + /* #02202028 */ 0x77C1E1BB, + /* #0220202C */ 0xF4DC7F1D, + /* #02202030 */ 0xABAD932F, + /* #02202034 */ 0x4E08FDCF, + /* #02202038 */ 0x6E0FAFF8, + /* #0220203C */ 0x7CCF76CF, + /* #02202040 */ 0xFD1FF9CF, + /* #02202044 */ 0xABF88DC6, + /* #02202048 */ 0xAB5679F7, + /* #0220204C */ 0xB0937383, + /* #02202050 */ 0xDFCE79F7, + /* #02202054 */ 0xB091E6BB, + /* #02202058 */ 0xE5BBE74F, + /* #0220205C */ 0xB3FA6F0F, + /* #02202060 */ 0x6FFB76CE, + /* #02202064 */ 0xEE0DF9CF, + /* #02202068 */ 0x2BFBEFEF, + /* #0220206C */ 0xCFEEF9CF, + /* #02202070 */ 0x76CEAD24, + /* #02202074 */ 0x90B2DF9A, + /* #02202078 */ 0x7FDDD0BF, + /* #0220207C */ 0x4BF847FD, + /* #02202080 */ 0x7CCF76CE, + /* #02202084 */ 0xCFEF7E1F, + /* #02202088 */ 0x7F1D7DFD, + /* #0220208C */ 0xF0B6EF71, + /* #02202090 */ 0x7FC177C1, + /* #02202094 */ 0xFBC86079, + /* #02202098 */ 0xE722FBC8, + /* #0220209C */ 0x5FFFDFFF, + /* #022020A0 */ 0x5FB2FFFB, + /* #022020A4 */ 0xFBC8F3C8, + /* #022020A8 */ 0x94A67F01, + /* #022020AC */ 0x7F1D5F39, + /* #022020B0 */ 0xAFE85F5E, + /* #022020B4 */ 0xFFDFDF96, + /* #022020B8 */ 0xCB9FAF7D, + /* #022020BC */ 0x5FC1AFED, + /* #022020C0 */ 0x8C1C5FC1, + /* #022020C4 */ 0xAFDD5FC3, + /* #022020C8 */ 0xDF9A7EFD, + /* #022020CC */ 0xB0B25FB2, + /* #022020D0 */ 0xFFFEABAD, + /* #022020D4 */ 0x5FB2FFFE, + /* #022020D8 */ 0x5FCE600B, + /* #022020DC */ 0xE6BB600B, + /* #022020E0 */ 0x5FCEDFC6, + /* #022020E4 */ 0x27FBEFDF, + /* #022020E8 */ 0x5FC8CFDE, + /* #022020EC */ 0x3A9CE7C0, + /* #022020F0 */ 0xEDF0F3C8, + /* #022020F4 */ 0x7F0154CD, + /* #022020F8 */ 0x7F1D2D3D, + /* #022020FC */ 0x363A7570, + /* #02202100 */ 0x7E0AF1CE, + /* #02202104 */ 0x37EF2E68, + /* #02202108 */ 0x7FEE10EC, + /* #0220210C */ 0xADF8EFDE, + /* #02202110 */ 0xCFEAE52F, + /* #02202114 */ 0x7D0FE12B, + /* #02202118 */ 0xF1CE5F65, + /* #0220211C */ 0x7E0A4DF8, + /* #02202120 */ 0xCFEA5F72, + /* #02202124 */ 0x7D0BEFEE, + /* #02202128 */ 0xCFEA5F74, + /* #0220212C */ 0xE522EFDE, + /* #02202130 */ 0x5F74CFDA, + /* #02202134 */ 0x0B627385, + /* #02202138 */ 0xDF627E0A, + /* #0220213C */ 0x30D8145B, + /* #02202140 */ 0xBFFFF3C8, + /* #02202144 */ 0x5FFFDFFF, + /* #02202148 */ 0xA7F85F5E, + /* #0220214C */ 0xBFFE7F7D, + /* #02202150 */ 0x10D31450, + /* #02202154 */ 0x5F36BFFF, + /* #02202158 */ 0xAF785F5E, + /* #0220215C */ 0xBFFDA7F8, + /* #02202160 */ 0x5F36BFFE, + /* #02202164 */ 0x77FD30C0, + /* #02202168 */ 0x4E08FDCF, + /* #0220216C */ 0xE5FF6E0F, + /* #02202170 */ 0xAFF87E1F, + /* #02202174 */ 0x7E0FFD1F, + /* #02202178 */ 0xF1CF5F1B, + /* #0220217C */ 0xABF80D5E, + /* #02202180 */ 0x5F5EFFEF, + /* #02202184 */ 0x79F730A2, + /* #02202188 */ 0xAFDD5F34, + /* #0220218C */ 0x47F85F34, + /* #02202190 */ 0xAFED7FDD, + /* #02202194 */ 0x50B24978, + /* #02202198 */ 0x47FD7F1D, + /* #0220219C */ 0x7DFD70AD, + /* #022021A0 */ 0xEF717EC1, + /* #022021A4 */ 0x6BA47F01, + /* #022021A8 */ 0x2D267EFD, + /* #022021AC */ 0x30DE5F5E, + /* #022021B0 */ 0xFFFD5F5E, + /* #022021B4 */ 0xFFEF5F5E, + /* #022021B8 */ 0xFFDF0CA0, + /* #022021BC */ 0xAFED0A9E, + /* #022021C0 */ 0xAFDD0C3A, + /* #022021C4 */ 0x5F3AAFBD, + /* #022021C8 */ 0x7FBDB082, + /* #022021CC */ 0x5F8247F8, +}; + +/*S00600004844521B*/ +static ulong ubase2 = 0x2F00; +static ulong ucode2[] = { + /* #02202F00 */ 0x3E303430, + /* #02202F04 */ 0x34343737, + /* #02202F08 */ 0xABF7BF9B, + /* #02202F0C */ 0x994B4FBD, + /* #02202F10 */ 0xBD599493, + /* #02202F14 */ 0x349FFF37, + /* #02202F18 */ 0xFB9B177D, + /* #02202F1C */ 0xD9936956, + /* #02202F20 */ 0xBBFDD697, + /* #02202F24 */ 0xBDD2FD11, + /* #02202F28 */ 0x31DB9BB3, + /* #02202F2C */ 0x63139637, + /* #02202F30 */ 0x93733693, + /* #02202F34 */ 0x193137F7, + /* #02202F38 */ 0x331737AF, + /* #02202F3C */ 0x7BB9B999, + /* #02202F40 */ 0xBB197957, + /* #02202F44 */ 0x7FDFD3D5, + /* #02202F48 */ 0x73B773F7, + /* #02202F4C */ 0x37933B99, + /* #02202F50 */ 0x1D115316, + /* #02202F54 */ 0x99315315, + /* #02202F58 */ 0x31694BF4, + /* #02202F5C */ 0xFBDBD359, + /* #02202F60 */ 0x31497353, + /* #02202F64 */ 0x76956D69, + /* #02202F68 */ 0x7B9D9693, + /* #02202F6C */ 0x13131979, + /* #02202F70 */ 0x79376935, +}; + +/* + * compensate for chip design botch by installing + * microcode to relocate I2C and SPI parameters away + * from the ethernet parameters + */ +static void +i2cspireloc(void) +{ + IMM *io; + static int done; + + if(done) + return; + io = m->iomem; + io->rccr &= ~3; + memmove((uchar*)m->iomem+ubase1, ucode1, sizeof(ucode1)); + memmove((uchar*)m->iomem+ubase2, ucode2, sizeof(ucode2)); + io->rctr1 = 0x802a; /* relocate SPI */ + io->rctr2 = 0x8028; /* relocate SPI */ + io->rctr3 = 0x802e; /* relocate I2C */ + io->rctr4 = 0x802c; /* relocate I2C */ + io->rccr |= 1; + done = 1; +} diff --git a/mpc/dat.h b/mpc/dat.h new file mode 100644 index 0000000000000000000000000000000000000000..0e92ca92fc5eb9ee33d8a30dc85bd54c84df69ad --- /dev/null +++ b/mpc/dat.h @@ -0,0 +1,217 @@ +typedef struct Conf Conf; +typedef struct FPsave FPsave; +typedef struct IMM IMM; +typedef struct Irqctl Irqctl; +typedef struct ISAConf ISAConf; +typedef struct Label Label; +typedef struct Lock Lock; +typedef struct Mach Mach; +typedef struct Notsave Notsave; +typedef struct PMMU PMMU; +typedef struct Map Map; +typedef struct PCArch PCArch; +typedef struct Proc Proc; +typedef struct RMap RMap; +typedef struct Ureg Ureg; + +#define MACHP(n) (n==0? &mach0 : *(Mach**)0) + +/* + * parameters for sysproc.c + */ +#define AOUT_MAGIC (Q_MAGIC) + + +struct Lock +{ + ulong key; + ulong pc; + ulong sr; + Proc *p; + ushort isilock; +}; + +struct Label +{ + ulong sp; + ulong pc; +}; + +/* + * things saved in the Proc structure during a notify + */ +struct Notsave +{ + ulong UNUSED; +}; + +/* + * MMU stuff in proc + */ +#define NCOLOR 1 +struct PMMU +{ + ulong UNUSED; +}; + +/* + * FPsave.status + */ +enum +{ + FPinit, + FPactive, + FPinactive, +}; + +/* + * This structure must agree with fpsave and fprestore asm routines + */ +struct FPsave +{ + double fpreg[32]; + union { + double fpscrd; + struct { + ulong pad; + ulong fpscr; + }; + }; + int fpistate; /* emulated fp */ + ulong emreg[32][3]; /* emulated fp */ +}; + +struct Conf +{ + ulong nmach; /* processors */ + ulong nproc; /* processes */ + ulong npage0; /* total physical pages of memory */ + ulong npage1; /* total physical pages of memory */ + ulong npage; /* total physical pages of memory */ + ulong upages; /* user page pool */ + ulong nimage; /* number of page cache image headers */ + ulong nswap; /* number of swap pages */ + int nswppo; /* max # of pageouts per segment pass */ + ulong base0; /* base of bank 0 */ + ulong base1; /* base of bank 1 */ + ulong copymode; /* 0 is copy on write, 1 is copy on reference */ + ulong ialloc; /* max interrupt time allocation in bytes */ + ulong interps; /* number of interpreter processes */ + ulong pipeqsize; /* size in bytes of pipe queues */ +}; + +#include "../port/portdat.h" + +/* + * machine dependent definitions not used by ../port/dat.h + */ + +struct Mach +{ + /* OFFSETS OF THE FOLLOWING KNOWN BY l.s */ + int machno; /* physical id of processor (unused) */ + ulong splpc; /* pc of last caller to splhi (unused) */ + int mmask; /* 1<machno (unused) */ + + /* ordering from here on irrelevant */ + ulong ticks; /* of the clock since boot time */ + Proc *proc; /* current process on this processor */ + Label sched; /* scheduler wakeup */ + Lock alarmlock; /* access to alarm list */ + void *alarm; /* alarms bound to this clock */ + int nrdy; + int speed; /* general system clock in MHz */ + long oscclk; /* oscillator frequency (MHz) */ + long cpuhz; /* general system clock (cycles) */ + long clockgen; /* clock generator frequency (cycles) */ + int cputype; + ulong delayloop; + ulong* bcsr; + IMM* iomem; /* MPC8xx internal i/o control memory */ + + ulong fairness; /* for runproc */ + + int tlbfault; + int tlbpurge; + int pfault; + int cs; + int syscall; + int load; + int intr; + vlong fastclock; /* last sampled value */ + int flushmmu; /* make current proc flush it's mmu state */ + + /* MUST BE LAST */ + int stack[1]; +}; +extern Mach mach0; + +/* + * Fake kmap + */ +typedef void KMap; +#define VA(k) ((ulong)(k)) +#define kmap(p) (KMap*)((p)->pa) +#define kunmap(k) + +/* + * routines for things outside the PowerPC model + */ +struct PCArch +{ + char* id; + int (*ident)(void); /* this should be in the model */ + void (*reset)(void); /* this should be in the model */ + int (*serialpower)(int); /* 1 == on, 0 == off */ + int (*modempower)(int); /* 1 == on, 0 == off */ + + void (*intrinit)(void); + int (*intrenable)(int, int, Irqctl*); + + void (*clockenable)(void); +}; + +/* + * a parsed .ini line + */ +#define ISAOPTLEN 16 +#define NISAOPT 8 + +struct ISAConf { + char type[NAMELEN]; + ulong port; + ulong irq; + ulong mem; + int dma; + ulong size; + ulong freq; + uchar bus; + + int nopt; + char opt[NISAOPT][ISAOPTLEN]; +}; + +struct Map { + int size; + ulong addr; +}; + +struct RMap { + char* name; + Map* map; + Map* mapend; + + Lock; +}; + +struct +{ + Lock; + short machs; + short exiting; + short ispanic; +}active; + +extern register Mach *m; +extern register Proc *up; + diff --git a/mpc/devether.c b/mpc/devether.c new file mode 100644 index 0000000000000000000000000000000000000000..843ad35e14b9aa326daa5336ecc862c079d17ad0 --- /dev/null +++ b/mpc/devether.c @@ -0,0 +1,447 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" +#include "ureg.h" +#include "../port/error.h" +#include "../port/netif.h" + +#include "etherif.h" + +static Ether *etherxx[MaxEther]; + +void ethermediumlink(void); + +Chan* +etherattach(char* spec) +{ + ulong ctlrno; + char *p; + Chan *chan; + + ctlrno = 0; + if(spec && *spec){ + ctlrno = strtoul(spec, &p, 0); + if((ctlrno == 0 && p == spec) || *p || (ctlrno >= MaxEther)) + error(Ebadarg); + } + if(etherxx[ctlrno] == 0) + error(Enodev); + + chan = devattach('l', spec); + chan->dev = ctlrno; + if(etherxx[ctlrno]->attach) + etherxx[ctlrno]->attach(etherxx[ctlrno]); + return chan; +} + +static void +etherdetach(void) +{ + Ether **ether; + + ether = etherxx; + while(*ether){ + if((*ether)->detach) + (*ether)->detach(*ether); + ether++; + } +} + +static int +etherwalk(Chan* chan, char* name) +{ + return netifwalk(etherxx[chan->dev], chan, name); +} + +static void +etherstat(Chan* chan, char* dp) +{ + netifstat(etherxx[chan->dev], chan, dp); +} + +static Chan* +etheropen(Chan* chan, int omode) +{ + return netifopen(etherxx[chan->dev], chan, omode); +} + +static void +ethercreate(Chan*, char*, int, ulong) +{ +} + +static void +etherclose(Chan* chan) +{ + Ether *ether; + + ether = etherxx[chan->dev]; + netifclose(ether, chan); + if(ether->closed) + ether->closed(ether); +} + +static long +etherread(Chan* chan, void* buf, long n, vlong offset) +{ + Ether *ether; + + ether = etherxx[chan->dev]; + if((chan->qid.path & CHDIR) == 0 && ether->ifstat){ + /* + * With some controllers it is necessary to reach + * into the chip to extract statistics. + */ + if(NETTYPE(chan->qid.path) == Nifstatqid) + return ether->ifstat(ether, buf, n, offset); + else if(NETTYPE(chan->qid.path) == Nstatqid) + ether->ifstat(ether, buf, 0, offset); + } + + return netifread(ether, chan, buf, n, offset); +} + +static Block* +etherbread(Chan* chan, long n, ulong offset) +{ + return netifbread(etherxx[chan->dev], chan, n, offset); +} + +static void +etherremove(Chan*) +{ +} + +static void +etherwstat(Chan* chan, char* dp) +{ + netifwstat(etherxx[chan->dev], chan, dp); +} + +static void +etherrtrace(Netfile* f, Etherpkt* pkt, int len) +{ + int i, n; + Block *bp; + + if(qwindow(f->in) <= 0) + return; + if(len > 64) + n = 64; + else + n = len; + bp = iallocb(n); + if(bp == 0) + return; + memmove(bp->wp, pkt->d, n); + i = TK2MS(MACHP(0)->ticks); + bp->wp[58] = len>>8; + bp->wp[59] = len; + bp->wp[60] = i>>24; + bp->wp[61] = i>>16; + bp->wp[62] = i>>8; + bp->wp[63] = i; + bp->wp += 64; + qpass(f->in, bp); +} + +Block* +etheriq(Ether* ether, Block* bp, int freebp) +{ + Etherpkt *pkt; + ushort type; + int len; + Netfile **ep, *f, **fp, *fx; + Block *xbp; + + ether->inpackets++; + + pkt = (Etherpkt*)bp->rp; + len = BLEN(bp); + type = (pkt->type[0]<<8)|pkt->type[1]; + fx = 0; + ep = ðer->f[Ntypes]; + + /* check for valid multcast addresses */ + if((pkt->d[0] & 1) && memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) != 0 && ether->prom == 0){ + if(!activemulti(ether, pkt->d, sizeof(pkt->d))){ + if(freebp){ + freeb(bp); + bp = 0; + } + return bp; + } + } + + /* + * Multiplex the packet to all the connections which want it. + * If the packet is not to be used subsequently (freebp != 0), + * attempt to simply pass it into one of the connections, thereby + * saving a copy of the data (usual case hopefully). + */ + for(fp = ether->f; fp < ep; fp++){ + if((f = *fp) && (f->type == type || f->type < 0)){ + if(f->type > -2){ + if(freebp && fx == 0) + fx = f; + else if(xbp = iallocb(len)){ + memmove(xbp->wp, pkt, len); + xbp->wp += len; + qpass(f->in, xbp); + } + else + ether->soverflows++; + } + else + etherrtrace(f, pkt, len); + } + } + + if(fx){ + qpass(fx->in, bp); + return 0; + } + if(freebp){ + freeb(bp); + return 0; + } + + return bp; +} + +static int +etheroq(Ether* ether, Block* bp) +{ + int len, loopback, s; + Etherpkt *pkt; + + ether->outpackets++; + + /* + * Check if the packet has to be placed back onto the input queue, + * i.e. if it's a loopback or broadcast packet or the interface is + * in promiscuous mode. + * If it's a loopback packet indicate to etheriq that the data isn't + * needed and return, etheriq will pass-on or free the block. + */ + pkt = (Etherpkt*)bp->rp; + len = BLEN(bp); + loopback = (memcmp(pkt->d, ether->ea, sizeof(pkt->d)) == 0); + if(loopback || memcmp(pkt->d, ether->bcast, sizeof(pkt->d)) == 0 || ether->prom){ + s = splhi(); + etheriq(ether, bp, loopback); + splx(s); + } + + if(!loopback){ + qbwrite(ether->oq, bp); + ether->transmit(ether); + } + + return len; +} + +static long +etherwrite(Chan* chan, void* buf, long n, vlong) +{ + Ether *ether; + Block *bp; + + ether = etherxx[chan->dev]; + if(NETTYPE(chan->qid.path) != Ndataqid) + return netifwrite(ether, chan, buf, n); + + if(n > ETHERMAXTU) + error(Etoobig); +// if(n < ETHERMINTU) +// error(Etoosmall); + + bp = allocb(n); + if(waserror()){ + freeb(bp); + nexterror(); + } + memmove(bp->rp, buf, n); + memmove(bp->rp+Eaddrlen, ether->ea, Eaddrlen); + poperror(); + bp->wp += n; + + return etheroq(ether, bp); +} + +static long +etherbwrite(Chan* chan, Block* bp, ulong) +{ + Ether *ether; + long n; + + n = BLEN(bp); + + ether = etherxx[chan->dev]; + if(NETTYPE(chan->qid.path) != Ndataqid){ + n = netifwrite(ether, chan, bp->rp, n); + freeb(bp); + return n; + } + + if(n > ETHERMAXTU){ + freeb(bp); + error(Ebadarg); + } + + return etheroq(ether, bp); +} + +static struct { + char* type; + int (*reset)(Ether*); +} cards[MaxEther+1]; + +void +addethercard(char* t, int (*r)(Ether*)) +{ + static int ncard; + + if(ncard == MaxEther) + panic("too many ether cards"); + cards[ncard].type = t; + cards[ncard].reset = r; + ncard++; +} + +int +parseether(uchar *to, char *from) +{ + char nip[4]; + char *p; + int i; + + p = from; + for(i = 0; i < 6; i++){ + if(*p == 0) + return -1; + nip[0] = *p++; + if(*p == 0) + return -1; + nip[1] = *p++; + nip[2] = 0; + to[i] = strtoul(nip, 0, 16); + if(*p == ':') + p++; + } + return 0; +} + +static void +etherreset(void) +{ + Ether *ether; + int i, n, ctlrno; + char name[NAMELEN], buf[128]; + + //ethermediumlink(); + for(ether = 0, ctlrno = 0; ctlrno < MaxEther; ctlrno++){ + if(ether == 0) + ether = malloc(sizeof(Ether)); + memset(ether, 0, sizeof(Ether)); + ether->ctlrno = ctlrno; + ether->tbdf = BUSUNKNOWN; + ether->mbps = 10; + if(isaconfig("ether", ctlrno, ether) == 0) + continue; + for(n = 0; cards[n].type; n++){ + if(cistrcmp(cards[n].type, ether->type)) + continue; + for(i = 0; i < ether->nopt; i++){ + if(strncmp(ether->opt[i], "ea=", 3)) + continue; + if(parseether(ether->ea, ðer->opt[i][3]) == -1) + memset(ether->ea, 0, Eaddrlen); + } + if(cards[n].reset(ether)) + break; + + intrenable(ether->irq, ether->interrupt, ether, ether->tbdf); + + i = sprint(buf, "#l%d: %s: %dMbps port 0x%luX irq %d", + ctlrno, ether->type, ether->mbps, ether->port, ether->irq); + if(ether->mem) + i += sprint(buf+i, " addr 0x%luX", PADDR(ether->mem)); + if(ether->size) + i += sprint(buf+i, " size 0x%luX", ether->size); + i += sprint(buf+i, ": %2.2uX%2.2uX%2.2uX%2.2uX%2.2uX%2.2uX", + ether->ea[0], ether->ea[1], ether->ea[2], + ether->ea[3], ether->ea[4], ether->ea[5]); + sprint(buf+i, "\n"); + print(buf); + + snprint(name, sizeof(name), "ether%d", ctlrno); + if(ether->mbps == 100){ + netifinit(ether, name, Ntypes, 256*1024); + if(ether->oq == 0) + ether->oq = qopen(256*1024, 1, 0, 0); + } + else{ + netifinit(ether, name, Ntypes, 32*1024); + if(ether->oq == 0) + ether->oq = qopen(64*1024, 1, 0, 0); + } + if(ether->oq == 0) + panic("etherreset %s", name); + ether->alen = Eaddrlen; + memmove(ether->addr, ether->ea, Eaddrlen); + memset(ether->bcast, 0xFF, Eaddrlen); + + etherxx[ctlrno] = ether; + ether = 0; + break; + } + } + if(ether) + free(ether); +} + +#define POLY 0xedb88320 + +/* really slow 32 bit crc for ethers */ +ulong +ethercrc(uchar *p, int len) +{ + int i, j; + ulong crc, b; + + crc = 0xffffffff; + for(i = 0; i < len; i++){ + b = *p++; + for(j = 0; j < 8; j++){ + crc = (crc>>1) ^ (((crc^b) & 1) ? POLY : 0); + b >>= 1; + } + } + return crc; +} + +Dev etherdevtab = { + 'l', + "ether", + + etherreset, + devinit, + etherattach, + /*etherdetach,*/ + devclone, + etherwalk, + etherstat, + etheropen, + ethercreate, + etherclose, + etherread, + etherbread, + etherwrite, + etherbwrite, + etherremove, + etherwstat, +}; diff --git a/mpc/devrtc.c b/mpc/devrtc.c new file mode 100644 index 0000000000000000000000000000000000000000..0850eb97cb572194996524d3f0fc465d1ca2fa83 --- /dev/null +++ b/mpc/devrtc.c @@ -0,0 +1,180 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "../port/error.h" + +#include "io.h" + +/* + * MPC8xx real time clock + * FADS board option switch + * interrupt statistics + */ + +enum{ + Qrtc = 1, + Qswitch, + Qintstat, + + /* sccr */ + RTDIV= 1<<24, + RTSEL= 1<<23, + + /* rtcsc */ + RTE= 1<<0, + R38K= 1<<4, +}; + +static QLock rtclock; /* mutex on clock operations */ + +static Dirtab rtcdir[]={ + "rtc", {Qrtc, 0}, 12, 0666, + "switch", {Qswitch, 0}, 0, 0444, + "intstat", {Qintstat, 0}, 0, 0444, +}; +#define NRTC (sizeof(rtcdir)/sizeof(rtcdir[0])) + +static void +rtcreset(void) +{ + IMM *io; + int n; + + io = m->iomem; + io->rtcsck = KEEP_ALIVE_KEY; + n = (RTClevel<<8)|RTE; + if(m->oscclk == 5) + n |= R38K; + io->rtcsc = n; + io->rtcsck = ~KEEP_ALIVE_KEY; +print("sccr=#%8.8lux plprcr=#%8.8lux\n", io->sccr, io->plprcr); +} + +static Chan* +rtcattach(char *spec) +{ + return devattach('r', spec); +} + +static int +rtcwalk(Chan *c, char *name) +{ + return devwalk(c, name, rtcdir, NRTC, devgen); +} + +static void +rtcstat(Chan *c, char *dp) +{ + devstat(c, dp, rtcdir, NRTC, devgen); +} + +static Chan* +rtcopen(Chan *c, int omode) +{ + omode = openmode(omode); + switch(c->qid.path){ + case Qrtc: + if(strcmp(up->user, eve)!=0 && omode!=OREAD) + error(Eperm); + break; + case Qswitch: + case Qintstat: + if(omode!=OREAD) + error(Eperm); + break; + } + return devopen(c, omode, rtcdir, NRTC, devgen); +} + +static void +rtcclose(Chan*) +{ +} + +static long +rtcread(Chan *c, void *buf, long n, vlong offset) +{ + ulong t; + char *b; + + if(c->qid.path & CHDIR) + return devdirread(c, buf, n, rtcdir, NRTC, devgen); + + switch(c->qid.path){ + case Qrtc: + t = m->iomem->rtc; + n = readnum(offset, buf, n, t, 12); + return n; + case Qswitch: + return readnum(offset, buf, n, (m->bcsr[2]>>19)&0xF, 12); + } + error(Egreg); + return 0; /* not reached */ +} + +static long +rtcwrite(Chan *c, void *buf, long n, vlong offset) +{ + ulong secs; + char *cp, *ep; + IMM *io; + + switch(c->qid.path){ + case Qrtc: + if(offset!=0) + error(Ebadarg); + /* + * read the time + */ + cp = ep = buf; + ep += n; + while(cp < ep){ + if(*cp>='0' && *cp<='9') + break; + cp++; + } + secs = strtoul(cp, 0, 0); + /* + * set it + */ + io = ioplock(); + io->rtck = KEEP_ALIVE_KEY; + io->rtc = secs; + io->rtck = ~KEEP_ALIVE_KEY; + iopunlock(); + return n; + case Qswitch: + return 0; + } + error(Egreg); + return 0; /* not reached */ +} + +long +rtctime(void) +{ + return m->iomem->rtc; +} + +Dev rtcdevtab = { + 'r', + "rtc", + + rtcreset, + devinit, + rtcattach, + devclone, + rtcwalk, + rtcstat, + rtcopen, + devcreate, + rtcclose, + rtcread, + devbread, + rtcwrite, + devbwrite, + devremove, + devwstat, +}; diff --git a/mpc/etherif.h b/mpc/etherif.h new file mode 100644 index 0000000000000000000000000000000000000000..096c9d483bef5d5f458482d1d95b8c60b0a48d1f --- /dev/null +++ b/mpc/etherif.h @@ -0,0 +1,28 @@ +enum { + MaxEther = 24, + Ntypes = 8, +}; + +typedef struct Ether Ether; +struct Ether { + ISAConf; /* hardware info */ + int ctlrno; + int tbdf; /* type+busno+devno+funcno */ + int mbps; /* Mbps */ + uchar ea[Eaddrlen]; + + void (*attach)(Ether*); /* filled in by reset routine */ + void (*closed)(Ether*); + void (*detach)(Ether*); + void (*transmit)(Ether*); + void (*interrupt)(Ureg*, void*); + long (*ifstat)(Ether*, void*, long, ulong); + void *ctlr; + + Queue* oq; + + Netif; +}; + +extern Block* etheriq(Ether*, Block*, int); +extern void addethercard(char*, int(*)(Ether*)); diff --git a/mpc/fns.h b/mpc/fns.h new file mode 100644 index 0000000000000000000000000000000000000000..0224c7874f467736f2c939834b25264f20c96100 --- /dev/null +++ b/mpc/fns.h @@ -0,0 +1,91 @@ +#include "../port/portfns.h" + +void archinit(void); +int brgalloc(void); +void brgfree(int); +ulong baudgen(int, int); +int cistrcmp(char*, char*); +int cistrncmp(char*, char*, int); +void clockcheck(void); +void clockinit(void); +void clockintr(Ureg*); +void clrfptrap(void); +#define coherence() // not need on signle processor machines +void cpminit(void); +int cpuidentify(void); +void cpuidprint(void); +void dcflush(void*, ulong); +void delay(int); +ulong draminit(ulong*); +void dtlbmiss(void); +void dumpregs(Ureg*); +void eieio(void); +void evenaddr(ulong); +void faultpower(Ureg*); +void firmware(int); +void fpinit(void); +int fpipower(Ureg*); +void fpoff(void); +ulong fpstatus(void); +char* getconf(char*); +ulong getdar(void); +ulong getdec(void); +ulong getdepn(void); +ulong getdsisr(void); +ulong getimmr(void); +ulong getmsr(void); +ulong getpvr(void); +ulong gettbl(void); +ulong gettbu(void); +void gotopc(ulong); +void icflush(void*, ulong); +void idle(void); +int iprint(char*, ...); +void intr(Ureg*); +void intrenable(int, void (*)(Ureg*, void*), void*, int); +int intrstats(char*, int); +void intrvec(void); +void itlbmiss(void); +int isaconfig(char*, int, ISAConf*); +void kbdinit(void); +void kbdreset(void); +void links(void); +void mapfree(RMap*, ulong, int); +void mapinit(RMap*, Map*, int); +void mathinit(void); +void mmuinit(void); +ulong* mmuwalk(ulong*, ulong, int); +#define procrestore(p) +void procsave(Proc*); +void procsetup(Proc*); +void putdec(ulong); +void putmsr(ulong); +ulong rmapalloc(RMap*, ulong, int, int); +void screeninit(void); +void setpanic(void); +int screenprint(char*, ...); /* debugging */ +#define screenputs(x, y) // no screen +ulong sdraminit(ulong*); +int segflush(void*, ulong); +void spireset(void); +long spioutin(void*, long, void*); +int tas(void*); +void trapinit(void); +void trapvec(void); +void uartinstall(void); +void uartwait(void); /* debugging */ +void wbflush(void); + +#define waserror() (up->nerrlab++, setlabel(&up->errlab[up->nerrlab-1])) +ulong getcallerpc(void*); + +// identity map between kernel physical and virtual addresses +#define KADDR(a) ((void*)(a)) +#define PADDR(a) ((ulong)(a)) + +/* IBM bit field order */ +#define IBIT(b) ((ulong)1<<(31-(b))) +#define SIBIT(n) ((ushort)1<<(15-(n))) + +/* compatibility with inf2.1 */ +#define bpenumenv(n) ((char*)0) diff --git a/mpc/io.h b/mpc/io.h new file mode 100644 index 0000000000000000000000000000000000000000..ae6f187816a16028ebba93378563c735619b9484 --- /dev/null +++ b/mpc/io.h @@ -0,0 +1,556 @@ +typedef struct BD BD; +typedef struct Ring Ring; +typedef struct GTimer GTimer; + +enum +{ + /* interrupt vectors (SIU and CPM) */ + VectorPIC= 0, /* level 0 to level 7, assigned by software */ + /* vector assignments are determined by the assignments here */ + PITlevel= 2, + CPIClevel= 4, + PCMCIAlevel= 6, + RTClevel= 7, + VectorIRQ= VectorPIC+8, /* IRQ0 to IRQ7 */ + VectorCPIC= VectorIRQ+8, /* 32 CPM interrupts: 0 (error) to 0x1F (PC15) */ +}; + +/* + * these are defined to keep the interface compatible with other + * architectures, but only BUSUNKNOWN is currently used + */ +#define MKBUS(t,b,d,f) (((t)<<24)|(((b)&0xFF)<<16)|(((d)&0x1F)<<11)|(((f)&0x07)<<8)) +#define BUSFNO(tbdf) (((tbdf)>>8)&0x07) +#define BUSDNO(tbdf) (((tbdf)>>11)&0x1F) +#define BUSBNO(tbdf) (((tbdf)>>16)&0xFF) +#define BUSTYPE(tbdf) ((tbdf)>>24) +#define BUSBDF(tbdf) ((tbdf)&0x00FFFF00) +#define BUSUNKNOWN (-1) + +/* + * Buffer Descriptors and IO Rings + */ + +struct BD { + ushort status; + ushort length; + ulong addr; +}; + +BD* bdalloc(int); +void bdfree(BD*, int); + +enum { + /* Rx BDs, bits common to all protocols */ + BDEmpty= 1<<15, + BDWrap= 1<<13, + BDInt= 1<<12, + BDLast= 1<<11, + BDFirst= 1<<10, + + /* Tx BDs */ + BDReady= 1<<15, + /* BDWrap, BDInt, BDLast */ +}; + + +struct Ring { + BD* rdr; /* receive descriptor ring */ + void* rrb; /* receive ring buffers */ + int rdrx; /* index into rdr */ + int nrdre; /* length of rdr */ + + BD* tdr; /* transmit descriptor ring */ + Block** txb; /* corresponding transmit ring buffers */ + int tdrh; /* host index into tdr */ + int tdri; /* interface index into tdr */ + int ntdre; /* length of tdr */ + int ntq; /* pending transmit requests */ +}; + +#define NEXT(x, l) (((x)+1)%(l)) +#define PREV(x, l) (((x) == 0) ? (l)-1: (x)-1) +#define HOWMANY(x, y) (((x)+((y)-1))/(y)) +#define ROUNDUP(x, y) (HOWMANY((x), (y))*(y)) + +int ioringinit(Ring*, int, int, int); + +/* + * CPM + */ +enum { + /* commands */ + InitRxTx = 0, + InitRx = 1, + InitTx = 2, + EnterHunt= 3, + StopTx= 4, + GracefulStopTx = 5, + InitIDMA = 5, + RestartTx = 6, + CloseRxBD = 7, + SetGroupAddr = 8, + SetTimer = 8, + GCITimeout = 9, + GCIAbort = 10, + StopIDMA = 11, + StartDSP = 12, + ArmIDMA = 13, + InitDSP = 13, + USBCmd = 15, + + /* channel IDs */ + SCC1ID= 0, + USBID= 0, + I2CID= 1, + IDMA1ID= 1, + SCC2ID= 4, + SPIID= 5, + IDMA2ID= 5, + TIMERID= 5, + SCC3ID= 8, + SMC1ID= 9, + DSP1ID=9, + SCC4ID= 12, + SMC2ID= 13, + DSP2ID= 13, + + /* bgcr */ + BaudEnable = 1<<16, + + /* sicr */ + CLK1 = 4, /* SCC1,2 */ + CLK2 = 5, + CLK3 = 6, + CLK4 = 7, + CLK5 = CLK1, /* SCC3,4 */ + CLK6 = CLK2, + CLK7 = CLK3, + CLK8 = CLK4, +}; + +void cpmop(int, int, int); +void* cpmalloc(int, int); +void cpmfree(void*, int); +void* cpmparam(ulong, int); +IMM* ioplock(void); +void iopunlock(void); +void sccnmsi(int, int, int); +int scc2claim(int, ulong, void(*)(void*), void*); +void scc2stop(void*); + +/* + * CPM timers + */ +enum { + /* timer modes */ + CaptureRise= 1<<6, + CaptureFall= 2<<6, + CaptureEdge= 3<<6, + TimerToggle= 1<<5, /* toggle TOUTx* pin */ + TimerORI= 1<<4, /* Output Reference Interrupt */ + TimerRestart= 1<<3, + TimerSclk= 1<<1, + TimerSclk16= 2<<1, + TimerTIN= 3<<1, /* clock by falling edge of TINx */ + TimerGate= 1<<0, /* TGATE1* controls timer */ + + /* timer events */ + TimerREF= 1<<1, + TimerCAP= 1<<0 +}; + +struct GTimer{ + int x; + int inuse; + int event; + ushort* tmr; + ushort* trr; + ushort* tcr; + ushort* tcn; + ushort* ter; + void* arg; + void (*interrupt)(Ureg*, void*, GTimer*); +}; +GTimer* gtimer(ushort, ushort, void (*)(Ureg*,void*,GTimer*), void*); +void gtimerset(GTimer*, ushort, int); +void gtimerstart(GTimer*); +void gtimerstop(GTimer*); +void gtimerfree(GTimer*); + +enum { + /* BCSR1 bits */ + DisableFlash= IBIT(0), + DisableDRAM= IBIT(1), + DisableEther= IBIT(2), + DisableIR= IBIT(3), + DisableRS232a= IBIT(7), + DisablePCMCIA= IBIT(8), + PCCVCCMask= IBIT(9)|IBIT(15), + PCCVPPMask= IBIT(10)|IBIT(11), + DisableRS232b= IBIT(13), + EnableSDRAM= IBIT(14), + + PCCVCC0V= IBIT(15)|IBIT(9), + PCCVCC5V= IBIT(9), /* active low */ + PCCVCC3V= IBIT(15), /* active low */ + PCCVPP0V= IBIT(10)|IBIT(11), /* active low */ + PCCVPP5V= IBIT(10), /* active low */ + PCCVPP12V= IBIT(11), /* active low */ + PCCVPPHiZ= IBIT(10)|IBIT(11), + + /* BCSR4 bits */ + DisableTPDuplex= IBIT(1), + DisableLamp= IBIT(3), + DisableUSB= IBIT(4), + USBFullSpeed= IBIT(5), + DisableUSBVcc= IBIT(6), + DisableVideoLamp= IBIT(8), + EnableVideoClock= IBIT(9), + EnableVideoPort= IBIT(10), + DisableModem= IBIT(11), +}; + +/* + * everything in this file follows a hardware/firmware layout in the 8xx manuals: + * mind the data types, offsets and alignment + */ + +/* + * basic IO controller parameters (SMC and SCC) + */ +typedef struct IOCparam IOCparam; +struct IOCparam { + ushort rbase; + ushort tbase; + uchar rfcr; + uchar tfcr; + ushort mrblr; + ulong rstate; + ulong rxidp; + ushort rbptr; + ushort rxibc; + ulong rxtemp; + ulong tstate; + ulong txidp; + ushort tbptr; + ushort txibc; + ulong txtemp; +}; + +typedef struct SCCparam SCCparam; +struct SCCparam { + IOCparam; + ulong rcrc; + ulong tcrc; +}; + +typedef struct SCC SCC; +struct SCC { + ulong gsmrl; + ulong gsmrh; + ushort psmr; + uchar rsvscc0[2]; + ushort todr; + ushort dsr; + ushort scce; + uchar rsvscc1[2]; + ushort sccm; + uchar rsvscc3; + uchar sccs; + ushort irmode; + ushort irsip; +}; + +typedef struct SMC SMC; +struct SMC { + uchar pad1[2]; + ushort smcmr; + uchar pad2[2]; + uchar smce; + uchar pad3[3]; + uchar smcm; + uchar pad4[5]; +}; + +typedef struct SPI SPI; +struct SPI { + ushort spmode; + uchar res1[4]; + uchar spie; + uchar res2[3]; + uchar spim; + uchar res3[2]; + uchar spcom; + uchar res4[10]; +}; + +typedef struct USB USB; +struct USB { + uchar usmod; + uchar usadr; + uchar uscom; + uchar rsvu1; + ushort usep[4]; + uchar rsvu2[4]; + ushort usber; + uchar rsvu3[2]; + ushort usbmr; + uchar rsvu4; + uchar usbs; + uchar rsvu5[8]; +}; + +typedef struct IMM IMM; +struct IMM { + struct { /* general SIU */ + ulong siumcr; + ulong sypcr; + uchar rsv0[0xE-0x8]; + ushort swsr; + ulong sipend; + ulong simask; + ulong siel; + uchar sivec; + uchar padv[3]; + ulong tesr; + uchar rsv1[0x30-0x24]; + ulong sdcr; + uchar rsv2[0x80-0x34]; + }; + struct { /* PCMCIA */ + struct { + ulong base; + ulong option; + } pcmr[8]; + uchar rsv3[0xe0-0xc0]; + ulong pgcra; + ulong pgcrb; + ulong pscr; + uchar rsv4[0xf0-0xec]; + ulong pipr; + uchar rsv5[4]; + ulong per; + uchar rsv6[4]; + }; + struct { /* MEMC */ + struct { + ulong base; + ulong option; + } memc[8]; + uchar rsv7a[0x24]; + ulong mar; + ulong mcr; + uchar rsv7b[4]; + ulong mamr; + ulong mbmr; + ushort mstat; + ushort mptpr; + ulong mdr; + uchar rsv7c[0x80]; + }; + struct { /* system integration timers */ + ushort tbscr; + uchar rsv8a[2]; + ulong tbrefu; + ulong tbrefl; + uchar rsv8b[0x14]; + ushort rtcsc; + uchar rsv8c[2]; + ulong rtc; + ulong rtsec; + ulong rtcal; + uchar rsv8d[0x10]; + ushort piscr; + ushort rsv8e; + ulong pitc; + ulong pitr; + uchar rsv8f[0x34]; + }; + struct { /* 280: clocks and resets */ + ulong sccr; + ulong plprcr; + ulong rsr; + uchar rsv9[0x300-0x28c]; + }; + struct { /* 300: system integration timers keys */ + ulong tbscrk; + ulong tbrefuk; + ulong tbreflk; + ulong tbk; + uchar rsv10a[0x10]; + ulong rtcsck; + ulong rtck; + ulong rtseck; + ulong rtcalk; + uchar rsv10b[0x10]; + ulong piscrk; + ulong pitck; + uchar rsv10c[0x38]; + }; + struct { /* 380: clocks and resets keys */ + ulong sccrk; + ulong plprcrk; + ulong rsrk; + uchar rsv11[0x800-0x38C]; + }; + struct { /* 800: video controller */ + ushort vccr; + ushort pad11a; + uchar vsr; + uchar pad11b; + uchar vcmr; + uchar pad11c; + ulong vbcb; + ulong pad11d; + ulong vfcr0; + ulong vfaa0; + ulong vfba0; + ulong vfcr1; + ulong vfaa1; + ulong vfba1; + uchar rsv11a[0x840-0x828]; + }; + struct { /* 840: LCD */ + ulong lccr; + ulong lchcr; + ulong lcvcr; + ulong rsv11b; + ulong lcfaa; + ulong lcfba; + uchar lcsr; + uchar rsv11c[0x860-0x859]; + }; + struct { /* 860: I2C */ + uchar i2mod; + uchar rsv12a[3]; + uchar i2add; + uchar rsv12b[3]; + uchar i2brg; + uchar rsv12c[3]; + uchar i2com; + uchar rsv12d[3]; + uchar i2cer; + uchar rsv12e[3]; + uchar i2cmr; + uchar rsv12[0x900-0x875]; + }; + struct { /* 900: DMA */ + uchar rsv13[4]; + ulong sdar; + uchar sdsr; + uchar pad1[3]; + uchar sdmr; + uchar pad2[3]; + uchar idsr1; + uchar pad3[3]; + uchar idmr1; + uchar pad4[3]; + uchar idsr2; + uchar pad5[3]; + uchar idmr2; + uchar pad6[0x930-0x91D]; + }; + struct { /* CPM interrupt control */ + ushort civr; + uchar pad7[0x940-0x932]; + ulong cicr; + ulong cipr; + ulong cimr; + ulong cisr; + }; + struct { /* input/output port */ + ushort padir; + ushort papar; + ushort paodr; + ushort padat; + uchar pad8[8]; + ushort pcdir; + ushort pcpar; + ushort pcso; + ushort pcdat; + ushort pcint; + uchar pad9[6]; + ushort pddir; + ushort pdpar; + ushort rsv14a; + ushort pddat; + uchar rsv14[0x980-0x978]; + }; + struct { /* CPM timers */ + ushort tgcr; + uchar rsv15a[0x990-0x982]; + ushort tmr1; + ushort tmr2; + ushort trr1; + ushort trr2; + ushort tcr1; + ushort tcr2; + ushort tcn1; + ushort tcn2; + ushort tmr3; + ushort tmr4; + ushort trr3; + ushort trr4; + ushort tcr3; + ushort tcr4; + ushort tcn3; + ushort tcn4; + ushort ter1; + ushort ter2; + ushort ter3; + ushort ter4; + uchar rsv15[0x9C0-0x9B8]; + }; + struct { /* CPM */ + ushort cpcr; + uchar res0[2]; + ushort rccr; + uchar res1; + uchar rmds; + uchar res2a[4]; + ushort rctr1; + ushort rctr2; + ushort rctr3; + ushort rctr4; + uchar res2[2]; + ushort rter; + uchar res3[2]; + ushort rtmr; + uchar rsv16[0x9F0-0x9DC]; + }; + union { /* BRG */ + struct { + ulong brgc1; + ulong brgc2; + ulong brgc3; + ulong brgc4; + }; + ulong brgc[4]; + }; + uchar skip0[0xAB2-0xA00]; /* USB, SCC, SMC, SPI: address using IOREGS in fns.h */ + struct { /* PIP */ + ushort pipc; /* not 823 */ + ushort ptpr; /* not 823 */ + ulong pbdir; + ulong pbpar; + uchar pad10[2]; + ushort pbodr; + ulong pbdat; + uchar pad11[0xAE0-0xAC8]; + }; + struct { /* SI */ + ulong simode; + uchar sigmr; + uchar pad12; + uchar sistr; + uchar sicmr; + uchar pad13[4]; + ulong sicr; + ulong sirp; + uchar pad14[0xB00-0xAF4]; + }; + uchar vcram[256]; + uchar siram[512]; + ushort lcdmap[256]; +}; diff --git a/mpc/l.s b/mpc/l.s new file mode 100644 index 0000000000000000000000000000000000000000..2a0299b0802609c1381ecb739f54eb367a4c3145 --- /dev/null +++ b/mpc/l.s @@ -0,0 +1,663 @@ +#include "mem.h" + +/* + * common ppc special purpose registers + */ +#define DSISR 18 +#define DAR 19 /* Data Address Register */ +#define DEC 22 /* Decrementer */ +#define SRR0 26 /* Saved Registers (exception) */ +#define SRR1 27 +#define SPRG0 272 /* Supervisor Private Registers */ +#define SPRG1 273 +#define SPRG2 274 +#define SPRG3 275 +#define TBRU 269 /* Time base Upper/Lower (Reading) */ +#define TBRL 268 +#define TBWU 285 /* Time base Upper/Lower (Writing) */ +#define TBWL 284 +#define PVR 287 /* Processor Version */ + +/* + * mpc8xx-specific special purpose registers of interest here + */ +#define EIE 80 +#define EID 81 +#define NRI 82 +#define IMMR 638 +#define IC_CST 560 +#define IC_ADR 561 +#define IC_DAT 562 +#define DC_CST 568 +#define DC_ADR 569 +#define DC_DAT 570 +#define MI_CTR 784 +#define MI_AP 786 +#define MI_EPN 787 +#define MI_TWC 789 +#define MI_RPN 790 +#define MI_DBCAM 816 +#define MI_DBRAM0 817 +#define MI_DBRAM1 818 +#define MD_CTR 792 +#define M_CASID 793 +#define MD_AP 794 +#define MD_EPN 795 +#define M_TWB 796 +#define MD_TWC 797 +#define MD_RPN 798 +#define M_TW 799 +#define MD_DBCAM 824 +#define MD_DBRAM0 825 +#define MD_DBRAM1 826 + +/* use of SPRG registers in save/restore */ +#define SAVER0 SPRG0 +#define SAVER1 SPRG1 +#define SAVELR SPRG2 +#define SAVEXX SPRG3 + +/* special instruction definitions */ +#define BDNZ BC 16,0, +#define BDNE BC 0,2, +#define TLBIA WORD $(31<<26) +#define MFTB(tbr,d) WORD $((31<<26)|((d)<<21)|((tbr&0x1f)<<16)|(((tbr>>5)&0x1f)<<11)|(371<<1)) + +/* on some models mtmsr doesn't synchronise enough (eg, 603e) */ +#define MSRSYNC SYNC; ISYNC + +#define UREGSPACE (UREGSIZE+8) + + TEXT start(SB), $-4 + + /* turn off interrupts but enable traps */ + MOVW MSR, R3 + MOVW $~(MSR_EE|MSR_FP), R4 + AND R4, R3 + OR $(MSR_IP|MSR_ME), R3 + ISYNC + MOVW R3, MSR + MSRSYNC + + MOVW $0, R0 /* except during trap handling, R0 is zero from now on */ + MOVW $setSB(SB), R2 + +/* + * reset the caches and disable them for now + */ + MOVW SPR(IC_CST), R4 /* read and clear */ + MOVW $(5<<25), R4 + MOVW R4, SPR(IC_CST) /* unlock all */ + ISYNC + MOVW $(6<<25), R4 + MOVW R4, SPR(IC_CST) /* invalidate all */ + ISYNC + MOVW $(2<<25), R4 + MOVW R4, SPR(IC_CST) /* disable i-cache */ + ISYNC + + SYNC + MOVW SPR(DC_CST), R4 /* read and clear */ + MOVW $(10<<24), R4 + SYNC + MOVW R4, SPR(DC_CST) /* unlock all */ + ISYNC + MOVW $(12<<24), R4 + SYNC + MOVW R4, SPR(DC_CST) /* invalidate all */ + ISYNC + MOVW $(4<<24), R4 + SYNC + MOVW R4, SPR(DC_CST) /* disable d-cache */ + ISYNC + + MOVW $7, R4 + MOVW R4, SPR(158) /* cancel `show cycle' for normal instruction execution */ + ISYNC + +/* + * set other system configuration values + */ + MOVW $INTMEM, R4 + MOVW R4, SPR(IMMR) /* set internal memory base */ + + MOVW $mach0(SB), R(MACH) + ADD $(MACHSIZE-8), R(MACH), R1 + SUB $4, R(MACH), R3 + ADD $4, R1, R4 +clrmach: + MOVWU R0, 4(R3) + 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 + SUB $4, R3 +clrbss: + MOVWU R0, 4(R3) + CMP R3, R4 + BNE clrbss + + BL main(SB) + BR 0(PC) + +TEXT kernelmmu(SB), $0 + TLBIA + ISYNC + + MOVW $0, R4 + MOVW R4, SPR(M_CASID) /* set supervisor space */ + MOVW $(0<<29), R4 /* allow i-cache when IR=0 */ + MOVW R4, SPR(MI_CTR) /* i-mmu control */ + ISYNC + MOVW $((1<<29)|(1<<28)), R4 /* cache inhibit when DR=0, write-through */ + SYNC + MOVW R4, SPR(MD_CTR) /* d-mmu control */ + ISYNC + TLBIA + + /* map various things 1:1 */ + MOVW $tlbtab-KZERO(SB), R4 + MOVW $tlbtabe-KZERO(SB), R5 + SUB R4, R5 + MOVW $(3*4), R6 + DIVW R6, R5 + SUB $4, R4 + MOVW R5, CTR +ltlb: + MOVWU 4(R4), R5 + MOVW R5, SPR(MD_EPN) + MOVW R5, SPR(MI_EPN) + MOVWU 4(R4), R5 + MOVW R5, SPR(MI_TWC) + MOVW R5, SPR(MD_TWC) + MOVWU 4(R4), R5 + MOVW R5, SPR(MD_RPN) + MOVW R5, SPR(MI_RPN) + BDNZ ltlb + + MOVW $(1<<25), R4 + MOVW R4, SPR(IC_CST) /* enable i-cache */ + ISYNC + + MOVW $(1<<24), R4 + SYNC + MOVW R4, SPR(DC_CST) /* force write through mode */ + MOVW $(1<<25), R4 + SYNC + MOVW R4, SPR(DC_CST) /* enable d-cache */ + ISYNC + + /* enable MMU and set kernel PC to virtual space */ + MOVW $((0<<29)|(1<<28)), R4 /* cache when DR=0, write-through */ + SYNC + MOVW R4, SPR(MD_CTR) /* d-mmu control */ + MOVW LR, R3 + OR $KZERO, R3 + MOVW R3, SPR(SRR0) + MOVW MSR, R4 + OR $(MSR_ME|MSR_IR|MSR_DR), R4 /* had ME|FPE|FE0|FE1 */ + MOVW R4, SPR(SRR1) + RFI /* resume in kernel mode in caller */ + +TEXT splhi(SB), $0 + MOVW MSR, R3 + RLWNM $0, R3, $~MSR_EE, R4 + SYNC + MOVW R4, MSR + MSRSYNC + MOVW LR, R31 + MOVW R31, 4(R(MACH)) /* save PC in m->splpc */ + RETURN + +TEXT splx(SB), $0 + /* fall though */ + +TEXT splxpc(SB), $0 + MOVW MSR, R4 + RLWMI $0, R3, $MSR_EE, R4 + RLWNMCC $0, R3, $MSR_EE, R5 + BNE splx0 + MOVW LR, R31 + MOVW R31, 4(R(MACH)) /* save PC in m->splpc */ +splx0: + SYNC + MOVW R4, MSR + MSRSYNC + RETURN + +TEXT spllo(SB), $0 + MFTB(TBRL, 3) + MOVW R3, spltbl(SB) + MOVW MSR, R3 + OR $MSR_EE, R3, R4 + SYNC + MOVW R4, MSR + MSRSYNC + RETURN + +TEXT spldone(SB), $0 + RETURN + +TEXT islo(SB), $0 + MOVW MSR, R3 + RLWNM $0, R3, $MSR_EE, R3 + RETURN + +TEXT setlabel(SB), $-4 + MOVW LR, R31 + MOVW R1, 0(R3) + MOVW R31, 4(R3) + MOVW $0, R3 + RETURN + +TEXT gotolabel(SB), $-4 + MOVW 4(R3), R31 + MOVW R31, LR + MOVW 0(R3), R1 + MOVW $1, R3 + RETURN + +/* + * enter with stack set and mapped. + * on return, SB (R2) has been set, and R3 has the Ureg*, + * the MMU has been re-enabled, kernel text and PC are in KSEG, + * R(MACH) has been set, and R0 contains 0. + * + * this can be simplified in the Inferno regime + */ +TEXT saveureg(SB), $-4 +/* + * save state + */ + MOVMW R2, 48(R1) /* r2:r31 */ + MOVW $setSB(SB), R2 + MOVW SPR(SAVER1), R4 + MOVW R4, 44(R1) + MOVW SPR(SAVER0), R5 + MOVW R5, 40(R1) + MOVW CTR, R6 + MOVW R6, 36(R1) + MOVW XER, R4 + MOVW R4, 32(R1) + MOVW CR, R5 + MOVW R5, 28(R1) + MOVW SPR(SAVELR), R6 /* LR */ + MOVW R6, 24(R1) + /* pad at 20(R1) */ + /* old PC(16) and status(12) saved earlier */ + MOVW SPR(SAVEXX), R0 + MOVW R0, 8(R1) /* cause/vector */ + ADD $8, R1, R3 /* Ureg* */ + STWCCC R3, (R1) /* break any pending reservations */ + MOVW $0, R0 /* compiler/linker expect R0 to be zero */ + + MOVW MSR, R5 + OR $(MSR_IR|MSR_DR), R5 /* enable MMU */ + MOVW R5, SPR(SRR1) + MOVW LR, R31 + OR $KZERO, R31 /* return PC in KSEG0 */ + MOVW R31, SPR(SRR0) + SYNC + ISYNC + RFI /* returns to trap handler */ + +TEXT icflush(SB), $-4 /* icflush(virtaddr, count) */ + MOVW n+4(FP), R4 + RLWNM $0, R3, $~(CACHELINESZ-1), R5 + SUB R5, R3 + ADD R3, R4 + ADD $(CACHELINESZ-1), R4 + SRAW $CACHELINELOG, R4 + MOVW R4, CTR +icf0: ICBI (R5) + ADD $CACHELINESZ, R5 + BDNZ icf0 + ISYNC + RETURN + +TEXT dcflush(SB), $-4 /* dcflush(virtaddr, count) */ + SYNC + MOVW n+4(FP), R4 + RLWNM $0, R3, $~(CACHELINESZ-1), R5 + CMP R4, $0 + BLE dcf1 + SUB R5, R3 + ADD R3, R4 + ADD $(CACHELINESZ-1), R4 + SRAW $CACHELINELOG, R4 + MOVW R4, CTR +dcf0: DCBF (R5) + ADD $CACHELINESZ, R5 + BDNZ dcf0 + SYNC + ISYNC +dcf1: + RETURN + +TEXT tas(SB), $0 + SYNC + MOVW R3, R4 + MOVW $0xdeaddead,R5 +tas1: + DCBF (R4) /* fix for 603x bug */ + LWAR (R4), R3 + CMP R3, $0 + BNE tas0 + STWCCC R5, (R4) + BNE tas1 +tas0: + SYNC + ISYNC + RETURN + +TEXT gettbl(SB), $0 + MFTB(TBRL, 3) + RETURN + +TEXT gettbu(SB), $0 + MOVW SPR(TBRU), R3 + RETURN + +TEXT getpvr(SB), $0 + MOVW SPR(PVR), R3 + RETURN + +TEXT getimmr(SB), $0 + MOVW SPR(IMMR), R3 + RETURN + +TEXT getdec(SB), $0 + MOVW SPR(DEC), R3 + RETURN + +TEXT putdec(SB), $0 + MOVW R3, SPR(DEC) + RETURN + +TEXT getcallerpc(SB), $-4 + MOVW 0(R1), R3 + RETURN + +TEXT getdar(SB), $0 + MOVW SPR(DAR), R3 + RETURN + +TEXT getdsisr(SB), $0 + MOVW SPR(DSISR), R3 + RETURN + +TEXT getdepn(SB), $0 + MOVW SPR(MD_EPN), R3 + RETURN + +TEXT getmsr(SB), $0 + MOVW MSR, R3 + RETURN + +TEXT putmsr(SB), $0 + SYNC + MOVW R3, MSR + MSRSYNC + RETURN + +TEXT eieio(SB), $0 + EIEIO + RETURN + +TEXT gotopc(SB), $0 + MOVW R3, CTR + MOVW LR, R31 /* for trace back */ + BR (CTR) + +TEXT firmware(SB), $0 + MOVW MSR, R3 + MOVW $(MSR_EE|MSR_ME), R4 + ANDN R4, R3 + OR $(MSR_IP), R3 + ISYNC + MOVW R3, MSR /* turn off interrupts and machine checks */ + MSRSYNC + MOVW $(MSR_RI|MSR_IR|MSR_DR|MSR_ME), R4 + ANDN R4, R3 + MOVW R3, SPR(SRR1) + MOVW $(0xFF00<<16), R4 + MOVW R4, SPR(IMMR) + MOVW $(0x0800<<16), R4 + MOVW R4, SPR(SRR0) /* force bad address */ + MOVW R0, SPR(149) /* ensure checkstop on machine check */ + MOVW R0, R1 + MOVW R0, R2 + EIEIO + ISYNC + RFI + +/* + * byte swapping of arrays of long and short; + * could possibly be avoided with more changes to drivers + */ +TEXT swabl(SB), $0 + MOVW v+4(FP), R4 + MOVW n+8(FP), R5 + SRAW $2, R5, R5 + MOVW R5, CTR + SUB $4, R4 + SUB $4, R3 +swabl1: + ADD $4, R3 + MOVWU 4(R4), R7 + MOVWBR R7, (R3) + BDNZ swabl1 + RETURN + +TEXT swabs(SB), $0 + MOVW v+4(FP), R4 + MOVW n+8(FP), R5 + SRAW $1, R5, R5 + MOVW R5, CTR + SUB $2, R4 + SUB $2, R3 +swabs1: + ADD $2, R3 + MOVHZU 2(R4), R7 + MOVHBR R7, (R3) + BDNZ swabs1 + RETURN + +TEXT legetl(SB), $0 + MOVWBR (R3), R3 + RETURN + +TEXT lesetl(SB), $0 + MOVW v+4(FP), R4 + MOVWBR R4, (R3) + RETURN + +TEXT legets(SB), $0 + MOVHBR (R3), R3 + RETURN + +TEXT lesets(SB), $0 + MOVW v+4(FP), R4 + MOVHBR R4, (R3) + RETURN + +/* + * ITLB miss + * avoid references that might need the right SB value; + * IR and DR are off. + */ +TEXT itlbmiss(SB), $-4 + MOVW R1, SPR(M_TW) + MOVW SPR(SRR0), R1 /* instruction miss address */ + MOVW R1, SPR(MD_EPN) + MOVW SPR(M_TWB), R1 /* level one pointer */ + MOVW (R1), R1 + MOVW R1, SPR(MI_TWC) /* save level one attributes */ + MOVW R1, SPR(MD_TWC) /* save base and attributes */ + MOVW SPR(MD_TWC), R1 /* level two pointer */ + MOVW (R1), R1 /* level two entry */ + MOVW R1, SPR(MI_RPN) /* write TLB */ + MOVW SPR(M_TW), R1 + RFI + +/* + * DTLB miss + * avoid references that might need the right SB value; + * IR and DR are off. + */ +TEXT dtlbmiss(SB), $-4 + MOVW R1, SPR(M_TW) + MOVW SPR(M_TWB), R1 /* level one pointer */ + MOVW (R1), R1 /* level one entry */ + MOVW R1, SPR(MD_TWC) /* save base and attributes */ + MOVW SPR(MD_TWC), R1 /* level two pointer */ + MOVW (R1), R1 /* level two entry */ + MOVW R1, SPR(MD_RPN) /* write TLB */ + MOVW SPR(M_TW), R1 + RFI + +/* + * traps force memory mapping off. + * this code goes to too much effort (for the Inferno environment) to restore it. + */ +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 + MOVW R0, 12(R1) /* save status: could take DLTB miss here */ + MOVW LR, R0 + MOVW R0, 16(R1) /* old PC */ + BL saveureg(SB) + BL trap(SB) + BR restoreureg + +TEXT intrvec(SB), $-4 + MOVW LR, R0 + +/* + * 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, R0 /* make data space usable */ + SYNC + MOVW R0, MSR + MSRSYNC + SUB $UREGSPACE, R1 + + MFTB(TBRL, 0) + MOVW R0, intrtbl(SB) + + MOVW SPR(SRR0), R0 + MOVW R0, LR + MOVW SPR(SRR1), R0 + MOVW R0, 12(R1) + MOVW LR, R0 + MOVW R0, 16(R1) + BL saveureg(SB) + + MFTB(TBRL, 5) + MOVW R5, isavetbl(SB) + + BL intr(SB) + +/* + * restore state from Ureg and return from trap/interrupt + */ +restoreureg: + MOVMW 48(R1), R2 /* r2:r31 */ + /* defer R1 */ + MOVW 40(R1), R0 + MOVW R0, SPR(SAVER0) + MOVW 36(R1), R0 + MOVW R0, CTR + MOVW 32(R1), R0 + MOVW R0, XER + MOVW 28(R1), R0 + MOVW R0, CR /* CR */ + MOVW 24(R1), R0 + MOVW R0, SPR(SAVELR) /* LR */ + /* pad, skip */ + MOVW 16(R1), R0 + MOVW R0, SPR(SRR0) /* old PC */ + MOVW 12(R1), R0 + MOVW R0, SPR(SRR1) /* old MSR */ + /* cause, skip */ + MOVW 44(R1), R1 /* old SP */ + MOVW SPR(SAVELR), R0 + MOVW R0, LR + 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 + +TEXT reset(SB), $-4 + MOVW $0,R4 + MOVW 0(R4), R5 +loop: + BR loop + + +GLOBL mach0+0(SB), $MACHSIZE +GLOBL spltbl+0(SB), $4 +GLOBL intrtbl+0(SB), $4 +GLOBL isavetbl+0(SB), $4 + +/* + * TLB prototype entries, loaded once-for-all at startup, + * remaining unchanged thereafter. + * Limit the table to at most 8 entries to ensure + * it works on the 823 (other 8xx processors allow up to 32 TLB entries). + */ +#define TLBE(epn,rpn,twc) WORD $(epn); WORD $(twc); WORD $(rpn) + +TEXT tlbtab(SB), $-4 + + /* epn, rpn, twc */ +/* TLBE(KZERO|DRAMMEM|TLBVALID, DRAMMEM|PTEWRITE|PTELPS|PTESH|PTEVALID, PTE8MB|PTEWT|PTEVALID) /* DRAM, 8M */ +/* TLBE(KZERO|BCSRMEM|TLBVALID, BCSRMEM|PTEWRITE|PTESH|PTECI|PTEVALID, PTE4K|PTEWT|PTEVALID) /* Board CSR, 4K */ +/* TLBE(KZERO|INTMEM|TLBVALID, INTMEM|PTEWRITE|PTELPS|PTESH|PTECI|PTEVALID, PTE4K|PTEWT|PTEVALID) /* IMMR, 16K */ +/* TLBE(KZERO|FLASHMEM|TLBVALID, FLASHMEM|PTEWRITE|PTELPS|PTESH|PTECI|PTEVALID, PTE8MB|PTEWT|PTEVALID) /* Flash, 8M */ +/* TLBE(KZERO|SDRAMMEM|TLBVALID, SDRAMMEM|PTEWRITE|PTELPS|PTESH|PTEVALID, PTE8MB|PTEWT|PTEVALID) /* SDRAM, 8M */ +/* TLBE(KZERO|PCMCIAMEM|TLBVALID, PCMCIAMEM|PTEWRITE|PTELPS|PTESH|PTECI|PTEVALID, PTE8MB|PTEWT|PTEVALID) /* PCMCIA, 8M */ +TEXT tlbtabe(SB), $-4 + RETURN diff --git a/mpc/main.c b/mpc/main.c new file mode 100644 index 0000000000000000000000000000000000000000..49c1c263dd936c55427ade8f356ceaedaa58107f --- /dev/null +++ b/mpc/main.c @@ -0,0 +1,190 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" +#include "init.h" +#include "pool.h" + +#define MAXCONF 1000 + +char *confname[MAXCONF]; +char *confval[MAXCONF]; +int nconf; + +Conf conf; + +void +main(void) +{ + machinit(); +} + +void +machinit(void) +{ + IMM *io; + int mf, osc; + + memset(m, 0, sizeof(*m)); + m->delayloop = 20000; + m->cputype = getpvr()>>16; + m->iomem = KADDR(INTMEM); + + io = m->iomem; + osc = 5; + mf = io->plprcr >> 20; + m->oscclk = osc; + m->speed = osc*(mf+1); +} + +void +exit(int ispanic) +{ + int ms, once; + + lock(&active); + if(ispanic) + active.ispanic = ispanic; + else if(m->machno == 0 && (active.machs & (1<machno)) == 0) + active.ispanic = 0; + once = active.machs & (1<machno); + active.machs &= ~(1<machno); + active.exiting = 1; + unlock(&active); + + if(once) + print("cpu%d: exiting\n", m->machno); + spllo(); + for(ms = 5*1000; ms > 0; ms -= TK2MS(2)){ + delay(TK2MS(2)); + if(active.machs == 0 && consactive() == 0) + break; + } + + if(active.ispanic && m->machno == 0){ + if(cpuserver) + delay(10000); + else + for(;;); + } + else + delay(1000); + +// arch->reset(); +} + +/* + * set up floating point for a new process + */ +void +procsetup(Proc *p) +{ + USED(p); +} + +/* + * Save the mach dependent part of the process state. + */ +void +procsave(Proc *p) +{ + USED(p); +} + +// print without using interrupts +int +iprint(char *fmt, ...) +{ + char buf[PRINTSIZE]; + int n; + va_list arg; + + va_start(arg, fmt); + n = doprint(buf, buf+sizeof(buf), fmt, arg) - buf; + va_end(arg); + + print("%s", buf); + + return n; +} + + +int +isaconfig(char *class, int ctlrno, ISAConf *isa) +{ + char cc[NAMELEN], *p, *q, *r; + int n; + + sprint(cc, "%s%d", class, ctlrno); + for(n = 0; n < nconf; n++){ + if(strncmp(confname[n], cc, NAMELEN)) + continue; + isa->nopt = 0; + p = confval[n]; + while(*p){ + while(*p == ' ' || *p == '\t') + p++; + if(*p == '\0') + break; + if(strncmp(p, "type=", 5) == 0){ + p += 5; + for(q = isa->type; q < &isa->type[NAMELEN-1]; q++){ + if(*p == '\0' || *p == ' ' || *p == '\t') + break; + *q = *p++; + } + *q = '\0'; + } + else if(strncmp(p, "port=", 5) == 0) + isa->port = strtoul(p+5, &p, 0); + else if(strncmp(p, "irq=", 4) == 0) + isa->irq = strtoul(p+4, &p, 0); + else if(strncmp(p, "mem=", 4) == 0) + isa->mem = strtoul(p+4, &p, 0); + else if(strncmp(p, "size=", 5) == 0) + isa->size = strtoul(p+5, &p, 0); + else if(strncmp(p, "freq=", 5) == 0) + isa->freq = strtoul(p+5, &p, 0); + else if(strncmp(p, "dma=", 4) == 0) + isa->dma = strtoul(p+4, &p, 0); + else if(isa->nopt < NISAOPT){ + r = isa->opt[isa->nopt]; + while(*p && *p != ' ' && *p != '\t'){ + *r++ = *p++; + if(r-isa->opt[isa->nopt] >= ISAOPTLEN-1) + break; + } + *r = '\0'; + isa->nopt++; + } + while(*p && *p != ' ' && *p != '\t') + p++; + } + return 1; + } + return 0; +} + +int +cistrcmp(char *a, char *b) +{ + int ac, bc; + + for(;;){ + ac = *a++; + bc = *b++; + + if(ac >= 'A' && ac <= 'Z') + ac = 'a' + (ac - 'A'); + if(bc >= 'A' && bc <= 'Z') + bc = 'a' + (bc - 'A'); + ac -= bc; + if(ac) + return ac; + if(bc == 0) + break; + } + return 0; +} diff --git a/mpc/mem.h b/mpc/mem.h new file mode 100644 index 0000000000000000000000000000000000000000..8aa6529303fd1aaa46ae99ade0fba99735375769 --- /dev/null +++ b/mpc/mem.h @@ -0,0 +1,156 @@ +/* + * Memory and machine-specific definitions. Used in C and assembler. + */ + +/* + * Sizes + */ + +#define BI2BY 8 /* bits per byte */ +#define BI2WD 32 /* bits per word */ +#define BY2WD 4 /* bytes per word */ +#define BY2V 8 /* bytes per double word */ +#define BY2PG 4096 /* bytes per page */ +#define WD2PG (BY2PG/BY2WD) /* words per page */ +#define PGSHIFT 12 /* log(BY2PG) */ +#define ROUND(s, sz) (((s)+((sz)-1))&~((sz)-1)) +#define PGROUND(s) ROUND(s, BY2PG) +#define CACHELINELOG 4 +#define CACHELINESZ (1< */ +#define USER 29 /* R29 is up-> */ + +/* + * Fundamental addresses + */ +#define MACHADDR ((long)&mach0) + +#define UREGSIZE ((8+32)*4) + +/* + * virtual MMU + */ +#define PTEMAPMEM (1024*1024) +#define PTEPERTAB (PTEMAPMEM/BY2PG) +#define SEGMAPSIZE 1984 +#define SSEGMAPSIZE 16 +#define PPN(x) ((x)&~(BY2PG-1)) + +/* + * MMU + */ + +/* L1 table entry and Mx_TWC flags */ +#define PTEVALID (1<<0) +#define PTEWT (1<<1) /* write through */ +#define PTE4K (0<<2) +#define PTE512K (1<<2) +#define PTE8MB (3<<2) +#define PTEG (1<<4) /* guarded */ + +/* L2 table entry and Mx_RPN flags (also PTEVALID) */ +#define PTECI (1<<1) /* cache inhibit */ +#define PTESH (1<<2) /* page is shared; ASID ignored */ +#define PTELPS (1<<3) /* large page size */ +#define PTEWRITE 0x9F0 + +/* + * physical MMU - bogus at the momement + */ +#define PTEUNCACHED (1<<4) +#define PTERONLY (0<<1) +#define PTEKERNEL (0<<2) +#define PTEUSER (1<<2) +#define PTESIZE (1<<7) + +/* TLB and MxEPN flag */ +#define TLBVALID (1<<9) + +#define TLBSETS 32 /* number of tlb sets */ + +/* + * Address spaces + * + * User is at 0-2GB + * Kernel is at 2GB-4GB + */ +#define UZERO 0 /* base of user address space */ +#define UTZERO (UZERO+BY2PG) /* first address in user text */ +#define KZERO 0x80000000 /* base of kernel address space */ +#define KTZERO 0xff000000 /* first address in kernel text */ +#define USTKTOP (KZERO-BY2PG) /* byte just beyond user stack */ +#define USTKSIZE (16*1024*1024) /* size of user stack */ +#define TSTKTOP (USTKTOP-USTKSIZE) /* end of new stack in sysexec */ +#define TSTKSIZ 100 + +/* + * atlas board registers + */ +#define INTMEM 0x80000000 +#define NIMMEM 0x80100000 +#define FLASH0MEM 0x80200000 +#define FLASH1MEM 0x80400000 +#define SDRAMMEM 0x03000000 +#define DRAMMEM 0xff000000 // to 0xffffffff: 16 Meg + +#define SIRAM (INTMEM+0xC00) +#define LCDCOLR (INTMEM+0xE00) +#define DPRAM (INTMEM+0x2000) +#define DPLEN1 0x200 +#define DPLEN2 0x400 +#define DPLEN3 0x800 +#define DPBASE (DPRAM+DPLEN1) + +#define SCC1P (INTMEM+0x3C00) +#define I2CP (INTMEM+0x3C80) +#define MISCP (INTMEM+0x3CB0) +#define IDMA1P (INTMEM+0x3CC0) +#define SCC2P (INTMEM+0x3D00) +#define SPIP (INTMEM+0x3D80) +#define TIMERP (INTMEM+0x3DB0) +#define SMC1P (INTMEM+0x3E80) +#define DSP1P (INTMEM+0x3EC0) +#define SMC2P (INTMEM+0x3F80) +#define DSP2P (INTMEM+0x3FC0) + +#define KEEP_ALIVE_KEY 0x55ccaa33 /* clock and rtc register key */ + +#define getpgcolor(a) 0 diff --git a/mpc/mmu.c b/mpc/mmu.c new file mode 100644 index 0000000000000000000000000000000000000000..777681ca55e4f8a90200cfa811e1a99bcfc22f29 --- /dev/null +++ b/mpc/mmu.c @@ -0,0 +1,68 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" + + +static void +taskswitch(ulong pdb, ulong stack) +{ + USED(pdb, stack); +} + +void +mmuinit(void) +{ +} + +void +flushmmu(void) +{ +} + +static void +mmuptefree(Proc* proc) +{ + USED(proc); +} + +void +mmuswitch(Proc* proc) +{ + USED(proc); +} + +void +mmurelease(Proc* proc) +{ + USED(proc); +} + +static Page* +mmupdballoc(void) +{ +} + +void +putmmu(ulong va, ulong pa, Page*) +{ + USED(va, pa); +} + +static Lock mmukmaplock; + +int +mmukmapsync(ulong va) +{ + USED(va); + return 0; +} + +ulong +mmukmap(ulong pa, ulong va, int size) +{ + USED(pa, va, size); + return 0; +} diff --git a/mpc/rmap.c b/mpc/rmap.c new file mode 100644 index 0000000000000000000000000000000000000000..aaf5f32e300490f0ce687f8ae9d1b350c0fec6c5 --- /dev/null +++ b/mpc/rmap.c @@ -0,0 +1,106 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" + +void +mapinit(RMap *rmap, Map *map, int size) +{ + lock(rmap); + rmap->map = map; + rmap->mapend = map+(size/sizeof(Map)); + unlock(rmap); +} + +void +mapfree(RMap* rmap, ulong addr, int size) +{ + Map *mp; + ulong t; + + if(size <= 0) + return; + + lock(rmap); + for(mp = rmap->map; mp->addr <= addr && mp->size; mp++) + ; + + if(mp > rmap->map && (mp-1)->addr+(mp-1)->size == addr){ + (mp-1)->size += size; + if(addr+size == mp->addr){ + (mp-1)->size += mp->size; + while(mp->size){ + mp++; + (mp-1)->addr = mp->addr; + (mp-1)->size = mp->size; + } + } + } + else{ + if(addr+size == mp->addr && mp->size){ + mp->addr -= size; + mp->size += size; + } + else do{ + if(mp >= rmap->mapend){ + print("mapfree: %s: losing 0x%uX, %d\n", + rmap->name, addr, size); + break; + } + t = mp->addr; + mp->addr = addr; + addr = t; + t = mp->size; + mp->size = size; + mp++; + }while(size = t); + } + unlock(rmap); +} + +ulong +rmapalloc(RMap* rmap, ulong addr, int size, int align) +{ + Map *mp; + ulong maddr, oaddr; + + lock(rmap); + for(mp = rmap->map; mp->size; mp++){ + maddr = mp->addr; + + if(addr){ + if(maddr > addr) + break; + if(maddr+mp->size < addr) + continue; + if(addr+size > maddr+mp->size) + break; + maddr = addr; + } + + if(align > 0) + maddr = ((maddr+align-1)/align)*align; + if(mp->addr+mp->size-maddr < size) + continue; + + oaddr = mp->addr; + mp->addr = maddr+size; + mp->size -= maddr-oaddr+size; + if(mp->size == 0){ + do{ + mp++; + (mp-1)->addr = mp->addr; + }while((mp-1)->size = mp->size); + } + + unlock(rmap); + if(oaddr != maddr) + mapfree(rmap, oaddr, maddr-oaddr); + + return maddr; + } + unlock(rmap); + + return 0; +} diff --git a/mpc/segment.h b/mpc/segment.h new file mode 100644 index 0000000000000000000000000000000000000000..3f6e9542bee2c5956771b00436fa8bbb8f17f350 --- /dev/null +++ b/mpc/segment.h @@ -0,0 +1,8 @@ +/* + * Attach segment types + */ +static Physseg physseg[10] = { + { SG_SHARED, "shared", 0, SEGMAXSIZE, 0, 0 }, + { SG_BSS, "memory", 0, SEGMAXSIZE, 0, 0 }, + { 0, 0, 0, 0, 0, 0 }, +}; diff --git a/mpc/trap.c b/mpc/trap.c new file mode 100644 index 0000000000000000000000000000000000000000..3d2a5ab54bcc420c27a6251321dd93f9690cab9b --- /dev/null +++ b/mpc/trap.c @@ -0,0 +1,133 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" +#include "ureg.h" +#include "../port/error.h" + +/* Give enough context in the ureg to produce a kernel stack for + * a sleeping process + */ +void +setkernur(Ureg* ureg, Proc* p) +{ + ureg->pc = p->sched.pc; + ureg->sp = p->sched.sp+4; +} + +/* 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) +{ + USED(ureg, pureg, uva, n); + panic("not done"); +} + +void +dumpregs(Ureg* ureg) +{ + USED(ureg); + panic("not done"); +} + +void +dumpstack(void) +{ + panic("not done"); +} + +ulong +userpc(void) +{ + Ureg *ureg; + + ureg = (Ureg*)up->dbgreg; + return ureg->pc; +} + +ulong +dbgpc(Proc *p) +{ + Ureg *ureg; + + ureg = p->dbgreg; + if(ureg == 0) + return 0; + + return ureg->pc; +} + +static void +linkproc(void) +{ + spllo(); + up->kpfun(up->kparg); +} + +void +kprocchild(Proc* p, void (*func)(void*), void* arg) +{ + p->sched.pc = (ulong)linkproc; + p->sched.sp = (ulong)p->kstack+KSTACK; + + p->kpfun = func; + p->kparg = arg; +} + +void +forkchild(Proc *p, Ureg *ureg) +{ + USED(p, ureg); +} + +/* + * called in sysfile.c + */ +void +evenaddr(ulong addr) +{ + if(addr & 3){ + postnote(up, 1, "sys: odd address", NDebug); + error(Ebadarg); + } +} + +long +execregs(ulong entry, ulong ssize, ulong nargs) +{ + ulong *sp; + Ureg *ureg; + + sp = (ulong*)(USTKTOP - ssize); + *--sp = nargs; + + ureg = up->dbgreg; + ureg->usp = (ulong)sp; + ureg->pc = entry; + return USTKTOP-BY2WD; /* address of user-level clock */ +} + +void +trap(Ureg *ur) +{ + USED(ur); +} + +/* + * called directly by l.s:/intrvec + */ +void +intr(Ureg *ur) +{ + USED(ur); +} + +void +intrenable(int v, void (*r)(Ureg*, void*), void *arg, int) +{ + USED(v, r, arg); +}