| plan 9 kernel history: overview | file list | diff list |
2002/0116/alphapc/main.c (diff list | history)
| alphapc/main.c on 1999/0415 | ||
| 1999/0415 | #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; | |
| 2000/0929 | /* setfcr(FPPDBL|FPRNR|FPINVAL|FPZDIV|FPOVFL) */ uvlong initfpcr = (1LL<62)|(1LL<61)|(1LL<60)|(2LL<<58)|(1LL<48); | |
| 1999/0415 | ||
| 2000/0401 | char bootargs[BOOTARGSLEN]; char *confname[MAXCONF]; char *confval[MAXCONF]; int nconf; static void options(void) { | |
| 2001/0727 | long i, n; char *cp, *line[MAXCONF], *p, *q; | |
| 2000/0401 | ||
| 2001/0728 | cp = bootargs; strncpy(cp, bootconf->bootargs, BOOTARGSLEN); | |
| 2000/0401 | cp[BOOTARGSLEN-1] = 0; | |
| 2001/0727 | /* * 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"); | |
| 2000/0401 | for(i = 0; i < n; i++){ if(*line[i] == '#') continue; cp = strchr(line[i], '='); | |
| 2001/0727 | if(cp == nil) | |
| 2000/0401 | continue; | |
| 2001/0727 | *cp++ = '\0'; | |
| 2000/0401 | confname[nconf] = line[i]; confval[nconf] = cp; nconf++; } } | |
| 1999/0415 | void main(void) { hwrpb = (Hwrpb*)0x10000000; hwrpb = (Hwrpb*)(KZERO|hwrpb->phys); arginit(); machinit(); | |
| 2000/0401 | options(); | |
| 2001/0727 | ioinit(); | |
| 1999/0415 | clockinit(); confinit(); archinit(); xinit(); | |
| 2000/0401 | memholes(); mmuinit(); if(arch->coreinit) | |
| 1999/0415 | arch->coreinit(); trapinit(); | |
| 2000/0108 | screeninit(); printinit(); | |
| 1999/0415 | kbdinit(); | |
| 2001/0727 | i8250console(); print("\nPlan 9\n"); | |
| 1999/0415 | cpuidprint(); | |
| 2000/0401 | if(arch->corehello) | |
| 1999/0415 | arch->corehello(); procinit0(); initseg(); links(); chandevreset(); | |
| 1999/0423 | pageinit(); | |
| 1999/0415 | swapinit(); | |
| 1999/0515 | savefpregs(&initfp); initfp.fpstatus = 0x68028000; | |
| 1999/0415 | userinit(); schedinit(); } /* * initialize a processor's mach structure. each processor does this * for itself. */ void machinit(void) { int n; | |
| 2001/0728 | Hwcpu *cpu; | |
| 1999/0415 | icflush(); n = m->machno; memset(m, 0, sizeof(Mach)); m->machno = n; active.exiting = 0; active.machs = 1; | |
| 2001/0728 | cpu = (Hwcpu*) ((ulong)hwrpb + hwrpb->cpuoff + n*hwrpb->cpulen); cpu->state &= ~1; /* boot in progress - not */ /* cpu->state |= (4<<16); /* stay halted */ | |
| 1999/0415 | } void init0(void) { | |
| 2000/0401 | int i; | |
| 2001/0727 | char tstr[32]; | |
| 1999/0415 | ||
| 2001/0727 | up->nerrlab = 0; | |
| 1999/0415 | 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); | |
| 2000/0422 | cnameclose(up->slash->name); up->slash->name = newcname("/"); | |
| 2001/0727 | up->dot = cclone(up->slash); | |
| 1999/0415 | chandevinit(); if(!waserror()){ | |
| 2002/0109 | ksetenv("cputype", "alpha", 0); | |
| 2001/0727 | sprint(tstr, "alpha %s alphapc", conffile); | |
| 2002/0109 | ksetenv("terminal", tstr, 0); | |
| 2000/0401 | if(cpuserver) | |
| 2002/0109 | ksetenv("service", "cpu", 0); | |
| 2000/0401 | else | |
| 2002/0109 | ksetenv("service", "terminal", 0); | |
| 2000/0401 | for(i = 0; i < nconf; i++) | |
| 2002/0109 | if(confname[i]) ksetenv(confname[i], confval[i], 1); | |
| 1999/0415 | 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; | |
| 2001/0727 | kstrdup(&eve, ""); kstrdup(&p->text, "*init*"); kstrdup(&p->user, eve); | |
| 1999/0415 | ||
| 1999/0515 | procsetup(p); | |
| 1999/0415 | /* * Kernel Stack */ p->sched.pc = (ulong)init0; | |
| 2001/0731 | p->sched.sp = (ulong)p->kstack+KSTACK-MAXSYSARG*BY2WD; | |
| 1999/0415 | /* * 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); | |
| 1999/0515 | } void procsetup(Proc *p) { p->fpstate = FPinit; fpenab(0); } void procsave(Proc *p) { if(p->fpstate == FPactive){ if(p->state == Moribund) fpenab(0); | |
| 2002/0116 | else | |
| 1999/0515 | 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. */ | |
| 2002/0116 | mmupark(); | |
| 1999/0415 | } | |
| 2002/0109 | ||
| 2002/0112 | /* still to do */ | |
| 2002/0109 | void reboot(void*, void*, ulong) { exit(0); } | |
| 1999/0415 | void exit(int) { 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 */ | |
| 2000/0401 | if(arch->coredetach) | |
| 1999/0415 | arch->coredetach(); firmware(); } void confinit(void) { | |
| 2000/0401 | ulong ktop, kpages; Bank *b, *eb; extern void _main(void); int userpcnt; char *p; | |
| 1999/0415 | ||
| 2000/0401 | if(p = getconf("*kernelpercent")) userpcnt = 100 - strtol(p, 0, 0); else userpcnt = 0; | |
| 1999/0415 | /* | |
| 2000/0401 | * The console firmware divides memory into 1 or more banks. * FInd the bank with the kernel in it. | |
| 1999/0415 | */ | |
| 2000/0401 | 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. */ | |
| 1999/0415 | conf.npage0 = (8*1024*1024)/BY2PG; conf.base0 = 0; | |
| 2000/0401 | conf.npage1 = (b->max-8*1024*1024)/BY2PG; | |
| 1999/0415 | conf.base1 = 8*1024*1024; conf.npage = conf.npage0+conf.npage1; conf.upages = (conf.npage*70)/100; conf.npage0 -= ktop/BY2PG; conf.base0 += ktop; conf.ialloc = ((conf.npage-conf.upages)/2)*BY2PG; | |
| 2000/0401 | /* * 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); | |
| 1999/0415 | conf.nmach = 1; | |
| 2000/0401 | conf.nproc = 100 + ((conf.npage*BY2PG)/MB)*5; if(cpuserver) conf.nproc *= 3; if(conf.nproc > 2000) conf.nproc = 2000; conf.nimage = 200; | |
| 1999/0415 | conf.nswap = conf.nproc*80; | |
| 2000/0401 | conf.nswppo = 4096; | |
| 1999/0415 | conf.copymode = 0; /* copy on write */ | |
| 2000/0401 | 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; } | |
| 2001/0727 | // conf.monitor = 1; /* BUG */ | |
| 1999/0415 | } void | |
| 2000/0401 | memholes(void) | |
| 1999/0415 | { | |
| 2000/0401 | 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++; } | |
| 1999/0415 | } | |
| 2000/0401 | ||
| 1999/0415 | 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) { | |
| 2001/0727 | char cc[32], *p; int i, n; | |
| 1999/0415 | ||
| 2001/0727 | snprint(cc, sizeof cc, "%s%d", class, ctlrno); | |
| 1999/0415 | for(n = 0; n < nconf; n++){ | |
| 2001/0727 | if(cistrcmp(confname[n], cc) != 0) | |
| 1999/0415 | continue; | |
| 2001/0727 | 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; | |
| 1999/0415 | 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; | |
| 2000/0401 | } 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; | |
| 1999/0415 | } | |