#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<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(); }