123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597 |
- #include "u.h"
- #include "tos.h"
- #include "../port/lib.h"
- #include "mem.h"
- #include "dat.h"
- #include "fns.h"
- #include "init.h"
- #include <pool.h>
- #include "reboot.h"
- /* Firmware compatibility */
- #define Minfirmrev 326770
- #define Minfirmdate "22 Jul 2012"
- /*
- * Where configuration info is left for the loaded programme.
- */
- #define BOOTARGS ((char*)CONFADDR)
- #define BOOTARGSLEN (MACHADDR-CONFADDR)
- #define MAXCONF 64
- #define MAXCONFLINE 160
- uintptr kseg0 = KZERO;
- Mach* machaddr[MAXMACH];
- Conf conf;
- ulong memsize = 128*1024*1024;
- /*
- * 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 */
- /* store plan9.ini contents here at least until we stash them in #ec */
- static char confname[MAXCONF][KNAMELEN];
- static char confval[MAXCONF][MAXCONFLINE];
- static int nconf;
- typedef struct Atag Atag;
- struct Atag {
- u32int size; /* size of atag in words, including this header */
- u32int tag; /* atag type */
- union {
- u32int data[1]; /* actually [size-2] */
- /* AtagMem */
- struct {
- u32int size;
- u32int base;
- } mem;
- /* AtagCmdLine */
- char cmdline[1]; /* actually [4*(size-2)] */
- };
- };
- enum {
- AtagNone = 0x00000000,
- AtagCore = 0x54410001,
- AtagMem = 0x54410002,
- AtagCmdline = 0x54410009,
- };
- static int
- findconf(char *name)
- {
- int i;
- for(i = 0; i < nconf; i++)
- if(cistrcmp(confname[i], name) == 0)
- return i;
- return -1;
- }
- char*
- getconf(char *name)
- {
- int i;
- i = findconf(name);
- if(i >= 0)
- return confval[i];
- return nil;
- }
- void
- addconf(char *name, char *val)
- {
- int i;
- i = findconf(name);
- if(i < 0){
- if(val == nil || nconf >= MAXCONF)
- return;
- i = nconf++;
- strecpy(confname[i], confname[i]+sizeof(confname[i]), name);
- }
- strecpy(confval[i], confval[i]+sizeof(confval[i]), val);
- }
- 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;
- if(n >= BOOTARGSLEN)
- error("kernel configuration too large");
- memmove(BOOTARGS, p, n);
- memset(BOOTARGS + n, '\n', BOOTARGSLEN - n);
- poperror();
- free(p);
- }
- static void
- plan9iniinit(char *s, int cmdline)
- {
- char *toks[MAXCONF];
- int i, c, n;
- char *v;
- if((c = *s) < ' ' || c >= 0x80)
- return;
- if(cmdline)
- n = tokenize(s, toks, MAXCONF);
- else
- n = getfields(s, toks, MAXCONF, 1, "\n");
- for(i = 0; i < n; i++){
- if(toks[i][0] == '#')
- continue;
- v = strchr(toks[i], '=');
- if(v == nil)
- continue;
- *v++ = '\0';
- addconf(toks[i], v);
- }
- }
- static void
- ataginit(Atag *a)
- {
- int n;
- if(a->tag != AtagCore){
- plan9iniinit((char*)a, 0);
- return;
- }
- while(a->tag != AtagNone){
- switch(a->tag){
- case AtagMem:
- /* use only first bank */
- if(conf.mem[0].limit == 0 && a->mem.size != 0){
- memsize = a->mem.size;
- conf.mem[0].base = a->mem.base;
- conf.mem[0].limit = a->mem.base + memsize;
- }
- break;
- case AtagCmdline:
- n = (a->size * sizeof(u32int)) - offsetof(Atag, cmdline[0]);
- if(a->cmdline + n < BOOTARGS + BOOTARGSLEN)
- a->cmdline[n] = 0;
- else
- BOOTARGS[BOOTARGSLEN-1] = 0;
- plan9iniinit(a->cmdline, 1);
- break;
- }
- a = (Atag*)((u32int*)a + a->size);
- }
- }
- void
- machinit(void)
- {
- m->machno = 0;
- machaddr[m->machno] = m;
- m->ticks = 1;
- m->perf.period = 1;
- conf.nmach = 1;
- active.machs = 1;
- active.exiting = 0;
- up = nil;
- }
- static void
- optionsinit(char* s)
- {
- strecpy(oargb, oargb+sizeof(oargb), s);
- oargblen = strlen(oargb);
- oargc = tokenize(oargb, oargv, nelem(oargv)-1);
- oargv[oargc] = nil;
- }
- void
- main(void)
- {
- extern char edata[], end[];
- uint rev;
- okay(1);
- m = (Mach*)MACHADDR;
- memset(edata, 0, end - edata); /* clear bss */
- machinit();
- mmuinit1();
- optionsinit("/boot/boot boot");
- quotefmtinstall();
-
- ataginit((Atag*)BOOTARGS);
- confinit(); /* figures out amount of memory */
- xinit();
- uartconsinit();
- screeninit();
- print("\nPlan 9 from Bell Labs\n");
- rev = getfirmware();
- print("firmware: rev %d\n", rev);
- if(rev < Minfirmrev){
- print("Sorry, firmware (start.elf) must be at least rev %d (%s)\n",
- Minfirmrev, Minfirmdate);
- for(;;)
- ;
- }
- trapinit();
- clockinit();
- printinit();
- timersinit();
- if(conf.monitor)
- swcursorinit();
- cpuidprint();
- archreset();
- procinit0();
- initseg();
- links();
- chandevreset(); /* most devices are discovered here */
- pageinit();
- swapinit();
- userinit();
- schedinit();
- assert(0); /* shouldn't have returned */
- }
- /*
- * starting place for first process
- */
- void
- init0(void)
- {
- int i;
- char buf[2*KNAMELEN];
- up->nerrlab = 0;
- coherence();
- 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()){
- snprint(buf, sizeof(buf), "%s %s", "ARM", conffile);
- ksetenv("terminal", buf, 0);
- ksetenv("cputype", "arm", 0);
- if(cpuserver)
- ksetenv("service", "cpu", 0);
- else
- ksetenv("service", "terminal", 0);
- snprint(buf, sizeof(buf), "-a %s", getethermac());
- ksetenv("etherargs", buf, 0);
- /* convert plan9.ini variables to #e and #ec */
- for(i = 0; i < nconf; i++) {
- ksetenv(confname[i], confval[i], 0);
- ksetenv(confname[i], confval[i], 1);
- }
- poperror();
- }
- kproc("alarm", alarmkproc, 0);
- touser(sp);
- assert(0); /* shouldn't have returned */
- }
- 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;
- }
- /*
- * create the first process
- */
- void
- userinit(void)
- {
- Proc *p;
- Segment *s;
- KMap *k;
- Page *pg;
- /* no processes yet */
- up = nil;
- 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);
- /*
- * Kernel Stack
- */
- p->sched.pc = PTR2UINT(init0);
- p->sched.sp = PTR2UINT(p->kstack+KSTACK-sizeof(up->s.args)-sizeof(uintptr));
- 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);
- s->flushme++;
- 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);
- 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]);
- memmove(UINT2PTR(VA(k)), initcode, sizeof initcode);
- kunmap(k);
- ready(p);
- }
- void
- confinit(void)
- {
- int i;
- ulong kpages;
- uintptr pa;
- char *p;
- if(0 && (p = getconf("service")) != nil){
- if(strcmp(p, "cpu") == 0)
- cpuserver = 1;
- else if(strcmp(p,"terminal") == 0)
- cpuserver = 0;
- }
- if((p = getconf("*maxmem")) != nil){
- memsize = strtoul(p, 0, 0) - PHYSDRAM;
- if (memsize < 16*MB) /* sanity */
- memsize = 16*MB;
- }
- getramsize(&conf.mem[0]);
- if(conf.mem[0].limit == 0){
- conf.mem[0].base = PHYSDRAM;
- conf.mem[0].limit = PHYSDRAM + memsize;
- }else if(p != nil)
- conf.mem[0].limit = conf.mem[0].base + memsize;
- conf.npage = 0;
- pa = PADDR(PGROUND(PTR2UINT(end)));
- /*
- * we assume that the kernel is at the beginning of one of the
- * contiguous chunks of memory and fits therein.
- */
- for(i=0; i<nelem(conf.mem); i++){
- /* take kernel out of allocatable space */
- if(pa > conf.mem[i].base && pa < conf.mem[i].limit)
- conf.mem[i].base = pa;
- conf.mem[i].npage = (conf.mem[i].limit - conf.mem[i].base)/BY2PG;
- conf.npage += conf.mem[i].npage;
- }
- conf.upages = (conf.npage*80)/100;
- conf.ialloc = ((conf.npage-conf.upages)/2)*BY2PG;
- /* only one processor */
- conf.nmach = 1;
- /* set up other configuration parameters */
- conf.nproc = 100 + ((conf.npage*BY2PG)/MB)*5;
- if(cpuserver)
- conf.nproc *= 3;
- if(conf.nproc > 2000)
- conf.nproc = 2000;
- conf.nswap = conf.npage*3;
- conf.nswppo = 4096;
- conf.nimage = 200;
- conf.copymode = 0; /* copy on write */
- /*
- * Guess how much is taken by the large permanent
- * datastructures. Mntcache and Mntrpc are not accounted for
- * (probably ~300KB).
- */
- kpages = conf.npage - conf.upages;
- kpages *= BY2PG;
- kpages -= conf.upages*sizeof(Page)
- + conf.nproc*sizeof(Proc)
- + conf.nimage*sizeof(Image)
- + conf.nswap
- + conf.nswppo*sizeof(Page);
- mainmem->maxsize = kpages;
- if(!cpuserver)
- /*
- * give terminals lots of image memory, too; the dynamic
- * allocation will balance the load properly, hopefully.
- * be careful with 32-bit overflow.
- */
- imagmem->maxsize = kpages;
- }
- static void
- shutdown(int ispanic)
- {
- int ms, once;
- lock(&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);
- active.machs &= ~(1<<m->machno);
- active.exiting = 1;
- unlock(&active);
- if(once)
- iprint("cpu%d: exiting\n", m->machno);
- spllo();
- for(ms = 5*1000; ms > 0; ms -= TK2MS(2)){
- delay(TK2MS(2));
- if(active.machs == 0 && consactive() == 0)
- break;
- }
- delay(1000);
- }
- /*
- * exit kernel either on a panic or user request
- */
- void
- exit(int code)
- {
- shutdown(code);
- splfhi();
- archreboot();
- }
- /*
- * stub for ../omap/devether.c
- */
- int
- isaconfig(char *class, int ctlrno, ISAConf *isa)
- {
- USED(ctlrno);
- USED(isa);
- return strcmp(class, "ether") == 0;
- }
- /*
- * 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);
- print("starting reboot...");
- writeconf();
- shutdown(0);
- /*
- * should be the only processor running now
- */
- print("reboot entry %#lux code %#lux size %ld\n",
- PADDR(entry), PADDR(code), size);
- delay(100);
- /* turn off buffered serial console */
- serialoq = nil;
- kprintoq = nil;
- screenputs = nil;
- /* shutdown devices */
- chandevshutdown();
- /* stop the clock (and watchdog if any) */
- clockshutdown();
- splfhi();
- intrsoff();
- /* setup reboot trampoline function */
- f = (void*)REBOOTADDR;
- memmove(f, rebootcode, sizeof(rebootcode));
- cacheuwbinv();
- /* off we go - never to return */
- (*f)(PADDR(entry), PADDR(code), size);
- iprint("loaded kernel returned!\n");
- delay(1000);
- archreboot();
- }
- int
- cmpswap(long *addr, long old, long new)
- {
- return cas32(addr, old, new);
- }
|