#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" #include "../ip/ip.h" #include #include <../port/error.h> enum { /* space for syscall args, return PC, top-of-stack struct */ Stkheadroom = sizeof(Sargs) + sizeof(uintptr) + sizeof(Tos), }; static uchar *sp; /* XXX - must go - user stack of init proc */ static FPsave initfp; #define MAXCONF 64 static char confname[MAXCONF][KNAMELEN]; static char confval[MAXCONF][ERRMAX]; static int nconf; /* * software tlb simulation */ static Softtlb stlb[MAXMACH][STLBSIZE]; Conf conf; static void bootargsinit(int argc, char *argv[]) { int i, j; char *p, *ep; nconf = 0; for(i = 0; i < argc; i++){ p = argv[i]; ep = strchr(p, '='); if(ep == nil) continue; *ep++ = '\0'; for(j = 0; j < nconf; j++){ if(strcmp(confname[j], p) == 0) break; } strecpy(confname[j], confname[j]+KNAMELEN, p); strecpy(confval[j], confval[j]+KNAMELEN, ep); if(j == nconf) nconf++; } } char* getconf(char *name) { int i; for(i = 0; i < nconf; i++){ if(strcmp(confname[i], name) == 0) return confval[i]; } return nil; } void confsummary(void) { int i; Confmem *m; for(i = 0; i < nelem(conf.mem); i++){ m = &conf.mem[i]; print("conf.mem[%d]: 0x%08p 0x%08p %8ludK\n", i, m->base, m->base + (m->npage*BY2PG), (m->npage*BY2PG)/1024); } } static void fmtinit(void) { printinit(); quotefmtinstall(); /* ipreset installs these when chandevreset runs */ fmtinstall('i', eipfmt); fmtinstall('I', eipfmt); fmtinstall('E', eipfmt); fmtinstall('V', eipfmt); fmtinstall('M', eipfmt); fmtinstall('H', encodefmt); } static int ckpagemask(ulong mask, ulong size) { int s; ulong pm; s = splhi(); setpagemask(mask); pm = getpagemask(); splx(s); if(pm != mask){ iprint("page size %ldK not supported on this cpu; " "mask %#lux read back as %#lux\n", size/1024, mask, pm); return -1; } return 0; } void led(int blue) { int i; *IO(u32int, (blue?GPIO_F_CLEAR:GPIO_F_SET)) = GPIO_F_LED_PIN; //delay(1); for(i=0; i<1000; i++) ; } ulong getconfig(int sel) { extern ulong getconfig0(void), getconfig1(void), getconfig2(void), getconfig3(void); extern ulong getconfig4(void), getconfig5(void), getconfig6(void); switch(sel){ case 0: return getconfig0(); case 1: return getconfig1(); case 2: return getconfig2(); case 3: return getconfig3(); case 4: return getconfig4(); case 5: return getconfig5(); case 6: return getconfig6(); } return 0; } void setconfig(int sel, ulong val) { USED(sel, val); //extern void setconfig2(ulong); switch(sel){ //case 2: setconfig2(val); break; } } ulong getstatus(int sel) { extern ulong getstatus0(void), getstatus1(void), getstatus2(void), getstatus3(void), getstatus4(void); switch(sel){ case 0: return getstatus0(); case 1: return getstatus1(); case 2: return getstatus2(); case 3: return getstatus3(); case 4: return getstatus4(); } return 0; } void setstatus(int sel, ulong val) { extern void setstatus4(ulong); switch(sel){ case 4: setstatus4(val); break; } } void identify(void) { extern uintptr start, end; uintptr kstart, kend, kdiff; kstart = (uintptr)&start; kend = (uintptr)&end; kdiff = PGROUND(kend) - kstart; print("kernel @ %#p - %#p %ludK\n", &start, &end, kdiff/1024); } static void prcpuid(void) { ulong cpuid, cfg0, cfg1; char *cpu; cpuid = prid(); cfg0 = getconfig(0); cfg1 = getconfig(1); if (((cpuid>>16) & MASK(8)) == 0) /* vendor */ cpu = "old mips"; else if (((cpuid>>16) & MASK(8)) == 0xe1) switch ((cpuid>>8) & MASK(8)) { /* processor */ case 0x02: cpu = "ingenic jz4780"; break; default: cpu = "mips"; break; } else cpu = "other mips"; print("cpu%d: %ldMHz %s %se v%ld.%ld rev %ld\n", m->machno, m->hz / Mhz, cpu, cfg0 & (1<<15)? "b": "l", (cpuid>>5) & MASK(3), (cpuid>>2) & MASK(3), cpuid & MASK(2)); print("cpu%d: %s perf counter ", m->machno, (cfg1 & 16? "has": "no")); print("%s watch registers ", (cfg1 & 8? "has": "no")); print("%s mips16 ", (cfg1 & 4? "has": "no")); print("%s ejtag ", (cfg1 & 2? "has": "no")); print("%s fpu\n", (cfg1 & 1? "has": "no")); print("cpu%d: %ld tlb entries, using %dK pages\n", m->machno, ((cfg1>>25) & MASK(6)) + 1, BY2PG/1024); print("cpu%d: l1 i cache: %d sets %lud ways %d bytes/line\n", m->machno, 64 << ((cfg1>>22) & MASK(3)), 1+((cfg1>>16) & MASK(3)), 2 << ((cfg1>>19) & MASK(3))); print("cpu%d: l1 d cache: %d sets %lud ways %d bytes/line\n", m->machno, 64 << ((cfg1>>13) & MASK(3)), 1+((cfg1>>7) & MASK(3)), 2 << ((cfg1>>10) & MASK(3))); } static void memcheck(void) { int i; uintptr p, pg; uchar fnord[BY2PG]; memset(fnord, 0x55, sizeof(fnord)); for(i = 0; i < nelem(conf.mem); i++){ if(conf.mem[i].npage == 0) continue; p = conf.mem[i].base|KSEG1; print("checking %#p - %#p\n", p, p + (conf.mem[i].npage * BY2PG)); for(pg = 0; pg < conf.mem[i].npage; pg++){ //memcpy((void*)(p+(pg*BY2PG)), fnord, sizeof(fnord)); ((uchar*)(p+(pg*BY2PG)))[0] = 1; //if(memcmp((void*)(p+(pg*BY2PG)), fnord, sizeof(fnord)) != 0){ if(((uchar*)(p+(pg*BY2PG)))[0] != 1){ print("%#p failed memcheck\n", p+(pg*BY2PG)); panic("failed memcheck"); } if(pg > 0 && pg % 256 == 0) print("%#p %ludK ok\n", p+(pg*BY2PG), (pg*BY2PG)/1024); if(pg > 0 && pg % 100 == 0) led(pg % 3 == 0); wdci20.restart(); } } } static void addmem(uintptr base, uintptr top) { extern char start[], end[]; uintptr s, e; int i; if(base > top) return; /* exclude address from MACHADDR to kernel end */ s = PADDR(PGROUND((uintptr)MACHADDR)); e = PADDR(PGROUND((uintptr)end)); if(s < top && e > base){ if(s > base) addmem(base, s); if(e < top) addmem(e, top); return; } for(i = 0; i < nelem(conf.mem); i++){ if(conf.mem[i].npage == 0){ conf.mem[i].base = base; conf.mem[i].npage = (top - base)/BY2PG; conf.npage += conf.mem[i].npage; return; } } print("conf.mem[] too small\n"); } static void meminit(void) { conf.npage = 0; addmem(0x1000, 0x10000000); //addmem(0x30000000, 0x60000000); } void main(int argc, char *argv[]) { wdci20.enable(); bootargsinit(argc, argv); savefpregs(&initfp); i8250console(); meminit(); //memcheck(); confinit(); confsummary(); machinit(); /* calls clockinit */ active.exiting = 0; active.machs[0] = 1; kmapinit(); print("\nPlan 9\n"); xinit(); timersinit(); fmtinit(); identify(); prcpuid(); /* unmask INTC to cpu0 */ //setstatus(4, 1<<8); /* enable interrupts from INTC */ //intron(INTR2|INTR3|INTR4|INTR5|INTR6|INTR7); /* int i; for(i = 0; i < 5; i++) print("STATUS%d %032lub\n", i, getstatus(i)); print("ICSR0 %032ub\n", *IO(u32int, INTBASE+ICSR0)); print("ICMR0 %032ub\n", *IO(u32int, INTBASE+ICMR0)); print("ICPR0 %032ub\n", *IO(u32int, INTBASE+ICPR0)); print("ICSR1 %032ub\n", *IO(u32int, INTBASE+ICSR1)); print("ICMR1 %032ub\n", *IO(u32int, INTBASE+ICMR1)); print("ICPR1 %032ub\n", *IO(u32int, INTBASE+ICPR1)); ulong *test = mallocz(4, 1); test[0] = 0x1deadbee; poolcheck(mainmem); */ uvlong f = fastticks(nil); print("fastticks(nil) = %llud\n", f); ckpagemask(PGSZ, BY2PG); print("tlbinit...\n"); tlbinit(); print("pageinit...\n"); pageinit(); print("procinit0...\n"); procinit0(); print("initseg...\n"); initseg(); print("links...\n"); links(); print("chandevreset...\n"); chandevreset(); print("userinit...\n"); userinit(); print("schedinit...\n"); schedinit(); panic("schedinit returned"); } /* * initialize a processor's mach structure. each processor does this * for itself. */ void machinit(void) { extern void vector0(void); extern void vector180(void); extern void vector200(void); m->stb = stlb[m->machno]; memmove((void*)UTLBMISS, (void*)vector0, 0x80); memmove((void*)EXCEPTION, (void*)vector180, 0x80); memmove((void*)(KSEG0+0x200), (void*)vector200, 0x80); icflush((void*)UTLBMISS, 0x80); icflush((void*)EXCEPTION, 0x80); icflush((void*)(KSEG0+0x200), 0x80); /* Ensure CU1 is off */ clrfpintr(); clockinit(); } void init0(void) { char buf[128]; up->nerrlab = 0; poolcheck(mainmem); /* * These are o.k. because rootinit is null. * Then early kproc's will have a root and dot. */ up->slash = namec("#/", Atodir, 0, 0); pathclose(up->slash->path); up->slash->path = newpath("/"); up->dot = cclone(up->slash); chandevinit(); poolcheck(mainmem); if(!waserror()){ ksetenv("cputype", "spim", 0); snprint(buf, sizeof buf, "spim %s", conffile); ksetenv("terminal", buf, 0); if(cpuserver) ksetenv("service", "cpu", 0); else ksetenv("service", "terminal", 0); ksetenv("bootargs", "tcp", 0); ksetenv("console", "0", 0); /* no usb */ ksetenv("usbwait", "0", 0); ksetenv("nousbrc", "1", 0); poperror(); } kproc("alarm", alarmkproc, 0); touser(sp); } static uchar * pusharg(char *p) { int n; n = strlen(p) + 1; sp -= n; memmove(sp, p, n); return sp; } static void bootargs(uintptr base) { int i, ac; uchar *av[32]; uchar **lsp; sp = (uchar *) base + BY2PG - sizeof(Tos); ac = 0; av[ac++] = pusharg("boot"); sp = (uchar *) ((ulong) sp & ~7); sp -= ROUND((ac + 1) * sizeof(sp), 8) + 4; lsp = (uchar **) sp; for(i = 0; i < ac; i++) lsp[i] = av[i] + ((USTKTOP - BY2PG) - (ulong) base); lsp[i] = 0; sp += (USTKTOP - BY2PG) - (ulong) base; } void userinit(void) { Proc *p; KMap *k; Page *pg; Segment *s; p = newproc(); p->pgrp = newpgrp(); p->egrp = smalloc(sizeof(Egrp)); p->egrp->ref = 1; p->fgrp = dupfgrp(nil); p->rgrp = newrgrp(); p->procmode = 0640; kstrdup(&eve, ""); kstrdup(&p->text, "*init*"); kstrdup(&p->user, eve); iprint("%s setup\n", p->text); procsetup(p); /* * Kernel Stack */ p->sched.pc = (ulong)init0; p->sched.sp = (ulong)p->kstack+KSTACK-Stkheadroom; p->sched.sp = STACKALIGN(p->sched.sp); /* * User Stack * * Technically, newpage can't be called here because it * should only be called when in a user context as it may * try to sleep if there are no pages available, but that * shouldn't be the case here. */ s = newseg(SG_STACK, USTKTOP-USTKSIZE, USTKSIZE/BY2PG); p->seg[SSEG] = s; pg = newpage(1, 0, USTKTOP-BY2PG); segpage(s, pg); k = kmap(pg); bootargs(VA(k)); kunmap(k); /* * Text */ s = newseg(SG_TEXT, UTZERO, 1); s->flushme++; p->seg[TSEG] = s; pg = newpage(1, 0, UTZERO); pg->txtflush = ~0; segpage(s, pg); k = kmap(s->map[0]->pages[0]); memset((void *)VA(k), 0, BY2PG); memmove((ulong*)VA(k), initcode, sizeof initcode); kunmap(k); ready(p); } void exit(int) { print("cpu%d: exiting\n", m->machno); lock(&active); active.machs[m->machno] = 0; active.exiting = 1; unlock(&active); splhi(); reboot(nil, nil, 0); } void reboot(void *, void *, ulong) { print("reboot\n"); for(;;){led(0);delay(50);led(1);delay(50);} } void evenaddr(uintptr va) { if((va & 3) != 0){ dumpstack(); postnote(up, 1, "sys: odd address", NDebug); error(Ebadarg); } } void procsetup(Proc *p) { p->fpstate = FPinit; memmove(p->fpsave, &initfp, sizeof(FPsave)); cycles(&p->kentry); p->pcycles = -p->kentry; } void procfork(Proc *p) { int s; p->kentry = up->kentry; p->pcycles = -p->kentry; s = splhi(); switch(up->fpstate & ~FPillegal){ case FPactive: savefpregs(up->fpsave); up->fpstate = FPinactive; /* wet floor */ case FPinactive: memmove(p->fpsave, up->fpsave, sizeof(FPsave)); p->fpstate = FPinactive; } splx(s); } void procsave(Proc *p) { uvlong t; if(p->fpstate == FPactive){ if(p->state != Moribund) { savefpregs(p->fpsave); p->fpstate = FPinactive; } } cycles(&t); p->pcycles += t; } void procrestore(Proc *p) { uvlong t; if(p->kp) return; cycles(&t); p->pcycles -= t; } void idlehands(void) { led(1); led(0); } void confinit(void) { ulong kpages; /* * set up CPU's mach structure * cpu0's was zeroed in l.s and our stack is in Mach, so don't zero it. */ m->machno = 0; m->hz = 1200 * Mhz; conf.nmach = 1; /* set up other configuration parameters */ conf.nproc = 100; conf.nswap = 0;//262144; conf.nswppo = 0;//4096; conf.nimage = 100; conf.copymode = 0; /* copy on write */ kpages = conf.npage - (conf.npage*80)/100; if(kpages > (64*MB + conf.npage*sizeof(Page))/BY2PG){ kpages = (64*MB + conf.npage*sizeof(Page))/BY2PG; kpages += (conf.nproc*KSTACK)/BY2PG; } conf.upages = conf.npage - kpages; conf.ialloc = (kpages/2)*BY2PG; kpages *= BY2PG; kpages -= conf.upages*sizeof(Page) + conf.nproc*sizeof(Proc) + conf.nimage*sizeof(Image) + conf.nswap + conf.nswppo*sizeof(Page*); mainmem->maxsize = kpages; imagmem->maxsize = kpages; mainmem->flags |= POOL_PARANOIA|POOL_ANTAGONISM|POOL_NOREUSE; conf.nuart = 1; } void setupwatchpts(Proc *, Watchpt *, int n) { if(n > 0) error("no watchpoints"); } /* for(i = 0; i < 5; i++) print("STATUS%d %032lub\n", i, getstatus(i)); print("ICSR0 %032ub\n", *IO(u32int, INTBASE+ICSR0)); print("ICMR0 %032ub\n", *IO(u32int, INTBASE+ICMR0)); print("ICPR0 %032ub\n", *IO(u32int, INTBASE+ICPR0)); print("ICSR1 %032ub\n", *IO(u32int, INTBASE+ICSR1)); print("ICMR1 %032ub\n", *IO(u32int, INTBASE+ICMR1)); print("ICPR1 %032ub\n", *IO(u32int, INTBASE+ICPR1)); for(;;){led(0);led(1);} */