summaryrefslogtreecommitdiff
path: root/os/cerf405/main.c
diff options
context:
space:
mode:
Diffstat (limited to 'os/cerf405/main.c')
-rw-r--r--os/cerf405/main.c719
1 files changed, 719 insertions, 0 deletions
diff --git a/os/cerf405/main.c b/os/cerf405/main.c
new file mode 100644
index 00000000..11e172fc
--- /dev/null
+++ b/os/cerf405/main.c
@@ -0,0 +1,719 @@
+#include "u.h"
+#include "../port/lib.h"
+#include "mem.h"
+#include "dat.h"
+#include "fns.h"
+#include "io.h"
+#include "ureg.h"
+#include "../ip/ip.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 *);
+void eepromscan(void);
+
+static void
+options(void)
+{
+// nconf = archconfval(confname, confval, sizeof(confname));
+}
+
+void
+doc(char *m)
+{
+ USED(m);
+ iprint("%s...\n", m);
+}
+
+void
+idoc(char *m)
+{
+ uartputs(m, strlen(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 = 115200;
+ 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)
+{
+ idoc("machinit...\n");
+ machinit();
+ idoc("options...\n");
+ compiledcr();
+ options();
+// archinit();
+ quotefmtinstall();
+ idoc("confinit...\n");
+ confinit();
+ xinit();
+ poolsizeinit();
+ poolinit();
+ idoc("trapinit...\n");
+ trapinit();
+ mmuinit();
+ ioinit();
+ printinit();
+ uartinstall();
+ serialconsole();
+ pcimapinit();
+ eepromscan();
+ 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();
+}
+
+//ccdv=1 cbdv=2 opdv=2 epdv=3 mpdv=1 ppdv=2
+
+void
+machinit(void)
+{
+ int n;
+
+ n = m->machno;
+ memset(m, 0, sizeof(Mach));
+ m->machno = n;
+ m->mmask = 1<<m->machno;
+ m->cputype = getpvr()>>16;
+ m->delayloop = 20000; /* initial estimate only; set by clockinit */
+ m->speed = 266; /* initial estimate only; set by archinit */
+ m->cpuhz = 266333333;
+ m->vcohz = 799000000;
+ m->pllhz = 266333333;
+ m->plbhz = 133166666;
+ m->opbhz = 66600000;
+ m->epbhz = 44*MHz;
+ m->pcihz = 66600000;
+ m->clockgen = m->cpuhz; /* it's the internal cpu clock */
+}
+
+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;
+
+ 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;
+
+}
+
+static void
+twinkle(void)
+{
+ if(m->ticks%MS2TK(1000) == 0)
+ ((Gpioregs*)PHYSGPIO)->or ^= 1<<31;
+}
+
+void (*archclocktick)(void) = twinkle;
+
+void
+exit(int ispanic)
+{
+ up = 0;
+ 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(;;)
+ ;
+}
+
+/*
+ * kept in case it's needed for PCI/ISA devices
+ */
+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
+idlehands(void)
+{
+ putmsr(getmsr() | MSR_WE | MSR_EE | MSR_CE); /* MSR_DE as well? */
+}
+
+/* stubs */
+void
+setfsr(ulong)
+{
+}
+
+ulong
+getfsr()
+{
+ return 0;
+}
+
+void
+setfcr(ulong)
+{
+}
+
+ulong
+getfcr()
+{
+ return 0;
+}
+
+/*
+ * some of this is possibly ice-cube specific
+ */
+
+enum {
+ Cpc0Pllmr0= 0xF0, /* PLL mode register 0 */
+ Cpc0Boot= 0xF1, /* clock status */
+ Cpc0Pllmr1= 0xF4, /* PLL mode register 1 */
+ Cpc0Srr= 0xF6, /* PCI soft reset */
+ Cpc0PCI= 0xF9, /* PCI control */
+};
+/*
+00f0 = 00011101
+00f1 = 00000025
+00f2 = 00000000
+00f3 = 00000000
+00f4 = 8085523e
+00f5 = 00000017
+00f6 = 00000000
+ccdv=1 cbdv=2 opdv=2 epdv=3 mpdv=1 ppdv=2
+fbmul=8 fwdva=5 fwdvb=5 tun=257 m=40
+*/
+void
+archconfinit(void)
+{
+ ulong ktop;
+
+ conf.npage0 = (32*1024*1024)/BY2PG;
+ conf.base0 = 0;
+ ktop = PGROUND((ulong)end);
+ ktop = PADDR(ktop) - conf.base0;
+ conf.npage0 -= ktop/BY2PG;
+ conf.base0 += ktop;
+
+ {int i; for(i=0xF0; i<=0xF6; i++){iprint("%.4ux = %.8lux\n", i, getdcr(i));}}
+ {
+ int ccdv, cbdv, opdv, epdv, mpdv, ppdv;
+ int fbmul, fwdva, fwdvb, tun;
+ ulong mr0, mr1;
+
+ mr0 = getdcr(Cpc0Pllmr0);
+ ccdv = ((mr0>>20)&3)+1;
+ cbdv = ((mr0>>16)&3)+1;
+ opdv = ((mr0>>12)&3)+1;
+ epdv = ((mr0>>8)&3)+2;
+ mpdv = ((mr0>>4)&3)+1;
+ ppdv = (mr0&3)+1;
+ iprint("ccdv=%d cbdv=%d opdv=%d epdv=%d mpdv=%d ppdv=%d\n",
+ ccdv, cbdv, opdv, epdv, mpdv, ppdv);
+ mr1 = getdcr(Cpc0Pllmr1);
+ fbmul = (mr1>>20) & 0xF;
+ if(fbmul == 0)
+ fbmul = 16;
+ fwdva = (mr1>>16) & 7;
+ if(fwdva == 0)
+ fwdva = 8;
+ fwdvb = (mr1>>12) & 7;
+ if(fwdvb == 0)
+ fwdvb = 8;
+ tun = mr0 & 0x3FF;
+ iprint("fbmul=%d fwdva=%d fwdvb=%d tun=%d m=%d\n",
+ fbmul, fwdva, fwdvb, tun, fbmul*fwdva);
+ }
+}
+
+void
+archreboot(void)
+{
+ putevpr(~0);
+ firmware(0);
+ for(;;);
+}
+
+void
+clockcheck(void)
+{
+}
+
+void
+cpuidprint(void)
+{
+ iprint("PowerPC 405EP pvr=%8.8lux\n", getpvr());
+ /* TO DO */
+}
+
+#include "../port/flashif.h"
+
+/*
+ * for 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)
+{
+ switch(bank){
+ case 0:
+ f->type = "AMD29F0x0"; /* not right, but will do for now */
+ f->addr = (void*)PHYSFLASH;
+ f->size = FLASHSIZE;
+ f->width = 2;
+ return 0;
+ case 1:
+ f->type = "nand";
+ f->addr = (void*)PHYSNAND;
+ f->size = 0; /* done by probe */
+ f->width = 1;
+ return 0;
+ default:
+ return -1;
+ }
+}
+
+void
+archflashwp(Flash*, int)
+{
+}
+
+#include "../port/netif.h"
+#include "etherif.h"
+
+enum {
+ /* EMAC-PHY control, tucked away in CPC0 */
+ Cpc0Epctl= 0xF3, /* EMAC-PHY ctl */
+
+ E0Nf= 1<<31, /* Emac0 noise filter enable */
+ E1Nf= 1<<30, /* Emac1 noise filter enable */
+ E1pr= 1<<7, /* Emac1 packet reject is active high */
+ E0pr= 1<<6, /* Emac 0 packet reject is active high */
+ E1rm= 1<<5, /* enable Emac 1 packet removal */
+ E0rm= 1<<4, /* enable Emac 0 packet removal */
+ E1pci= 1<<1, /* Emac 1 clock source is Tx clock output (loopback) */
+ E0pci= 1<<0, /* Emac 0 clock source is Tx clock output (loopback) */
+};
+
+int
+archether(int ctlno, Ether *ether)
+{
+ char name[KNAMELEN], *p;
+ int s;
+
+ if(ctlno > 1)
+ return -1;
+ ether->type = "EMAC";
+ ether->port = ctlno;
+ if(ctlno != 0)
+ snprint(name, sizeof(name), "eth%daddr", ctlno);
+ else
+ strcpy(name, "ethaddr");
+ p = getconf(name);
+ if(p == 0){
+ iprint("ether%d: no %s in EEPROM env\n", ctlno, name);
+ return -1;
+ }
+ parsemac(ether->ea, p, Eaddrlen);
+ s = splhi();
+ putdcr(Cpc0Epctl, getdcr(Cpc0Epctl) | (ctlno?E1Nf:E0Nf));
+ splx(s);
+ return 1;
+}
+
+enum {
+ /* UART control */
+ Cpc0Ucr= 0xF5, /* UART control register */
+
+ U0Dc= 1<<21, /* UART0 DMA clear enable */
+ U0Dt= 1<<20, /* enable UART0 DMA transmit channel */
+ U0Dr= 1<<19, /* enable UART0 DMA receive channel */
+ U1Dc= 1<<18, /* UART1 DMA clear enable */
+ U1Dt= 1<<17, /* enable UART1 DMA transmit channel */
+ U1Dr= 1<<16, /* enable UART1 DMA receive channel */
+ U1Div_s= 8, /* UART1 serial clock divisor (shift) */
+ U1Stop= 1<<8,
+ U0Div_s= 0, /* UART0 serial clock divisor (shift) */
+ U0Stop= 1<<0,
+ UDiv_m= 0x7F, /* UARTx divisor mask */
+};
+
+static ulong
+findserialclock(int rate, ulong *freq)
+{
+ ulong d, b;
+ ulong serialclock;
+ int actual, e, beste, bestd;
+
+ *freq = 0;
+ if(rate == 0)
+ return 0;
+ d = ((m->pllhz+m->opbhz-1)/m->opbhz)*2; /* double to allow for later rounding */
+ beste = 0;
+ bestd = -1;
+ for(; d<=128; d++){
+ serialclock = (2*m->pllhz)/d;
+ b = ((serialclock+8*rate-1)/(rate*16))>>1;
+ actual = ((serialclock+8*b-1)/(b*16))>>1;
+ e = rate-actual;
+ if(e < 0)
+ e = -e;
+ if(bestd < 0 || e < beste || e == beste && (bestd&1) && (d&1)==0){
+ beste = e;
+ bestd = d;
+ }
+ }
+ if(bestd > 0)
+ *freq = m->pllhz/bestd;
+ return bestd;
+}
+
+/*
+ * return a value for UARTn's baud rate generator, and
+ * set a corresponding divsor in the UARTn clock generator
+ * (between 2 and 128)
+ */
+ulong
+archuartclock(int n, int rate)
+{
+ int d, s;
+ ulong m, freq;
+
+ d = findserialclock(rate, &freq);
+ if(d <= 0)
+ d = U0Stop;
+ m = UDiv_m;
+ if(n){
+ d <<= U1Div_s;
+ m <<= U1Div_s;
+ }
+ s = splhi();
+ putdcr(Cpc0Ucr, (getdcr(Cpc0Ucr) & ~m) | d);
+ splx(s);
+ return freq;
+}
+
+void
+archuartdma(int n, int on)
+{
+ ulong r;
+ int s;
+
+ r = n? (U1Dc|U1Dt|U1Dr): (U0Dc|U0Dt|U0Dr);
+ if(on){
+ s = splhi();
+ putdcr(Cpc0Ucr, getdcr(Cpc0Ucr) | r);
+ splx(s);
+ }else{
+ s = splhi();
+ putdcr(Cpc0Ucr, getdcr(Cpc0Ucr) & ~r);
+ splx(s);
+ }
+}
+
+/*
+ * boot environment in eeprom
+ */
+
+enum {
+ EEpromHdr= 8, /* bytes */
+ Envsize= 0x400,
+};
+
+static I2Cdev eedev;
+static struct {
+ uchar buf[Envsize];
+ int size;
+} bootenv;
+
+static int
+eepromitem(uchar *buf, int lim, ulong *off)
+{
+ int l;
+ uchar b;
+
+ if(i2crecv(&eedev, &b, 1, (*off)++) != 1)
+ return -1;
+ l = b;
+ if(l & 0x80){
+ if(i2crecv(&eedev, &b, 1, (*off)++) != 1)
+ return -1;
+ l = ((l & 0x7F)<<8) | b;
+ }
+ if(buf == nil)
+ return l;
+ if(l > lim)
+ l = lim;
+ return i2crecv(&eedev, buf, l, *off);
+}
+
+void
+eepromscan(void)
+{
+ int n, l;
+ ulong off;
+ uchar buf[2];
+ char *p, *ep, *v;
+
+ eedev.addr = 0x50;
+ eedev.salen = 2;
+ i2csetup(1);
+ n = i2crecv(&eedev, buf, sizeof(buf), 0);
+ if(n <= 0){
+ iprint("eepromscan: %d\n", n);
+ return;
+ }
+ if(buf[0] != 0xEF || buf[1] != 0xBE){
+ iprint("eeprom invalid\n");
+ return;
+ }
+ bootenv.size = 0;
+ for(off = EEpromHdr; off < 16384;){
+ l = eepromitem(bootenv.buf, sizeof(bootenv.buf), &off); /* key */
+ if(l <= 0)
+ break;
+ off += l;
+ if(l == 7 && memcmp(bootenv.buf, "PPCBOOT", 7) == 0){ /* intrinsyc key */
+ bootenv.size = eepromitem(bootenv.buf, sizeof(bootenv.buf), &off);
+ break;
+ }
+ l = eepromitem(nil, 0, &off); /* skip value */
+ if(l < 0)
+ break;
+ off += l+2; /* 2 byte crc */
+ }
+ p = (char*)bootenv.buf+4; /* skip crc */
+ ep = p+bootenv.size;
+ for(; p < ep && *p; p += l){
+ l = strlen(p)+1;
+ v = strchr(p, '=');
+ if(v != nil)
+ *v++ = 0;
+ else
+ v = "";
+ addconf(p, v);
+ if(0)
+ iprint("%q = %q\n", p, v);
+ }
+}
+
+ulong
+logfsnow(void)
+{
+ return rtctime();
+}