diff options
author | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
---|---|---|
committer | Taru Karttunen <taruti@taruti.net> | 2011-03-30 15:46:40 +0300 |
commit | e5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch) | |
tree | d8d51eac403f07814b9e936eed0c9a79195e2450 /sys/src/9/alphapc/main.c |
Import sources from 2011-03-30 iso image
Diffstat (limited to 'sys/src/9/alphapc/main.c')
-rwxr-xr-x | sys/src/9/alphapc/main.c | 703 |
1 files changed, 703 insertions, 0 deletions
diff --git a/sys/src/9/alphapc/main.c b/sys/src/9/alphapc/main.c new file mode 100755 index 000000000..c9f0dcc6e --- /dev/null +++ b/sys/src/9/alphapc/main.c @@ -0,0 +1,703 @@ +#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 "/sys/src/boot/alphapc/conf.h" +#include "axp.h" + +char argbuf[128]; /* arguments passed to initcode and /boot */ + +Hwrpb *hwrpb; +Bootconf *bootconf; +Conf conf; +FPsave initfp; + /* setfcr(FPPDBL|FPRNR|FPINVAL|FPZDIV|FPOVFL) */ +uvlong initfpcr = (1LL<62)|(1LL<61)|(1LL<60)|(2LL<<58)|(1LL<48); + +char bootargs[BOOTARGSLEN]; +char *confname[MAXCONF]; +char *confval[MAXCONF]; +int nconf; + +static void +options(void) +{ + long i, n; + char *cp, *line[MAXCONF], *p, *q; + + cp = bootargs; + strncpy(cp, bootconf->bootargs, BOOTARGSLEN); + cp[BOOTARGSLEN-1] = 0; + /* can't print in this routine, see below in main() */ + + /* + * Strip out '\r', change '\t' -> ' '. + */ + p = cp; + for(q = cp; *q; q++){ + if(*q == '\r') + continue; + if(*q == '\t') + *q = ' '; + *p++ = *q; + } + *p = 0; + + n = getfields(cp, line, MAXCONF, 1, "\n"); + for(i = 0; i < n; i++){ + if(*line[i] == '#') + continue; + cp = strchr(line[i], '='); + if(cp == nil) + continue; + *cp++ = '\0'; + confname[nconf] = line[i]; + confval[nconf] = cp; + nconf++; + } +} + +/* debugging only */ +static void +dumpopts(void) +{ + int i; + + print("dumpopts: found /alpha/conf options at %#p\n", + bootconf->bootargs); + for(i = 0; i < nconf; i++) + print("dumpopts: read %s=%s\n", confname[i], confval[i]); +} + +extern void (*i8237alloc)(void); + +void +main(void) +{ + hwrpb = (Hwrpb*)0x10000000; + hwrpb = (Hwrpb*)(KZERO|hwrpb->phys); + arginit(); + machinit(); + options(); + ioinit(); + clockinit(); + confinit(); + archinit(); + xinit(); + memholes(); + if(i8237alloc != nil) + i8237alloc(); + mmuinit(); + if(arch->coreinit) + arch->coreinit(); + trapinit(); + screeninit(); + printinit(); + /* it's now safe to print */ + /* dumpopts(); /* DEBUG */ + kbdinit(); + i8250console(); + quotefmtinstall(); + print("\nPlan 9\n"); + + cpuidprint(); + if(arch->corehello) + arch->corehello(); + + procinit0(); + initseg(); + timersinit(); + links(); + chandevreset(); + pageinit(); + swapinit(); + savefpregs(&initfp); +initfp.fpstatus = 0x68028000; + userinit(); + schedinit(); +} + +/* cpu->state bits */ +enum { + Cpubootinprog = 1, /* boot in progress */ + Cpucanrestart = 2, /* restart possible */ + Cpuavail = 4, /* processor available */ + Cpuexists = 8, /* processor present */ + Cpuuserhalted = 0x10, /* user halted */ + Cpuctxtokay = 0x20, /* context valid */ + Cpupalokay = 0x40, /* PALcode valid */ + Cpupalmemokay = 0x80, /* PALcode memory valid */ + Cpupalloaded = 0x100, /* PALcode loaded */ + Cpuhaltmask = 0xff0000, /* halt request mask */ + Cpuhaltdflt = 0, + Cpuhaltsaveexit = 0x10000, + Cpuhaltcoldboot = 0x20000, + Cpuhaltwarmboot = 0x30000, + Cpuhaltstayhalted = 0x40000, + Cpumustbezero = 0xffffffffff000000ULL, /* 24:63 -- must be zero */ +}; + +/* + * initialize a processor's mach structure. each processor does this + * for itself. + */ +void +machinit(void) +{ + int n; + Hwcpu *cpu; + + icflush(); + n = m->machno; + memset(m, 0, sizeof(Mach)); + m->machno = n; + + active.exiting = 0; + active.machs = 1; + + cpu = (Hwcpu*) ((ulong)hwrpb + hwrpb->cpuoff + n*hwrpb->cpulen); + cpu->state &= ~Cpubootinprog; + if (0) + cpu->state |= Cpuhaltstayhalted; +} + +void +init0(void) +{ + int i; + char buf[2*KNAMELEN]; + + 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()){ + snprint(buf, sizeof(buf), "alpha %s alphapc", conffile); + ksetenv("terminal", buf, 0); + ksetenv("cputype", "alpha", 0); + if(cpuserver) + ksetenv("service", "cpu", 0); + else + ksetenv("service", "terminal", 0); + for(i = 0; i < nconf; i++) + if(confname[i]){ + if(confname[i][0] != '*') + ksetenv(confname[i], confval[i], 0); + ksetenv(confname[i], confval[i], 1); + } + poperror(); + } + + kproc("alarm", alarmkproc, 0); + touser((uchar*)(USTKTOP - sizeof(argbuf))); +} + +void +userinit(void) +{ + Proc *p; + Segment *s; + KMap *k; + char **av; + Page *pg; + + 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); + + procsetup(p); + + /* + * Kernel Stack + */ + p->sched.pc = (ulong)init0; + p->sched.sp = (ulong)p->kstack+KSTACK-MAXSYSARG*BY2WD; + /* + * User Stack, pass input arguments to boot process + */ + s = newseg(SG_STACK, USTKTOP-USTKSIZE, USTKSIZE/BY2PG); + p->seg[SSEG] = s; + pg = newpage(1, 0, USTKTOP-BY2PG); + segpage(s, pg); + k = kmap(pg); + for(av = (char**)argbuf; *av; av++) + *av += (USTKTOP - sizeof(argbuf)) - (ulong)argbuf; + + memmove((uchar*)VA(k) + BY2PG - sizeof(argbuf), argbuf, sizeof argbuf); + 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]); + memmove((uchar*)VA(k), initcode, sizeof initcode); + kunmap(k); + + ready(p); +} + +void +procsetup(Proc *p) +{ + p->fpstate = FPinit; + fpenab(0); +} + +void +procsave(Proc *p) +{ + if(p->fpstate == FPactive){ + if(p->state == Moribund) + fpenab(0); + else + savefpregs(&up->fpsave); + p->fpstate = FPinactive; + } + + /* + * Switch to the prototype page tables for this processor. + * While this processor is in the scheduler, the process could run + * on another processor and exit, returning the page tables to + * the free list where they could be reallocated and overwritten. + * When this processor eventually has to get an entry from the + * trashed page tables it will crash. + */ + mmupark(); +} + +void +setupboot(int halt) +{ + int n = 0; // cpu id of primary cpu, not just m->machno + Hwcpu *cpu = (Hwcpu*)((ulong)hwrpb + hwrpb->cpuoff + n*hwrpb->cpulen); + + cpu->state &= ~(Cpucanrestart | Cpuhaltmask); + cpu->state |= (halt? Cpuhaltstayhalted: Cpuhaltwarmboot); +} + +/* from ../pc */ +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) + print("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; + } + + if(active.ispanic && m->machno == 0) { + if(cpuserver) + delay(10000); + else + for (;;) + continue; + } else + delay(1000); +} + +/* from ../pc: */ +void +reboot(void *entry, void *code, ulong size) +{ + // writeconf(); // pass kernel environment to next kernel + shutdown(0); + + /* + * should be the only processor running now + */ + print("shutting down...\n"); + delay(200); + + splhi(); + + /* turn off buffered serial console */ + serialoq = nil; + + /* shutdown devices */ + chandevshutdown(); + +#ifdef FUTURE +{ + ulong *pdb; + /* + * Modify the machine page table to directly map the low 4MB of memory + * This allows the reboot code to turn off the page mapping + */ + pdb = m->pdb; + pdb[PDX(0)] = pdb[PDX(KZERO)]; + mmuflushtlb(PADDR(pdb)); +} + /* setup reboot trampoline function */ +{ + void (*f)(ulong, ulong, ulong) = (void*)REBOOTADDR; + + memmove(f, rebootcode, sizeof(rebootcode)); +#else + USED(entry, code, size); +#endif + + print("rebooting...\n"); +#ifdef FUTURE + /* off we go - never to return */ + (*f)(PADDR(entry), PADDR(code), size); +} +#endif + setupboot(0); // reboot, don't halt + exit(0); +} + +void +exit(int ispanic) +{ + canlock(&active); + active.machs &= ~(1<<m->machno); + active.exiting = 1; + unlock(&active); + + spllo(); + print("cpu %d exiting\n", m->machno); + do + delay(100); + while(consactive()); + + splhi(); + delay(1000); /* give serial fifo time to finish flushing */ + if (getconf("*debug") != nil) { + USED(ispanic); + delay(60*1000); /* give us time to read the screen */ + } + if(arch->coredetach) + arch->coredetach(); + setupboot(1); // set up to halt + for (; ; ) + firmware(); + + // on PC is just: + //if (0) { + // shutdown(ispanic); + // arch->reset(); + //} +} + +void +confinit(void) +{ + ulong ktop, kpages; + Bank *b, *eb; + extern void _main(void); + int userpcnt; + char *p; + + if(p = getconf("*kernelpercent")) + userpcnt = 100 - strtol(p, 0, 0); + else + userpcnt = 0; + + /* + * The console firmware divides memory into 1 or more banks. + * FInd the bank with the kernel in it. + */ + b = bootconf->bank; + eb = b+bootconf->nbank; + ktop = PGROUND((ulong)end); + ktop = PADDR(ktop); + while(b < eb) { + if(b->min < ktop && ktop < b->max) + break; + b++; + } + if(b == eb) + panic("confinit"); + + /* + * Split the bank of memory into 2 banks to fool the allocator into + * allocating low memory pages from bank 0 for any peripherals + * which only have a 24bit address counter. + */ + conf.mem[0].npage = (8*1024*1024)/BY2PG; + conf.mem[0].base = 0; + + conf.mem[1].npage = (b->max-8*1024*1024)/BY2PG; + conf.mem[1].base = 8*1024*1024; + + conf.npage = conf.mem[0].npage+conf.mem[1].npage; + conf.upages = (conf.npage*70)/100; + + conf.mem[0].npage -= ktop/BY2PG; + conf.mem[0].base += ktop; + conf.ialloc = ((conf.npage-conf.upages)/2)*BY2PG; + + /* + * Fix up the bank we found to be the remnant, below the kernel. + * This, and the other banks, will be passed to xhole() later. + * BUG: conf.upages needs to be adjusted, but how? In practice, + * we only have 1 bank, and the remnant is small. + */ + b->max = (uvlong)_main & ~(BY2PG-1); + + conf.nmach = 1; + conf.nproc = 100 + ((conf.npage*BY2PG)/MB)*5; + if(cpuserver) + conf.nproc *= 3; + if(conf.nproc > 2000) + conf.nproc = 2000; + conf.nimage = 200; + conf.nswap = conf.nproc*80; + conf.nswppo = 4096; + conf.copymode = 0; /* copy on write */ + + if(cpuserver) { + if(userpcnt < 10) + userpcnt = 70; + kpages = conf.npage - (conf.npage*userpcnt)/100; + + /* + * Hack for the big boys. Only good while physmem < 4GB. + * Give the kernel a max. of 16MB + enough to allocate the + * page pool. + * This is an overestimate as conf.upages < conf.npages. + * The patch of nimage is a band-aid, scanning the whole + * page list in imagereclaim just takes too long. + */ + if(kpages > (16*MB + conf.npage*sizeof(Page))/BY2PG){ + kpages = (16*MB + conf.npage*sizeof(Page))/BY2PG; + conf.nimage = 2000; + kpages += (conf.nproc*KSTACK)/BY2PG; + } + } else { + if(userpcnt < 10) { + if(conf.npage*BY2PG < 16*MB) + userpcnt = 40; + else + userpcnt = 60; + } + kpages = conf.npage - (conf.npage*userpcnt)/100; + + /* + * Make sure terminals with low memory get at least + * 4MB on the first Image chunk allocation. + */ + if(conf.npage*BY2PG < 16*MB) + imagmem->minarena = 4*1024*1024; + } + conf.upages = conf.npage - kpages; + conf.ialloc = (kpages/2)*BY2PG; + + /* + * Guess how much is taken by the large permanent + * datastructures. Mntcache and Mntrpc are not accounted for + * (probably ~300KB). + */ + 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; + } + +// conf.monitor = 1; /* BUG */ +} + +void +memholes(void) +{ + Bank *b, *eb; + + b = bootconf->bank; + eb = b+bootconf->nbank; + while(b < eb) { + if(b->min < (1LL<<32) && b->max < (1LL<<32)) + xhole(b->min, b->max-b->min); + b++; + } +} + +char *sp; + +char * +pusharg(char *p) +{ + int n; + + n = strlen(p)+1; + sp -= n; + memmove(sp, p, n); + return sp; +} + +void +arginit(void) +{ + char **av; + + av = (char**)argbuf; + sp = argbuf + sizeof(argbuf); + *av++ = pusharg("boot"); + *av = 0; +} + +char * +getconf(char *name) +{ + int n; + + for(n = 0; n < nconf; n++) + if(cistrcmp(confname[n], name) == 0) { + return confval[n]; + } + return 0; +} + +int +isaconfig(char *class, int ctlrno, ISAConf *isa) +{ + char cc[32], *p; + int i, n; + + snprint(cc, sizeof cc, "%s%d", class, ctlrno); + for(n = 0; n < nconf; n++){ + if(cistrcmp(confname[n], cc) != 0) + continue; + isa->nopt = tokenize(confval[n], 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, "dma=", 4) == 0) + isa->dma = 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); + } + return 1; + } + return 0; +} + +int +cistrcmp(char *a, char *b) +{ + int ac, bc; + + for(;;){ + ac = *a++; + bc = *b++; + + if(ac >= 'A' && ac <= 'Z') + ac = 'a' + (ac - 'A'); + if(bc >= 'A' && bc <= 'Z') + bc = 'a' + (bc - 'A'); + ac -= bc; + if(ac) + return ac; + if(bc == 0) + break; + } + return 0; +} + +int +cistrncmp(char *a, char *b, int n) +{ + unsigned ac, bc; + + while(n > 0){ + ac = *a++; + bc = *b++; + n--; + + if(ac >= 'A' && ac <= 'Z') + ac = 'a' + (ac - 'A'); + if(bc >= 'A' && bc <= 'Z') + bc = 'a' + (bc - 'A'); + + ac -= bc; + if(ac) + return ac; + if(bc == 0) + break; + } + + return 0; +} + +int +getcfields(char* lp, char** fields, int n, char* sep) +{ + int i; + + for(i = 0; lp && *lp && i < n; i++){ + while(*lp && strchr(sep, *lp) != 0) + *lp++ = 0; + if(*lp == 0) + break; + fields[i] = lp; + while(*lp && strchr(sep, *lp) == 0){ + if(*lp == '\\' && *(lp+1) == '\n') + *lp++ = ' '; + lp++; + } + } + + return i; +} |