123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622 |
- #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 <tos.h>
- #include <bootexec.h>
- #include "reboot.h"
- typedef struct mipsexec Mipsexec;
- /*
- * Option arguments from the command line.
- * oargv[0] is the boot file.
- */
- static int oargc;
- static char* oargv[20];
- static char oargb[128];
- static int oargblen;
- static uintptr sp; /* XXX - must go - user stack of init proc */
- /*
- * software tlb simulation
- */
- static Softtlb stlb[MAXMACH][STLBSIZE];
- Conf conf;
- FPsave initfp;
- int normalprint;
- char *
- getconf(char *)
- {
- return nil; /* stub */
- }
- static void
- optionsinit(char* s)
- {
- strecpy(oargb, oargb+sizeof(oargb), s);
- oargblen = strlen(oargb);
- oargc = tokenize(oargb, oargv, nelem(oargv)-1);
- oargv[oargc] = nil;
- }
- static void
- prcpuid(void)
- {
- ulong cpuid, cfg1;
- char *cpu;
- cpuid = prid();
- if (((cpuid>>16) & MASK(8)) == 0) /* vendor */
- cpu = "old mips";
- else if (((cpuid>>16) & MASK(8)) == 1)
- switch ((cpuid>>8) & MASK(8)) { /* processor */
- case 0x93:
- cpu = "mips 24k";
- break;
- case 0x96:
- cpu = "mips 24ke";
- break;
- default:
- cpu = "mips";
- break;
- }
- else
- cpu = "other mips";
- delay(20);
- print("cpu%d: %ldMHz %s %se v%ld.%ld rev %ld, ",
- m->machno, m->hz / Mhz, cpu, getconfig() & (1<<15)? "b": "l",
- (cpuid>>5) & MASK(3), (cpuid>>2) & MASK(3), cpuid & MASK(2));
- delay(200);
- cfg1 = getconfig1();
- 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);
- delay(50);
- print("cpu%d: l1 i cache: %d sets 4 ways 32 bytes/line\n", m->machno,
- 64 << ((cfg1>>22) & MASK(3)));
- delay(50);
- print("cpu%d: l1 d cache: %d sets 4 ways 32 bytes/line\n", m->machno,
- 64 << ((cfg1>>13) & MASK(3)));
- delay(500);
- if (0)
- print("cpu%d: cycle counter res = %ld\n",
- m->machno, gethwreg3());
- }
- 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);
- }
- 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;
- }
- /* called from rebootcmd() */
- int
- parsemipsboothdr(Chan *c, ulong magic, Execvals *evp)
- {
- long extra;
- Mipsexec me;
- /*
- * BOOT_MAGIC is sometimes defined like this:
- * #define BOOT_MAGIC (0x160<<16) || magic == ((0x160<<16)|3)
- * so we can only use it in a fairly stylized manner.
- */
- if(magic == BOOT_MAGIC) {
- c->offset = 0; /* back up */
- readn(c, &me, sizeof me);
- /* if binary is -H1, read an extra long */
- if (l2be(me.amagic) == 0407 && me.nscns == 0)
- readn(c, &extra, sizeof extra);
- evp->entry = l2be(me.mentry);
- evp->textsize = l2be(me.tsize);
- evp->datasize = l2be(me.dsize);
- return 0;
- } else
- return -1;
- }
- void
- main(void)
- {
- stopwdog(); /* tranquilise the dog */
- optionsinit("/boot/boot boot");
- confinit();
- savefpregs(&initfp);
- machinit(); /* calls clockinit */
- active.exiting = 0;
- active.machs = 1;
- kmapinit();
- xinit();
- timersinit();
- fmtinit();
- vecinit();
- normalprint = 1;
- print("\nPlan 9\n");
- prcpuid();
- if (PTECACHABILITY == PTENONCOHERWT)
- print("caches configured as write-through\n");
- if (0)
- xsummary();
- ckpagemask(PGSZ, BY2PG);
- tlbinit();
- machwire();
- pageinit();
- procinit0();
- initseg();
- links();
- chandevreset();
- swapinit();
- userinit();
- sicwdog();
- parseboothdr = parsemipsboothdr;
- schedinit();
- panic("schedinit returned");
- }
- /*
- * initialize a processor's mach structure. each processor does this
- * for itself.
- */
- void
- machinit(void)
- {
- /* Ensure CU1 is off */
- clrfpintr();
- m->stb = &stlb[m->machno][0];
- clockinit();
- }
- /*
- * setup MIPS trap vectors
- */
- void
- vecinit(void)
- {
- memmove((ulong*)UTLBMISS, (ulong*)vector0, 0x80);
- memmove((ulong*)XEXCEPTION, (ulong*)vector0, 0x80);
- memmove((ulong*)CACHETRAP, (ulong*)vector100, 0x80);
- memmove((ulong*)EXCEPTION, (ulong*)vector180, 0x80);
- memmove((ulong*)(KSEG0+0x200), (ulong*)vector180, 0x80);
- icflush((ulong*)UTLBMISS, 4*1024);
- setstatus(getstatus() & ~BEV);
- }
- void
- init0(void)
- {
- char buf[128];
- up->nerrlab = 0;
- spllo();
- /*
- * 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();
- if(!waserror()){
- ksetenv("cputype", "mips", 0);
- snprint(buf, sizeof buf, "mips %s rb450g", conffile);
- ksetenv("terminal", buf, 0);
- if(cpuserver)
- ksetenv("service", "cpu", 0);
- else
- ksetenv("service", "terminal", 0);
- /*
- * we don't have a good way to read our cfg file in
- * RouterBOOT, so set the configuration here.
- */
- ksetenv("nobootprompt", "tcp", 0);
- ksetenv("nvram", "/boot/nvram", 0);
- poperror();
- }
- kproc("alarm", alarmkproc, 0);
- i8250console();
- touser(sp);
- }
- FPsave initfp;
- static void
- bootargs(uintptr base)
- {
- int i;
- ulong ssize;
- char **av, *p;
- /*
- * Push the boot args onto the stack.
- * The initial value of the user stack must be such
- * that the total used is larger than the maximum size
- * of the argument list checked in syscall.
- */
- i = oargblen+1;
- p = UINT2PTR(STACKALIGN(base + BY2PG - sizeof(Tos) - i));
- memmove(p, oargb, i);
- /*
- * Now push the argv pointers.
- * The code jumped to by touser in lproc.s expects arguments
- * main(char* argv0, ...)
- * and calls
- * startboot("/boot/boot", &argv0)
- * not the usual (int argc, char* argv[])
- */
- av = (char**)(p - (oargc+1)*sizeof(char*));
- ssize = base + BY2PG - PTR2UINT(av);
- for(i = 0; i < oargc; i++)
- *av++ = (oargv[i] - oargb) + (p - base) + (USTKTOP - BY2PG);
- *av = nil;
- sp = USTKTOP - ssize;
- }
- 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);
- p->fpstate = FPinit;
- p->fpsave.fpstatus = initfp.fpstatus;
- /*
- * Kernel Stack
- */
- p->sched.pc = (ulong)init0;
- p->sched.sp = (ulong)p->kstack+KSTACK-(sizeof(Sargs)+BY2WD);
- 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);
- memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl));
- 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
- procrestore(Proc *p)
- {
- uvlong t;
- if(p->kp)
- return;
- cycles(&t);
- p->pcycles -= t;
- }
- /*
- * Save the mach dependent part of the process state.
- */
- void
- procsave(Proc *p)
- {
- uvlong t;
- cycles(&t);
- p->pcycles += t;
- /* no fpu, so no fp state to save */
- }
- static void
- writeconf(void)
- {
- char *p, *q;
- int n;
- p = getconfenv();
- if(waserror()) {
- free(p);
- nexterror();
- }
- /* convert to name=value\n format */
- for(q=p; *q; q++) {
- q += strlen(q);
- *q = '=';
- q += strlen(q);
- *q = '\n';
- }
- n = q - p + 1;
- #ifdef BOOTARGS_EXIST
- if(n >= BOOTARGSLEN)
- error("kernel configuration too large");
- memmove(BOOTARGS, p, n);
- memset(BOOTARGS + n, '\n', BOOTARGSLEN - n);
- #endif
- USED(n);
- poperror();
- free(p);
- }
- static void
- shutdown(int ispanic)
- {
- int ms, once;
- ilock(&active);
- if(ispanic)
- active.ispanic = ispanic;
- else if(m->machno == 0 && (active.machs & (1<<m->machno)) == 0)
- active.ispanic = 0;
- once = active.machs & (1<<m->machno);
- /*
- * setting exiting will make hzclock() on each processor call exit(0),
- * which calls shutdown(0) and idles non-bootstrap cpus and returns
- * on bootstrap processors (to permit a reboot). clearing our bit
- * in machs avoids calling exit(0) from hzclock() on this processor.
- */
- active.machs &= ~(1<<m->machno);
- active.exiting = 1;
- iunlock(&active);
- if(once) {
- delay(m->machno*1000); /* stagger them */
- iprint("cpu%d: exiting\n", m->machno);
- }
- spllo();
- ms = MAXMACH * 1000;
- for(; ms > 0; ms -= TK2MS(2)){
- delay(TK2MS(2));
- if(active.machs == 0 && consactive() == 0)
- break;
- }
- delay(100);
- }
- /*
- * the new kernel is already loaded at address `code'
- * of size `size' and entry point `entry'.
- */
- void
- reboot(void *entry, void *code, ulong size)
- {
- void (*f)(ulong, ulong, ulong);
- writeconf();
- /*
- * the boot processor is cpu0. execute this function on it
- * so that the new kernel has the same cpu0.
- */
- if (m->machno != 0) {
- procwired(up, 0);
- sched();
- }
- if (m->machno != 0)
- print("on cpu%d (not 0)!\n", m->machno);
- shutdown(0);
- /*
- * should be the only processor running now
- */
- // iprint("reboot: entry %#p code %#p size %ld\n", entry, code, size);
- // iprint("code[0] = %#lux\n", *(ulong *)code);
- /* turn off buffered serial console */
- serialoq = nil;
- kprintoq = nil;
- screenputs = nil;
- /* shutdown devices */
- chandevshutdown();
- /* call off the dog */
- clockshutdown();
- splhi();
- intrshutdown();
- /* is the watchdog tied into the usb machinery? */
- // *Reset |= Rstusbohcidll | Rstusbhost | Rstusbphy;
- // Rstge0mac | Rstge0phy |
- // Rstge1mac | Rstge1phy;
- /* setup reboot trampoline function */
- f = (void*)REBOOTADDR;
- memmove(f, rebootcode, sizeof(rebootcode));
- icflush(f, sizeof(rebootcode));
- setstatus(BEV); /* also, kernel mode, no interrupts */
- coherence();
- /* off we go - never to return */
- (*f)((ulong)entry, (ulong)code, size);
- panic("loaded kernel returned!");
- }
- void
- exit(int type)
- {
- int timer;
- void (*fnp)(void);
- stopwdog();
- delay(1000);
- lock(&active);
- active.machs &= ~(1<<m->machno);
- active.exiting = 1;
- unlock(&active);
- spllo();
- print("cpu %d exiting\n", m->machno);
- timer = 0;
- while(active.machs || consactive()) {
- if(timer++ > 400)
- break;
- delay(10);
- }
- delay(1000);
- splhi();
- USED(type);
- setstatus(BEV);
- coherence();
- iprint("exit: awaiting reset\n");
- wdogreset(); /* wake the dog with v. short timeout */
- // *Reset |= Rstfullchip;
- // *Reset |= Rstcpucold;
- delay(1000); /* await a reset */
- iprint("exit: jumping to rom\n");
- fnp = (void (*)(void))ROM;
- (*fnp)();
- iprint("exit: looping\n");
- for (;;)
- ;
- }
- void
- idlehands(void)
- {
- stopwdog();
- idle();
- sicwdog(); /* wake the dog */
- }
- void
- confinit(void)
- {
- ulong kpages, ktop;
- /*
- * divide memory twixt user pages and kernel.
- */
- conf.mem[0].base = ktop = PADDR(PGROUND((ulong)end));
- /* fixed memory on routerboard */
- conf.mem[0].npage = MEMSIZE/BY2PG - ktop/BY2PG;
- conf.npage = conf.mem[0].npage;
- conf.nuart = 1;
- 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;
- /*
- * 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->speed = 680; /* initial guess at MHz, for rb450g */
- m->hz = m->speed * Mhz;
- conf.nmach = 1;
- /* set up other configuration parameters */
- conf.nproc = 2000;
- conf.nswap = 262144;
- conf.nswppo = 4096;
- conf.nimage = 200;
- conf.copymode = 0; /* copy on write */
- }
|