diff options
Diffstat (limited to 'os/ipengine')
| -rw-r--r-- | os/ipengine/NOTICE | 4 | ||||
| -rw-r--r-- | os/ipengine/README | 40 | ||||
| -rw-r--r-- | os/ipengine/archipe.c | 488 | ||||
| -rw-r--r-- | os/ipengine/archipe.h | 32 | ||||
| -rw-r--r-- | os/ipengine/dat.h | 162 | ||||
| -rw-r--r-- | os/ipengine/devfpga.c | 389 | ||||
| -rw-r--r-- | os/ipengine/flash28f320b3b.c | 43 | ||||
| -rw-r--r-- | os/ipengine/fns.h | 120 | ||||
| -rw-r--r-- | os/ipengine/io.h | 1 | ||||
| -rw-r--r-- | os/ipengine/ipe | 109 | ||||
| -rw-r--r-- | os/ipengine/main.c | 348 | ||||
| -rw-r--r-- | os/ipengine/mem.h | 156 | ||||
| -rw-r--r-- | os/ipengine/mkfile | 105 | ||||
| -rw-r--r-- | os/ipengine/mmu.c | 20 | ||||
| -rw-r--r-- | os/ipengine/tlb.s | 21 |
15 files changed, 2038 insertions, 0 deletions
diff --git a/os/ipengine/NOTICE b/os/ipengine/NOTICE new file mode 100644 index 00000000..f7d66a0d --- /dev/null +++ b/os/ipengine/NOTICE @@ -0,0 +1,4 @@ +Inferno® Copyright © 1996-1999 Lucent Technologies Inc. All rights reserved. +PowerPC support Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net). All rights reserved. +MPC8xx Inferno PowerPC port Copyright © 1998-2003 Vita Nuova Holdings Limited. All rights reserved. +ip-Engine1 PowerPC port Copyright © 2000-2003 Vita Nuova Holdings Limited. All rights reserved. diff --git a/os/ipengine/README b/os/ipengine/README new file mode 100644 index 00000000..3572de78 --- /dev/null +++ b/os/ipengine/README @@ -0,0 +1,40 @@ +The ipEngine-1 is a Motorola MPC8xx-based small computer +made by Bright Star Engineering (www.brightstareng.com) +which also provides Linux and their own operating system for it. +It is an interesting hardware platform to do network-oriented Inferno +applications. + +The ipEngine is unusual in including an FPGA (Altera Flex 6016). +See fpga(3) and fpgaload(8). +We are also working on software to help program the thing. + + +Booting the ipEngine + +0. serial cable (port 1, 9600 baud), ether, power etc. + +1. make appropriate entries for your site in flash + using the BSE monitor: + + set netmask 255.255.255.0 + set nameserver 200.1.1.11 + set server 200.1.1.11 + set serverip 200.1.1.11 + set gateway 200.1.1.50 + set hostname stella + set domain vitanuova.com + set myip 200.1.1.96 + +2. add an entry to do the boot by tftp: + + set bootcmd "load /usr/inferno/os/ipengine/iipe 3000; go 3020" + + contrary to the BSE documentation this loads any + binary file at the given address. the -b option + doesn't seem to be needed. + +3. reset + it should load and start the kernel + +Vita Nuova +16 July 2003 diff --git a/os/ipengine/archipe.c b/os/ipengine/archipe.c new file mode 100644 index 00000000..151f72f7 --- /dev/null +++ b/os/ipengine/archipe.c @@ -0,0 +1,488 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" + +#include <draw.h> +#include <memdraw.h> +#include "screen.h" + +#include "../port/netif.h" +#include "etherif.h" +#include "../port/flashif.h" + +#include "archipe.h" + +/* + * board-specific support for the Bright Star Engineering ipEngine-1 + */ + +enum { + /* sccr */ + COM3= IBIT(1)|IBIT(2), /* clock output disabled */ + TBS = IBIT(6), /* =0, time base is OSCCLK/{4,16}; =1, time base is GCLK2/16 */ + RTSEL = IBIT(8), /* =0, select main oscillator (OSCM); =1, select external crystal (EXTCLK) */ + RTDIV = IBIT(7), /* =0, divide by 4; =1, divide by 512 */ + CRQEN = IBIT(9), /* =1, switch to high frequency when CPM active */ + PRQEN = IBIT(10), /* =1, switch to high frequency when interrupt pending */ + + /* plprcr */ + CSRC = IBIT(21), /* =0, clock is DFNH; =1, clock is DFNL */ + + Showports = 0, /* used to find lightly-documented bits set by bootstrap (eg, PDN) */ +}; + +static ulong ports[4*4]; + +/* + * called early in main.c, after machinit: + * using board and architecture specific registers, initialise + * 8xx registers that need it and complete initialisation of the Mach structure. + */ +void +archinit(void) +{ + IMM *io; + int mf; + + io = m->iomem; /* run by reset code: no need to lock */ + m->clockgen = 4000000; /* crystal frequency */ + m->oscclk = m->clockgen/MHz; + io->plprcrk = KEEP_ALIVE_KEY; + io->plprcr &= ~CSRC; /* general system clock is DFNH */ + mf = (io->plprcr >> 20)+1; /* use timing set by bootstrap */ + io->plprcrk = ~KEEP_ALIVE_KEY; + io->sccrk = KEEP_ALIVE_KEY; + io->sccr |= CRQEN | PRQEN | RTDIV | COM3; /* devfpga.c resets COM3 if needed */ + io->sccrk = ~KEEP_ALIVE_KEY; + m->cpuhz = m->clockgen*mf; + m->speed = m->cpuhz/MHz; + if((io->memc[CLOCKCS].base & 1) == 0){ /* prom hasn't mapped it */ + io->memc[CLOCKCS].option = 0xFFFF0F24; + io->memc[CLOCKCS].base = 0xFF020001; + } + if(Showports){ + ports[0] = io->padat; + ports[1] = io->padir; + ports[2] = io->papar; + ports[3] = io->paodr; + ports[4] = io->pbdat; + ports[5] = io->pbdir; + ports[6] = io->pbpar; + ports[7] = io->pbodr; + ports[8] = io->pcdat; + ports[9] = io->pcdir; + ports[10] = io->pcpar; + ports[11] = io->pcso; + ports[12] = io->pddat; + ports[13] = io->pddir; + ports[14] = io->pdpar; + ports[15] = 0; + } +} + +static ulong +banksize(int x, ulong *pa) +{ + IMM *io; + + io = m->iomem; + if((io->memc[x].base & 1) == 0) + return 0; /* bank not valid */ + *pa = io->memc[x].base & ~0x7FFF; + return -(io->memc[x].option&~0x7FFF); +} + +/* + * initialise the kernel's memory configuration: + * there are two banks (base0, npage0) and (base1, npage1). + * initialise any other values in conf that are board-specific. + */ +void +archconfinit(void) +{ + ulong pa, nbytes, ktop; + + conf.nscc = 2; + conf.sccuarts = 0; /* no SCC uarts */ + conf.smcuarts = (1<<0)|(1<<1); /* SMC1 (console) and SMC2 */ + + nbytes = banksize(DRAMCS, &pa); + if(nbytes == 0){ /* force default */ + nbytes = 16*1024*1024; + pa = 0; + } + conf.npage0 = nbytes/BY2PG; + conf.base0 = pa; + + conf.npage1 = 0; + + /* the following assumes the kernel text and/or data is in bank 0 */ + ktop = PGROUND((ulong)end); + ktop = PADDR(ktop) - conf.base0; + conf.npage0 -= ktop/BY2PG; + conf.base0 += ktop; +} + +void +cpuidprint(void) +{ + ulong v; + + print("PVR: "); + switch(m->cputype){ + case 0x01: print("MPC601"); break; + case 0x03: print("MPC603"); break; + case 0x04: print("MPC604"); break; + case 0x06: print("MPC603e"); break; + case 0x07: print("MPC603e-v7"); break; + case 0x50: print("MPC8xx"); break; + default: print("PowerPC version #%x", m->cputype); break; + } + print(", revision #%lux\n", getpvr()&0xffff); + print("IMMR: "); + v = getimmr() & 0xFFFF; + switch(v>>8){ + case 0x00: print("MPC860/821"); break; + case 0x20: print("MPC823"); break; + case 0x21: print("MPC823A"); break; + default: print("Type #%lux", v>>8); break; + } + print(", mask #%lux\n", v&0xFF); + print("%lud MHz system\n", m->cpuhz/MHz); + print("\n"); + + if(Showports){ + + print("plprcr=%8.8lux sccr=%8.8lux\n", m->iomem->plprcr, m->iomem->sccr); + print("pipr=%8.8lux\n", m->iomem->pipr); + + print("ports:\n"); + for(v=0;v<nelem(ports);v++) + print("%2ld %8.8lux\n", v, ports[v]); + + /* dump the memory configuration while we're at it */ + for(v=0; v<nelem(m->iomem->memc); v++) + if(m->iomem->memc[v].base & 1) + print("%ld %8.8lux %8.8lux\n", v, m->iomem->memc[v].base, m->iomem->memc[v].option); + } +} + +/* + * fetch parameters from flash, as stored by BSE bootstrap, + * compensating for a bug in its fset that produces silly entries. + */ + +static int +envnameok(char *s) +{ + if(*s == '*') + s++; + if(*s >= '0' && *s <= '9' || *s == 0) + return 0; + for(; *s; s++) + if(*s >= '0' && *s <= '9' || + *s >= 'a' && *s <= 'z' || + *s >= 'A' && *s <= 'Z' || + *s == '.' || *s == '_' || *s == '#'){ + /* ok */ + }else + return 0; + return 1; +} + +int +archconfval(char **names, char **vals, int limit) +{ + uchar *b, *e; + char *s; + int n, v, l, o; + static char bootargs[512]; + + /* we assume we can access this space before mmuinit() */ + b = KADDR(PHYSFLASH+0x4000); + if(*b & 1){ + b += 0x2000; /* try alternative location */ + if(*b & 1) + return 0; + } + v = (b[2]<<8)|b[3]; + b += 4; + if(v >= 0x2000-4) + return 0; + n = 0; + o = 0; + e = b+v; + for(; b < e; b += v){ + v = *b; + if(v == 0xFF || n >= limit) + break; + s = (char*)b+1; + if(v >= 0x80){ + v = ((v&0x7F)<<8) | b[1]; + s++; + } + if(envnameok(s)){ + names[n] = s; + s += strlen(s)+1; + l = strlen(s)+1; + if(o+l > sizeof(bootargs)) + break; + vals[n] = bootargs+o; + memmove(vals[n], s, l); + o += l; + n++; + } + } + return n; +} + +void +toggleled(int b) +{ + int s; + s = splhi(); + m->iomem->pdpar &= ~(0x20<<b); + m->iomem->pddir |= 0x20<<b; + m->iomem->pddat ^= 0x020<<b; + splx(s); +} + +/* + * provide value for #r/switch (devrtc.c) + */ +int +archoptionsw(void) +{ + return 0; +} + +/* + * invoked by clock.c:/^clockintr + */ +static void +twinkle(void) +{ + if(m->ticks%MS2TK(1000) == 0 && m->iomem) + toggleled(0); +} + +void (*archclocktick)(void) = twinkle; + +/* + * invoked by ../port/taslock.c:/^ilock: + * reset watchdog timer here, if there is one and it is enabled + */ +void +clockcheck(void) +{ +} + +/* + * for ../port/devflash.c:/^flashreset + * retrieve flash type, virtual base and length and return 0; + * return -1 on error (no flash) + */ +int +archflashreset(int bank, Flash *f) +{ + if(bank != 0) + return -1; + f->type = "Intel28F320B3B"; + f->addr = KADDR(PHYSFLASH); + f->size = 4*1024*1024; + f->width = 2; + return 0; +} + +void +archflashwp(Flash*, int) +{ +} + +/* + * set ether parameters: the contents should be derived from EEPROM or NVRAM + */ +int +archether(int ctlno, Ether *ether) +{ + if(isaconfig("ether", ctlno, ether) == 0 && ctlno > 0) + return -1; + if(ctlno == 0){ + ether->type = "SCC"; + ether->port = 2; + } + memmove(ether->ea, KADDR(PHYSFLASH+0x3FFA), Eaddrlen); + return 1; +} + +/* + * enable the clocks for the given SCC ether and reveal them to the caller. + * do anything else required to prepare the transceiver (eg, set full-duplex, reset loopback). + */ +int +archetherenable(int cpmid, int *rcs, int *tcs, int mbps, int fd) +{ + IMM *io; + + if(cpmid != CPscc2) + return -1; + USED(mbps); + io = ioplock(); + io->pcpar &= ~EnetLoopback; + io->pcso &= ~EnetLoopback; + io->pcdir |= EnetLoopback; + io->pcdat &= ~EnetLoopback; + if(0){ /* TO CHECK: causes ether errors if used */ + io->pbpar &= ~EnetFullDuplex; + io->pbdir |= EnetFullDuplex; + if(fd) + io->pbdat |= EnetFullDuplex; + else + io->pbdat &= ~EnetFullDuplex; + } + io->pbpar &= ~EnableEnet; + io->pbdir |= EnableEnet; + io->pbdat |= EnableEnet; + io->papar |= SIBIT(7)|SIBIT(6); /* enable CLK1 and CLK2 */ + io->padir &= ~(SIBIT(7)|SIBIT(6)); + iopunlock(); + *rcs = CLK2; + *tcs = CLK1; + return 0; +} + +/* + * do anything extra required to enable the UART on the given CPM port + */ +static ulong uartsactive; + +void +archenableuart(int id, int irda) +{ + IMM *io; + + USED(id); /* both uarts seem to be controlled by the same bit */ + USED(irda); /* no IrDA on ipEngine */ + io = ioplock(); + if(uartsactive == 0){ + io->pbpar &= ~EnableRS232; + io->pbdir |= EnableRS232; + io->pbdat |= EnableRS232; + } + uartsactive |= 1<<id; + iopunlock(); +} + +/* + * do anything extra required to disable the UART on the given CPM port + */ +void +archdisableuart(int id) +{ + IMM *io; + + io = ioplock(); + uartsactive &= ~(1<<id); + if(uartsactive == 0) + io->pbdat &= ~EnableRS232; + iopunlock(); +} + +/* + * enable the external USB transceiver + * speed is 12MHz if highspeed is non-zero; 1.5MHz if zero + * master is non-zero if the node is acting as USB Host and should provide power + */ +void +archenableusb(int highspeed, int master) +{ + IMM *io; + + USED(master); + io = ioplock(); + io->pcpar &= ~USBFullSpeed; + io->pcso &= ~USBFullSpeed; + if(highspeed) + io->pcdat |= USBFullSpeed; + else + io->pcdat &= ~USBFullSpeed; + io->pcdir |= USBFullSpeed; + iopunlock(); +} + +/* + * shut down the USB transceiver + */ +void +archdisableusb(void) +{ + /* nothing to be done on ipEngine, apparently */ +} + +/* + * set the external infrared transceiver to the given speed + */ +void +archsetirxcvr(int highspeed) +{ + USED(highspeed); +} + +/* + * force hardware reset/reboot + */ +void +archreboot(void) +{ + IMM *io; + + io = m->iomem; + io->plprcrk = KEEP_ALIVE_KEY; + io->plprcr |= 1<<7; /* checkstop reset enable */ + io->plprcrk = ~KEEP_ALIVE_KEY; + eieio(); + io->sdcr = 1; + eieio(); + io->lccr = 0; /* switch LCD off */ + eieio(); + firmware(0); +} + +/* + * enable/disable the LCD panel's backlight + */ +void +archbacklight(int on) +{ + USED(on); +} + +/* + * set parameters to describe the screen + */ +int +archlcdmode(Mode *m) +{ + /* sample parameters in case a panel is attached to the external pins */ + m->x = 640; + m->y = 480; + m->d = 3; + m->lcd.freq = 25000000; + m->lcd.ac = 0; + m->lcd.vpw = 1; + m->lcd.wbf = 33; + m->lcd.wbl = 228; + m->lcd.flags = IsColour | IsTFT | OELow | VsyncLow | ClockLow; + return -1; /* there isn't a screen */ +} + +/* + * there isn't a keyboard port + */ +void +archkbdinit(void) +{ +} diff --git a/os/ipengine/archipe.h b/os/ipengine/archipe.h new file mode 100644 index 00000000..575f7d8d --- /dev/null +++ b/os/ipengine/archipe.h @@ -0,0 +1,32 @@ +/* + * values for Brightstar Engineering ipEngine + */ +enum { + /* CS assignment */ + BOOTCS = 0, /* flash */ + FPGACS = 1, /* 8Mb FPGA space */ + DRAMCS = 2, + FPGACONFCS = 3, /* FPGA config */ + CLOCKCS = 4, /* clock synth reg */ +}; + +enum { + /* port A pins */ + VCLK= SIBIT(5), + BCLK= SIBIT(4), + + /* port B */ + EnableVCLK= IBIT(30), + EnableEnet= IBIT(29), + EnableRS232= IBIT(28), + EnetFullDuplex= IBIT(16), + + /* port C */ + nCONFIG = SIBIT(13), /* FPGA configuration */ + USBFullSpeed= SIBIT(12), + PDN= SIBIT(5), /* ? seems to control power to FPGA subsystem? */ + EnetLoopback= SIBIT(4), + + /* nSTATUS is ip_b1, conf_done is ip_b0 in PIPR (hardware doc wrongly says ip_b2 and ip_b1) */ + +}; diff --git a/os/ipengine/dat.h b/os/ipengine/dat.h new file mode 100644 index 00000000..19d7c560 --- /dev/null +++ b/os/ipengine/dat.h @@ -0,0 +1,162 @@ +typedef struct Conf Conf; +typedef struct FPU FPU; +typedef struct FPenv FPenv; +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 Map Map; +typedef struct Power Power; +typedef struct RMap RMap; +typedef struct Ureg Ureg; + +typedef ulong Instr; + +#define MACHP(n) (n==0? &mach0 : *(Mach**)0) + +struct Lock +{ + ulong key; + ulong pc; + ulong sr; + int pri; +}; + +struct Label +{ + ulong sp; + ulong pc; +}; + +/* + * Proc.fpstate + */ +enum +{ + FPINIT, + FPACTIVE, + FPINACTIVE, +}; + +/* + * This structure must agree with FPsave and FPrestore asm routines + */ +struct FPenv +{ + union { + double fpscrd; + struct { + ulong pad; + ulong fpscr; + }; + }; + int fpistate; /* emulated fp */ + ulong emreg[32][3]; /* emulated fp */ +}; +/* + * This structure must agree with fpsave and fprestore asm routines + */ +struct FPU +{ + double fpreg[32]; + FPenv env; +}; + +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 base0; /* base of bank 0 */ + ulong base1; /* base of bank 1 */ + ulong ialloc; /* max interrupt time allocation in bytes */ + + int nscc; /* number of SCCs implemented */ + ulong smcuarts; /* bits for SMCs to define as eiaN */ + ulong sccuarts; /* bits for SCCs to define as eiaN */ + int nocts2; /* CTS2 and CD2 aren't connected */ + uchar* nvrambase; /* virtual address of nvram */ + ulong nvramsize; /* size in bytes */ +}; + +#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<<m->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 */ + + /* MUST BE LAST */ + int stack[1]; +}; +extern Mach mach0; + + +/* + * a parsed .ini line + */ +#define NISAOPT 8 + +struct ISAConf { + char* type; + ulong port; + ulong irq; + ulong mem; + int dma; + ulong size; + ulong freq; + uchar bus; + + int nopt; + char* opt[NISAOPT]; +}; + +struct Map { + int size; + ulong addr; +}; + +struct RMap { + char* name; + Map* map; + Map* mapend; + + Lock; +}; + +struct Power { + Dev* dev; + int (*powerdown)(Power*); + int (*powerup)(Power*); + int state; + void* arg; +}; + +extern register Mach *m; +extern register Proc *up; diff --git a/os/ipengine/devfpga.c b/os/ipengine/devfpga.c new file mode 100644 index 00000000..41d1a445 --- /dev/null +++ b/os/ipengine/devfpga.c @@ -0,0 +1,389 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "../port/error.h" + +#include "io.h" +#include "archipe.h" + +enum { + FPGASIZE = 8*1024*1024, + FPGATMR = 2-1, /* BCLK timer number (mapped to origin 0) */ + TIMERSH = FPGATMR*4, /* timer field shift */ + + COM3= IBIT(1)|IBIT(2), /* sccr: clock output disabled */ + + ConfDone = 1<<1, + nStatus = 1<<0, +}; + +/* + * provisional FPGA interface for simple development work; + * for more complex things, use this to load the device then have a + * purpose-built device driver or module + */ + +enum{ + Qdir, + Qmemb, + Qmemw, + Qprog, + Qctl, + Qclk, + Qstatus, +}; + +static struct { + QLock; + int clkspeed; +} fpga; + +static void resetfpga(void); +static void startfpga(int); +static int endfpga(void); +static int fpgastatus(void); +static void powerfpga(int); +static void vclkenable(int); +static void vclkset(char*, char*, char*, char*); +static void memmovew(ushort*, ushort*, long); + +static Dirtab fpgadir[]={ + ".", {Qdir, 0, QTDIR}, 0, 0555, + "fpgamemb", {Qmemb, 0}, FPGASIZE, 0666, + "fpgamemw", {Qmemw, 0}, FPGASIZE, 0666, + "fpgaprog", {Qprog, 0}, 0, 0222, + "fpgastatus", {Qstatus, 0}, 0, 0444, + "fpgactl", {Qctl, 0}, 0, 0666, + "fpgaclk", {Qclk, 0}, 0, 0666, +}; + +static char Eodd[] = "odd count or offset"; + +static void +fpgareset(void) +{ + powerfpga(0); +} + +static Chan* +fpgaattach(char *spec) +{ + return devattach('G', spec); +} + +static Walkqid* +fpgawalk(Chan *c, Chan *nc, char **name, int nname) +{ + return devwalk(c, nc, name, nname, fpgadir, nelem(fpgadir), devgen); +} + +static int +fpgastat(Chan *c, uchar *dp, int n) +{ + return devstat(c, dp, n, fpgadir, nelem(fpgadir), devgen); +} + +static Chan* +fpgaopen(Chan *c, int omode) +{ + return devopen(c, omode, fpgadir, nelem(fpgadir), devgen); +} + +static void +fpgaclose(Chan*) +{ +} + +static long +fpgaread(Chan *c, void *buf, long n, vlong offset) +{ + int v; + char stat[32], *p; + + if(c->qid.type & QTDIR) + return devdirread(c, buf, n, fpgadir, nelem(fpgadir), devgen); + + switch((ulong)c->qid.path){ + case Qmemb: + if(offset >= FPGASIZE) + return 0; + if(offset+n >= FPGASIZE) + n = FPGASIZE-offset; + memmove(buf, KADDR(FPGAMEM+offset), n); + return n; + case Qmemw: + if((n | offset) & 1) + error(Eodd); + if(offset >= FPGASIZE) + return 0; + if(offset+n >= FPGASIZE) + n = FPGASIZE-offset; + memmovew((ushort*)buf, (ushort*)KADDR(FPGAMEM+offset), n); + return n; + case Qstatus: + v = fpgastatus(); + p = seprint(stat, stat+sizeof(stat), "%sconfig", v&ConfDone?"":"!"); + seprint(p, stat+sizeof(stat), " %sstatus\n", v&nStatus?"":"!"); + return readstr(offset, buf, n, stat); + case Qclk: + return readnum(offset, buf, n, fpga.clkspeed, NUMSIZE); + case Qctl: + case Qprog: + return 0; + } + error(Egreg); + return 0; /* not reached */ +} + +static long +fpgawrite(Chan *c, void *buf, long n, vlong offset) +{ + int i, j, v; + ulong w; + Cmdbuf *cb; + ulong *cfg; + uchar *cp; + + switch((ulong)c->qid.path){ + case Qmemb: + if(offset >= FPGASIZE) + return 0; + if(offset+n >= FPGASIZE) + n = FPGASIZE-offset; + memmove(KADDR(FPGAMEM+offset), buf, n); + return n; + case Qmemw: + if((n | offset) & 1) + error(Eodd); + if(offset >= FPGASIZE) + return 0; + if(offset+n >= FPGASIZE) + n = FPGASIZE-offset; + memmovew((ushort*)KADDR(FPGAMEM+offset), (ushort*)buf, n); + return n; + case Qctl: + cb = parsecmd(buf, n); + if(waserror()){ + free(cb); + nexterror(); + } + if(cb->nf < 1) + error(Ebadarg); + if(strcmp(cb->f[0], "reset") == 0) + resetfpga(); + else if(strcmp(cb->f[0], "bclk") == 0){ + v = 48; + if(cb->nf > 1) + v = strtoul(cb->f[1], nil, 0); + if(v <= 0 || 48%v != 0) + error(Ebadarg); + startfpga(48/v-1); + }else if(strcmp(cb->f[0], "vclk") == 0){ + if(cb->nf == 5){ /* vclk n m v r */ + vclkenable(1); + vclkset(cb->f[1], cb->f[2], cb->f[3], cb->f[4]); + }else + vclkenable(cb->nf < 2 || strcmp(cb->f[1], "on") == 0); + }else if(strcmp(cb->f[0], "power") == 0) + powerfpga(cb->nf < 2 || strcmp(cb->f[1], "off") != 0); + else + error(Ebadarg); + poperror(); + free(cb); + return n; + case Qprog: + qlock(&fpga); + if(waserror()){ + qunlock(&fpga); + nexterror(); + } + powerfpga(1); + resetfpga(); + cfg = KADDR(FPGACR); + cp = buf; + for(i=0; i<n; i++){ + w = cp[i]; + for(j=0; j<8; j++){ + *cfg = w&1; + w >>= 1; + } + } + for(j=0; j<50; j++) /* Altera note says at least 10 clock cycles, but microblaster uses 50 */ + *cfg = 0; + v = fpgastatus(); + if(v != (nStatus|ConfDone)){ + snprint(up->genbuf, sizeof(up->genbuf), "error loading fpga: status %d", v); + error(up->genbuf); + } + poperror(); + qunlock(&fpga); + return n; + } + error(Egreg); + return 0; /* not reached */ +} + +/* + * PDN seems to control power to the FPGA subsystem + * but it is not documented nor is its scope clear (PLL as well?). + * It will not run without it. + */ +static void +powerfpga(int on) +{ + IMM *io; + + io = ioplock(); + if(io->sccr & COM3){ + io->sccrk = KEEP_ALIVE_KEY; + io->sccr &= ~ COM3; /* FPGA designs can use the clock */ + io->sccrk = ~KEEP_ALIVE_KEY; + } + io->pcpar &= ~PDN; + io->pcdir |= PDN; + if(on) + io->pcdat &= ~PDN; + else + io->pcdat |= PDN; + iopunlock(); +} + +static void +resetfpga(void) +{ + IMM *io; + + io = ioplock(); + io->pcpar &= ~nCONFIG; + io->pcdir |= nCONFIG; + io->pcdat &= ~nCONFIG; + microdelay(200); + io->pcdat |= nCONFIG; + iopunlock(); +} + +static int +fpgastatus(void) +{ + /* isolate status bits IP_B0 and IP_B1 */ + return (m->iomem->pipr>>14) & (ConfDone|nStatus); +} + +static void +startfpga(int scale) +{ + IMM *io; + + io = ioplock(); + io->tgcr &= ~(0xF<<TIMERSH); + io->tmr2 = ((scale&0xFF)<<8) | 0x2A; + io->tcn2 = 0; + io->trr2 = 0; + io->ter2 = 0xFFFF; + io->tgcr |= 0x1<<TIMERSH; + io->padir |= BCLK; + io->papar |= BCLK; + iopunlock(); +} + +static void +vclkenable(int i) +{ + IMM *io; + + io = ioplock(); + io->padir &= ~VCLK; + io->papar &= ~VCLK; + io->pbdir |= EnableVCLK; + io->pbpar &= ~EnableVCLK; + if(i) + io->pbdat |= EnableVCLK; + else + io->pbdat &= ~EnableVCLK; + iopunlock(); +} + +static void +vclkin(ulong *clk, int v) +{ + int i; + + for(i=0; i<7; i++) + *clk = (v>>i) & 1; +} + +static void +vclkset(char *ns, char *ms, char *vs, char *rs) +{ + int n, m, v, r; + ulong *clk; + + clk = KADDR(CLOCKCR); + n = strtol(ns, nil, 0); + m = strtol(ms, nil, 0); + v = strtol(vs, nil, 0); + r = strtol(rs, nil, 0); + if(n < 3 || n > 127 || m < 3 || m > 127 || v != 1 && v != 8 || + r != 1 && r != 2 && r != 4 && r != 8) + error(Ebadarg); + vclkenable(0); + vclkin(clk, n); + vclkin(clk, m); + *clk = (v==0) & 1; + *clk = 1; *clk = 1; + *clk = r == 2 || r == 8; + *clk = r == 4 || r == 8; + *clk = 1; /* clock out */ + *clk = 0; /* disable clk/x */ + *clk = 1; *clk = 0; *clk = 1; + *clk = 0; *clk = 0; *clk = 0; + vclkenable(1); +} + +/* + * copy data aligned on 16-bit word boundaries. + */ +static void +memmovew(ushort *to, ushort *from, long count) +{ + int n; + + if(count <= 0) + return; + count >>= 1; + n = (count+7) >> 3; + switch(count&7) { /* Duff's device */ + case 0: do { *to++ = *from++; + case 7: *to++ = *from++; + case 6: *to++ = *from++; + case 5: *to++ = *from++; + case 4: *to++ = *from++; + case 3: *to++ = *from++; + case 2: *to++ = *from++; + case 1: *to++ = *from++; + } while(--n > 0); + } +} + +Dev fpgadevtab = { + 'G', + "fpga", + + fpgareset, + devinit, + devshutdown, + fpgaattach, + fpgawalk, + fpgastat, + fpgaopen, + devcreate, + fpgaclose, + fpgaread, + devbread, + fpgawrite, + devbwrite, + devremove, + devwstat, +}; diff --git a/os/ipengine/flash28f320b3b.c b/os/ipengine/flash28f320b3b.c new file mode 100644 index 00000000..27bb90d6 --- /dev/null +++ b/os/ipengine/flash28f320b3b.c @@ -0,0 +1,43 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" +#include "../port/error.h" + +#include "../port/flashif.h" + +/* + * Intel 28F320B3B in word mode + */ + +#define I(x) (x) +enum { + ReadArray = 0x00FF, +}; + +#include "../port/flashintel" + +static int +reset(Flash *f) +{ + f->id = 0x0089; /* can't use autoselect: might be running in flash */ + f->devid = 0x8897; + f->write = intelwrite2; + f->erasezone = intelerase; + f->width = 2; + f->cmask = 0x00FF; + *(ushort*)f->addr = ClearStatus; + *(ushort*)f->addr = ReadArray; + f->nr = 2; + f->regions[0] = (Flashregion){8, 0, 8*(8*1024), 8*1024, 0}; + f->regions[1] = (Flashregion){63, 64*1024, 4*1024*1024, 64*1024, 0}; + return 0; +} + +void +flash28f320b3blink(void) +{ + addflashcard("Intel28F320B3B", reset); +} diff --git a/os/ipengine/fns.h b/os/ipengine/fns.h new file mode 100644 index 00000000..6a92e5cd --- /dev/null +++ b/os/ipengine/fns.h @@ -0,0 +1,120 @@ +#include "../port/portfns.h" + +void addpower(Power*); +void archbacklight(int); +void archconfinit(void); +int archconfval(char**, char**, int); +void archdisableuart(int); +void archdisableusb(void); +void archdisablevideo(void); +void archenableuart(int, int); +void archenableusb(int, int); +void archenablevideo(void); +void archkbdinit(void); +void archresetvideo(void); +int archetherenable(int, int*, int*, int, int); +void archinit(void); +int archoptionsw(void); +void archreboot(void); +void archsetirxcvr(int); +uchar* archvideobuffer(long); +ulong baudgen(int, int); +int brgalloc(void); +void brgfree(int); +int cistrcmp(char*, char*); +int cistrncmp(char*, char*, int); +void clockcheck(void); +void clockinit(void); +void clockintr(Ureg*); +void clrfptrap(void); +#define coherence() /* nothing needed for uniprocessor */ +void cpminit(void); +void cpuidprint(void); +void dcflush(void*, ulong); +void dcinval(void*, ulong); +void delay(int); +void dtlbmiss(void); +void dumplongs(char*, ulong*, int); +void dumpregs(Ureg*); +void eieio(void); +void faultpower(Ureg*); +void firmware(int); +void fpinit(void); +int fpipower(Ureg*); +void fpoff(void); +void fprestore(FPU*); +void fpsave(FPU*); +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); +#define idlehands() /* nothing to do in the runproc */ +void intr(Ureg*); +void intrenable(int, void (*)(Ureg*, void*), void*, int, char*); +void intrdisable(int, void (*)(Ureg*, void*), void*, int, char*); +int intrstats(char*, int); +void intrvec(void); +int isaconfig(char*, int, ISAConf*); +int isvalid_va(void*); +void itlbmiss(void); +void kbdinit(void); +void kbdreset(void); +void lcdpanel(int); +void links(void); +void mapfree(RMap*, ulong, int); +void mapinit(RMap*, Map*, int); +void mathinit(void); +void mmuinit(void); +ulong* mmuwalk(ulong*, ulong, int); +void pcmenable(void); +void pcmintrenable(int, void (*)(Ureg*, void*), void*); +int pcmpin(int slot, int type); +void pcmpower(int, int); +int pcmpowered(int); +void pcmsetvcc(int, int); +void pcmsetvpp(int, int); +void procsave(Proc*); +void procsetup(Proc*); +void putdec(ulong); +void putmsr(ulong); +void puttwb(ulong); +ulong rmapalloc(RMap*, ulong, int, int); +void screeninit(void); +int screenprint(char*, ...); /* debugging */ +void (*screenputs)(char*, int); +int segflush(void*, ulong); +void toggleled(int); +void setpanic(void); +long spioutin(void*, long, void*); +void spireset(void); +ulong _tas(ulong*); +void trapinit(void); +void trapvec(void); +void uartinstall(void); +void uartspecial(int, int, Queue**, Queue**, int (*)(Queue*, int)); +void uartwait(void); /* debugging */ +void videoreset(void); +void videotest(void); +void wbflush(void); + +#define waserror() (up->nerrlab++, setlabel(&up->errlab[up->nerrlab-1])) +ulong getcallerpc(void*); + +#define KADDR(a) ((void*)((ulong)(a)|KZERO)) +#define PADDR(a) ((((ulong)(a)&KSEGM)!=KSEG0)?(ulong)(a):((ulong)(a)&~KZERO)) + +/* IBM bit field order */ +#define IBIT(b) ((ulong)1<<(31-(b))) +#define SIBIT(n) ((ushort)1<<(15-(n))) + +/* compatibility with inf2.1 */ diff --git a/os/ipengine/io.h b/os/ipengine/io.h new file mode 100644 index 00000000..30312c68 --- /dev/null +++ b/os/ipengine/io.h @@ -0,0 +1 @@ +#include "../mpc/800io.h" diff --git a/os/ipengine/ipe b/os/ipengine/ipe new file mode 100644 index 00000000..8e00c855 --- /dev/null +++ b/os/ipengine/ipe @@ -0,0 +1,109 @@ +# Bright Star Engineering ipEngine-1 +dev + root + cons archipe + env + mnt + pipe + prog + rtc + srv + dup + ssl + cap + sign + + ip bootp ip ipv6 ipaux iproute arp netlog ptclbsum iprouter plan9 nullmedium pktmedium netaux + ether netif netaux ethermedium + uart + flash +# i2c i2c + + ftl + + fpga + +ip + il + tcp + udp +# rudp +# igmp + ipifc + icmp + icmp6 + ipmux + +lib + interp + keyring + sec + mp + math + kern + +link + etherscc + ethermedium + flash28f320b3b + +mod + math + sys + keyring + +port + alarm + alloc + allocb + chan + dev + dial + dis + discall + exception + exportfs + inferno + latin1 + nocache + nodynld + parse + pgrp + print + proc + qio + qlock + random + sysfile + taslock + xalloc + +code + int cflag = 0; + int consoleprint = 1; + int panicreset = 0; + int main_pool_pcnt = 50; + int heap_pool_pcnt = 50; + int image_pool_pcnt = 0; + void screeninit(void){} + +init + ipeinit + +root + /chan / + /dev / + /dis / + /env / + /fd / + /n / + /net / + /nvfs / + /prog / + /osinit.dis + /dis/lib/auth.dis + /dis/lib/ssl.dis + /n/local / + /n/remote / +# authentication + /nvfs/default /usr/inferno/keyring/default diff --git a/os/ipengine/main.c b/os/ipengine/main.c new file mode 100644 index 00000000..cdd7ed58 --- /dev/null +++ b/os/ipengine/main.c @@ -0,0 +1,348 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" +#include "io.h" +#include "ureg.h" +#include "version.h" + +#define MAXCONF 32 + +extern ulong kerndate; +extern int cflag; +int remotedebug; + +extern int main_pool_pcnt; +extern int heap_pool_pcnt; +extern int image_pool_pcnt; + +char *confname[MAXCONF]; +char *confval[MAXCONF]; +int nconf; + +void addconf(char *, char *); + +static void +options(void) +{ + nconf = archconfval(confname, confval, sizeof(confname)); +} + +void +doc(char *m) +{ + USED(m); + //iprint("%s...\n", m); +} + +static void +poolsizeinit(void) +{ + ulong nb; + + nb = conf.npage*BY2PG; + poolsize(mainmem, (nb*main_pool_pcnt)/100, 0); + poolsize(heapmem, (nb*heap_pool_pcnt)/100, 0); + poolsize(imagmem, (nb*image_pool_pcnt)/100, 1); +} + +static void +serialconsole(void) +{ + char *p; + int port, baud; + + p = getconf("console"); + if(p == nil) + p = "0"; + if(p != nil && !remotedebug){ + port = strtol(p, nil, 0); + baud = 9600; + p = getconf("baud"); + if(p != nil){ + baud = strtol(p, nil, 0); + if(baud < 9600) + baud = 9600; + } + uartspecial(port, baud, &kbdq, &printq, kbdcr2nl); + } +} + +void +main(void) +{ + machinit(); + options(); + archinit(); + quotefmtinstall(); + confinit(); + cpminit(); + xinit(); + poolsizeinit(); + trapinit(); + mmuinit(); + printinit(); + uartinstall(); + serialconsole(); + doc("screeninit"); + screeninit(); + doc("kbdinit"); + kbdinit(); + doc("clockinit"); + clockinit(); + doc("procinit"); + procinit(); + cpuidprint(); + doc("links"); + links(); + doc("chandevreset"); + chandevreset(); + + eve = strdup("inferno"); + + print("\nInferno %s\n", VERSION); + print("Vita Nuova\n"); + print("conf %s (%lud) jit %d\n\n",conffile, kerndate, cflag); + + doc("userinit"); + userinit(); + doc("schedinit"); + schedinit(); +} + +void +machinit(void) +{ + int n; + + n = m->machno; + memset(m, 0, sizeof(Mach)); + m->machno = n; + m->mmask = 1<<m->machno; + m->iomem = KADDR(getimmr() & ~0xFFFF); + m->cputype = getpvr()>>16; + m->delayloop = 20000; /* initial estimate only; set by clockinit */ + m->speed = 50; /* initial estimate only; set by archinit */ +} + +void +init0(void) +{ + Osenv *o; + int i; + char buf[2*KNAMELEN]; + + up->nerrlab = 0; + + spllo(); + + if(waserror()) + panic("init0"); + /* + * These are o.k. because rootinit is null. + * Then early kproc's will have a root and dot. + */ + o = up->env; + o->pgrp->slash = namec("#/", Atodir, 0, 0); + cnameclose(o->pgrp->slash->name); + o->pgrp->slash->name = newcname("/"); + o->pgrp->dot = cclone(o->pgrp->slash); + + chandevinit(); + + if(!waserror()){ + ksetenv("cputype", "power", 0); + snprint(buf, sizeof(buf), "power %s", conffile); + ksetenv("terminal", buf, 0); + poperror(); + } + for(i = 0; i < nconf; i++) + if(confname[i][0] != '*'){ + if(!waserror()){ + ksetenv(confname[i], confval[i], 0); + poperror(); + } + } + + poperror(); + disinit("/osinit.dis"); +} + +void +userinit(void) +{ + Proc *p; + Osenv *o; + + p = newproc(); + o = p->env; + + o->fgrp = newfgrp(nil); + o->pgrp = newpgrp(); + o->egrp = newegrp(); + kstrdup(&o->user, eve); + + strcpy(p->text, "interp"); + + /* + * Kernel Stack + */ + p->sched.pc = (ulong)init0; + p->sched.sp = (ulong)p->kstack+KSTACK; + + ready(p); +} + +Conf conf; + +void +addconf(char *name, char *val) +{ + if(nconf >= MAXCONF) + return; + confname[nconf] = name; + confval[nconf] = val; + nconf++; +} + +char* +getconf(char *name) +{ + int i; + + for(i = 0; i < nconf; i++) + if(cistrcmp(confname[i], name) == 0) + return confval[i]; + return 0; +} + +void +confinit(void) +{ + char *p; + int pcnt; + + if(p = getconf("*kernelpercent")) + pcnt = 100 - strtol(p, 0, 0); + else + pcnt = 0; + + conf.nscc = 4; + conf.smcuarts = (1<<1)|(1<<0); /* SMC2, SMC1 (usual console) */ + conf.sccuarts = 0; /* SCC2 not available by default (it's Ether) */ + + archconfinit(); + + conf.npage = conf.npage0 + conf.npage1; + if(pcnt < 10) + pcnt = 70; + conf.ialloc = (((conf.npage*(100-pcnt))/100)/2)*BY2PG; + + conf.nproc = 100 + ((conf.npage*BY2PG)/MB)*5; + conf.nmach = MAXMACH; +} + +void +exit(int ispanic) +{ + up = 0; + toggleled(3); + spllo(); + print("cpu %d exiting\n", m->machno); + + /* Shutdown running devices */ + chandevshutdown(); + + delay(1000); + splhi(); + if(ispanic) + for(;;); + archreboot(); +} + +void +reboot(void) +{ + exit(0); +} + +void +halt(void) +{ + print("cpu halted\n"); + microdelay(1000); + for(;;) + ; +} + +int +isaconfig(char *class, int ctlrno, ISAConf *isa) +{ + char cc[KNAMELEN], *p; + int i; + + snprint(cc, sizeof cc, "%s%d", class, ctlrno); + p = getconf(cc); + if(p == nil) + return 0; + + isa->nopt = tokenize(p, isa->opt, NISAOPT); + for(i = 0; i < isa->nopt; i++){ + p = isa->opt[i]; + if(cistrncmp(p, "type=", 5) == 0) + isa->type = p + 5; + else if(cistrncmp(p, "port=", 5) == 0) + isa->port = strtoul(p+5, &p, 0); + else if(cistrncmp(p, "irq=", 4) == 0) + isa->irq = strtoul(p+4, &p, 0); + else if(cistrncmp(p, "mem=", 4) == 0) + isa->mem = strtoul(p+4, &p, 0); + else if(cistrncmp(p, "size=", 5) == 0) + isa->size = strtoul(p+5, &p, 0); + else if(cistrncmp(p, "freq=", 5) == 0) + isa->freq = strtoul(p+5, &p, 0); + else if(cistrncmp(p, "dma=", 4) == 0) + isa->dma = strtoul(p+4, &p, 0); + } + return 1; +} + +/* + * Save the mach dependent part of the process state. + */ +void +procsave(Proc*) +{ +} + +void +uartputs(char *s, int n) +{ +// screenputs(buf, n); + putstrn(s, n); + uartwait(); +} + +/* stubs */ +void +setfsr(ulong) +{ +} + +ulong +getfsr() +{ + return 0; +} + +void +setfcr(ulong) +{ +} + +ulong +getfcr() +{ + return 0; +} diff --git a/os/ipengine/mem.h b/os/ipengine/mem.h new file mode 100644 index 00000000..4934fc50 --- /dev/null +++ b/os/ipengine/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<<CACHELINELOG) + +#define MAXMACH 1 /* max # cpus system can run */ +#define MACHSIZE BY2PG + +/* + * Time + */ +#define HZ 100 /* clock frequency */ +#define MS2HZ (1000/HZ) /* millisec per clock tick */ +#define TK2SEC(t) ((t)/HZ) /* ticks to seconds */ +#define MS2TK(t) ((t)/MS2HZ) /* milliseconds to ticks */ +#define MHz 1000000 + +/* + * MSR bits + */ + +#define POW 0x40000 /* enable power mgmt */ +#define TGPR 0x20000 /* GPR0-3 remapped; 603/603e specific */ +#define ILE 0x10000 /* interrupts little endian */ +#define EE 0x08000 /* enable external/decrementer interrupts */ +#define PR 0x04000 /* =1, user mode */ +#define FPE 0x02000 /* enable floating point */ +#define ME 0x01000 /* enable machine check exceptions */ +#define FE0 0x00800 +#define SE 0x00400 /* single-step trace */ +#define BE 0x00200 /* branch trace */ +#define FE1 0x00100 +#define MSR_IP 0x00040 /* =0, vector to nnnnn; =1, vector to FFFnnnnn */ +#define IR 0x00020 /* enable instruction address translation */ +#define DR 0x00010 /* enable data address translation */ +#define RI 0x00002 /* exception is recoverable */ +#define LE 0x00001 /* little endian mode */ + +#define KMSR (ME|FE0|FE1|FPE) +#define UMSR (KMSR|PR|EE|IR|DR) + +/* + * Magic registers + */ + +#define MACH 30 /* R30 is m-> */ +#define USER 29 /* R29 is up-> */ +#define IOMEMR 28 /* R28 will be iomem-> */ + +/* + * Fundamental addresses + */ + +#define UREGSIZE ((8+32)*4) + +/* + * 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 + +/* TLB and MxEPN flag */ +#define TLBVALID (1<<9) + +/* + * Address spaces + */ + +#define KUSEG 0x00000000 +#define KSEG0 0x20000000 +#define KSEGM 0xE0000000 /* mask to check which seg */ + +#define KZERO KSEG0 /* base of kernel address space */ +#define KTZERO (KZERO+0x3000) /* first address in kernel text */ +#define KSTACK 8192 /* Size of kernel stack */ + +/* + * 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 (8xx) */ +#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 + +/* + * MPC8xx physical addresses (ipEngine) + */ +#define PHYSDRAM 0x00000000 +#define PHYSIMM 0xFF000000 +#define PHYSFLASH 0xFE000000 +#define FPGAMEM 0xFC000000 + +/* extra addresses on ipEngine-1 */ +#define FPGACR 0xFF010000 /* FPGA control */ +#define CLOCKCR 0xFF020000 /* Clock synthesiser register */ + +/* remaining ones are our choice */ +#define PHYSPCMCIA 0x40000000 +#define PCMCIALEN (8*MB) /* chosen to allow mapping by single TLB entry */ +#define ISAIO PHYSPCMCIA /* for inb.s */ + +/* + * MPC8xx dual-ported CPM memory physical addresses + */ +#define PHYSDPRAM (PHYSIMM+0x2000) +#define DPLEN1 0x200 +#define DPLEN2 0x400 +#define DPLEN3 0x800 +#define DPBASE (PHYSDPRAM+DPLEN1) + +#define KEEP_ALIVE_KEY 0x55ccaa33 /* clock and rtc register key */ diff --git a/os/ipengine/mkfile b/os/ipengine/mkfile new file mode 100644 index 00000000..ca6d6373 --- /dev/null +++ b/os/ipengine/mkfile @@ -0,0 +1,105 @@ +SYSTARG=Inferno +OBJTYPE=power +<../../mkconfig + +#Configurable parameters + +CONF=ipe #default configuration +CONFLIST=ipe +KZERO=0x20003020 + +SYSTARG=$OSTARG +OBJTYPE=power +INSTALLDIR=$ROOT/Inferno/$OBJTYPE/bin #path of directory where kernel is installed +#INSTALLDIR=/$OBJTYPE + +#end configurable parameters + +<$ROOT/mkfiles/mkfile-$SYSTARG-$OBJTYPE #set vars based on target system + +<| $SHELLNAME ../port/mkdevlist $CONF #sets $IP, $DEVS, $ETHERS, $VGAS, $PORT, $MISC, $LIBS, $OTHERS + +OBJ=\ + l.$O\ + tlb.$O\ + nofp.$O\ + clock.$O\ + cpm.$O\ + faultpower.$O\ + fpi.$O\ + fpimem.$O\ + fpipower.$O\ + kbd.$O\ + main.$O\ + mmu.$O\ + rmap.$O\ + trap.$O\ + $CONF.root.$O\ + $IP\ + $DEVS\ + $ETHERS\ + $LINKS\ + $VGAS\ + $PORT\ + $MISC\ + $OTHERS\ + +LIBNAMES=${LIBS:%=lib%.a} + +HFILES=\ + mem.h\ + dat.h\ + fns.h\ + io.h\ + ../mpc/800io.h\ + +CFLAGS=-wFV -I. -I../mpc -I../port -I$ROOT/Inferno/$OBJTYPE/include -I$ROOT/include -I$ROOT/libinterp +KERNDATE=`{$NDATE} + +#default:V: i$CONF.sq +default:V: i$CONF + +i$CONF: $OBJ $CONF.c $CONF.root.h $LIBNAMES + $CC $CFLAGS '-DKERNDATE='$KERNDATE $CONF.c + $LD -o $target -T$KZERO -l -R4 $OBJ $CONF.$O $LIBFILES + $KSIZE $target + +i$CONF.sq: i$CONF + sqz -w i$CONF >$target + +install:V: i$CONF # i$CONF.sq + cp i$CONF $INSTALLDIR/i$CONF + #cp i$CONF.sq $INSTALLDIR/i$CONF.sq + +uninstall:V: + rm -f $ROOT/$OBJDIR/bin/i$CONF + rm -f $ROOT/$OBJDIR/bin/i$CONF.sq + +<../port/portmkfile + +%.$O: ../mpc/%.c + $CC $CFLAGS -I. ../mpc/$stem.c + +%.$O: ../mpc/%.s + $AS -I. -I../mpc ../mpc/$stem.s + +../init/$INIT.dis: ../init/$INIT.b + cd ../init; mk $INIT.dis + +clock.$O: $ROOT/Inferno/$OBJTYPE/include/ureg.h +devether.$O: $ROOT/Inferno/$OBJTYPE/include/ureg.h +faultpower.$O: $ROOT/Inferno/$OBJTYPE/include/ureg.h +main.$O: $ROOT/Inferno/$OBJTYPE/include/ureg.h +trap.$O: $ROOT/Inferno/$OBJTYPE/include/ureg.h + +devether.$O $ETHERS: ../mpc/etherif.h ../port/netif.h +archipe.$O: ../mpc/screen.h archipe.h +screen.$O: ../mpc/screen.h + +$IP devip.$O: ../ip/ip.h + +devboot.$O: devboot.c + $CC $CFLAGS devboot.c + +devuart.$O: ../mpc/devuart.c + $CC $CFLAGS ../mpc/devuart.c diff --git a/os/ipengine/mmu.c b/os/ipengine/mmu.c new file mode 100644 index 00000000..c9cd758b --- /dev/null +++ b/os/ipengine/mmu.c @@ -0,0 +1,20 @@ +#include "u.h" +#include "../port/lib.h" +#include "mem.h" +#include "dat.h" +#include "fns.h" + +void +mmuinit(void) +{ + /* the l.s initial TLB settings do all that's required */ +} + +int +segflush(void *a, ulong n) +{ + /* flush dcache then invalidate icache */ + dcflush(a, n); + icflush(a, n); + return 0; +} diff --git a/os/ipengine/tlb.s b/os/ipengine/tlb.s new file mode 100644 index 00000000..c7451823 --- /dev/null +++ b/os/ipengine/tlb.s @@ -0,0 +1,21 @@ +#include "mem.h" +#define MB (1024*1024) + +/* + * 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|PHYSDRAM|TLBVALID, PHYSDRAM|PTEWRITE|PTELPS|PTESH|PTEVALID, PTE8MB|PTEVALID) /* DRAM, 8M */ + TLBE(KZERO|(PHYSDRAM+8*MB)|TLBVALID, (PHYSDRAM+8*MB)|PTEWRITE|PTELPS|PTESH|PTEVALID, PTE8MB|PTEVALID) /* DRAM, 8M */ + TLBE(KZERO|PHYSIMM|TLBVALID, PHYSIMM|PTEWRITE|PTELPS|PTESH|PTECI|PTEVALID, PTE512K|PTEVALID) /* IMMR, 512K (includes FPGA control and clock synth) */ + TLBE(KZERO|PHYSFLASH|TLBVALID, PHYSFLASH|PTEWRITE|PTELPS|PTESH|PTECI|PTEVALID, PTE8MB|PTEWT|PTEVALID) /* Flash, 8M */ + TLBE(KZERO|FPGAMEM|TLBVALID, FPGAMEM|PTEWRITE|PTELPS|PTESH|PTECI|PTEVALID, PTE8MB|PTEG|PTEVALID) /* FPGA mem, 8M */ +TEXT tlbtabe(SB), $-4 + RETURN |
