/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #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" Conf conf;FPsave initfp; voidmain(void){ memset(edata, 0, (ulong)end-(ulong)edata); conf.nmach = 1; machinit(); ioinit(); i8250console(); quotefmtinstall(); print("\nPlan 9\n"); confinit(); xinit(); raveninit(); trapinit(); printinit(); cpuidprint(); mmuinit(); hwintrinit(); clockinit(); kbdinit(); procinit0(); initseg(); timersinit(); links(); chandevreset(); pageinit(); swapinit(); fpsave(&initfp); initfp.fpscr = 0; userinit(); schedinit();} voidmachinit(void){ memset(m, 0, sizeof(Mach)); m->cputype = getpvr()>>16; /* * For polled uart output at boot, need * a default delay constant. 100000 should * be enough for a while. Cpuidentify will * calculate the real value later. */ m->loopconst = 100000; /* turn on caches */ puthid0(gethid0() | BIT(16) | BIT(17)); active.machs = 1; active.exiting = 0;} voidcpuidprint(void){ char *id; id = "unknown PowerPC"; switch(m->cputype) { case 9: id = "PowerPC 604e"; break; } print("cpu0: %s\n", id);} static struct{ char *name; char *val;}plan9ini[] ={ { "console", "0" }, { "ether0", "type=2114x" },}; char*getconf(char *name){ int i; for(i = 0; i < nelem(plan9ini); i++) if(cistrcmp(name, plan9ini[i].name) == 0) return plan9ini[i].val; return nil;} voidinit0(void){// char **p, *q, name[KNAMELEN];// int n; 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), "power %s mtx", conffile); ksetenv("terminal", buf, 0); ksetenv("cputype", "power", 0); if(cpuserver) ksetenv("service", "cpu", 0); else ksetenv("service", "terminal", 0); /* for(p = confenv; *p; p++) { q = strchr(p[0], '='); if(q == 0) continue; n = q-p[0]; if(n >= KNAMELEN) n = KNAMELEN-1; memmove(name, p[0], n); name[n] = 0; if(name[0] != '*') ksetenv(name, q+1, 0); ksetenv(name, q+1, 1); }*/ poperror(); } kproc("alarm", alarmkproc, 0); kproc("mmusweep", mmusweep, 0); touser((void*)(USTKTOP-8));} voiduserinit(void){ Proc *p; Segment *s; KMap *k; 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); p->fpstate = FPinit; /* * Kernel Stack * * N.B. The -12 for the stack pointer is important. * 4 bytes for gotolabel's return PC */ p->sched.pc = (ulong)init0; p->sched.sp = (ulong)p->kstack+KSTACK-(sizeof(Sargs)+BY2WD); /* * User Stack */ s = newseg(SG_STACK, USTKTOP-USTKSIZE, USTKSIZE/BY2PG); p->seg[SSEG] = s; pg = newpage(1, 0, USTKTOP-BY2PG); segpage(s, pg); /* * 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((ulong*)VA(k), initcode, sizeof initcode); kunmap(k); ready(p);} /* still to do */voidreboot(void*, void*, ulong){ exit(0);} voidexit(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 if(conf.monitor) for(;;); } else delay(1000); watchreset();} /* * set up floating point for a new process */voidprocsetup(Proc *p){ p->fpstate = FPinit;} /* * Save the mach dependent part of the process state. */voidprocsave(Proc *p){ if(p->fpstate == FPactive){ if(p->state != Moribund) fpsave(&up->fpsave); p->fpstate = FPinactive; }} voidconfinit(void){ char *p; int userpcnt; ulong pa, kpages; extern ulong memsize; /* passed in from ROM monitor */ if(p = getconf("*kernelpercent")) userpcnt = 100 - strtol(p, 0, 0); else userpcnt = 0; pa = PGROUND(PADDR(end)); conf.mem[0].npage = memsize/BY2PG; conf.mem[0].base = pa; conf.npage = conf.mem[0].npage; 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 */} static intgetcfields(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;} intisaconfig(char *class, int ctlrno, ISAConf *isa){ int i; char cc[KNAMELEN], *p; sprint(cc, "%s%d", class, ctlrno); p = getconf(cc); if(p == 0) return 0; isa->nopt = tokenize(p, 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;} intcistrcmp(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;} intcistrncmp(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;}
/*
* This file is part of the UCB release of Plan 9. It is subject to the license
* terms in the LICENSE file found in the top-level directory of this
* distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
* part of the UCB release of Plan 9, including this file, may be copied,
* modified, propagated, or distributed except according to the terms contained
* in the LICENSE file.
*/
#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"
Conf conf;
FPsave initfp;
void
main(void)
{
memset(edata, 0, (ulong)end-(ulong)edata);
conf.nmach = 1;
machinit();
ioinit();
i8250console();
quotefmtinstall();
print("\nPlan 9\n");
confinit();
xinit();
raveninit();
trapinit();
printinit();
cpuidprint();
mmuinit();
hwintrinit();
clockinit();
kbdinit();
procinit0();
initseg();
timersinit();
links();
chandevreset();
pageinit();
swapinit();
fpsave(&initfp);
initfp.fpscr = 0;
userinit();
schedinit();
}
void
machinit(void)
{
memset(m, 0, sizeof(Mach));
m->cputype = getpvr()>>16;
/*
* For polled uart output at boot, need
* a default delay constant. 100000 should
* be enough for a while. Cpuidentify will
* calculate the real value later.
*/
m->loopconst = 100000;
/* turn on caches */
puthid0(gethid0() | BIT(16) | BIT(17));
active.machs = 1;
active.exiting = 0;
}
void
cpuidprint(void)
{
char *id;
id = "unknown PowerPC";
switch(m->cputype) {
case 9:
id = "PowerPC 604e";
break;
}
print("cpu0: %s\n", id);
}
static struct
{
char *name;
char *val;
}
plan9ini[] =
{
{ "console", "0" },
{ "ether0", "type=2114x" },
};
char*
getconf(char *name)
{
int i;
for(i = 0; i < nelem(plan9ini); i++)
if(cistrcmp(name, plan9ini[i].name) == 0)
return plan9ini[i].val;
return nil;
}
void
init0(void)
{
// char **p, *q, name[KNAMELEN];
// int n;
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), "power %s mtx", conffile);
ksetenv("terminal", buf, 0);
ksetenv("cputype", "power", 0);
if(cpuserver)
ksetenv("service", "cpu", 0);
else
ksetenv("service", "terminal", 0);
/*
for(p = confenv; *p; p++) {
q = strchr(p[0], '=');
if(q == 0)
continue;
n = q-p[0];
if(n >= KNAMELEN)
n = KNAMELEN-1;
memmove(name, p[0], n);
name[n] = 0;
if(name[0] != '*')
ksetenv(name, q+1, 0);
ksetenv(name, q+1, 1);
}
*/
poperror();
}
kproc("alarm", alarmkproc, 0);
kproc("mmusweep", mmusweep, 0);
touser((void*)(USTKTOP-8));
}
void
userinit(void)
{
Proc *p;
Segment *s;
KMap *k;
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);
p->fpstate = FPinit;
/*
* Kernel Stack
*
* N.B. The -12 for the stack pointer is important.
* 4 bytes for gotolabel's return PC
*/
p->sched.pc = (ulong)init0;
p->sched.sp = (ulong)p->kstack+KSTACK-(sizeof(Sargs)+BY2WD);
/*
* User Stack
*/
s = newseg(SG_STACK, USTKTOP-USTKSIZE, USTKSIZE/BY2PG);
p->seg[SSEG] = s;
pg = newpage(1, 0, USTKTOP-BY2PG);
segpage(s, pg);
/*
* 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((ulong*)VA(k), initcode, sizeof initcode);
kunmap(k);
ready(p);
}
/* still to do */
void
reboot(void*, void*, ulong)
{
exit(0);
}
void
exit(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 if(conf.monitor)
for(;;);
}
else
delay(1000);
watchreset();
}
/*
* set up floating point for a new process
*/
void
procsetup(Proc *p)
{
p->fpstate = FPinit;
}
/*
* Save the mach dependent part of the process state.
*/
void
procsave(Proc *p)
{
if(p->fpstate == FPactive){
if(p->state != Moribund)
fpsave(&up->fpsave);
p->fpstate = FPinactive;
}
}
void
confinit(void)
{
char *p;
int userpcnt;
ulong pa, kpages;
extern ulong memsize; /* passed in from ROM monitor */
if(p = getconf("*kernelpercent"))
userpcnt = 100 - strtol(p, 0, 0);
else
userpcnt = 0;
pa = PGROUND(PADDR(end));
conf.mem[0].npage = memsize/BY2PG;
conf.mem[0].base = pa;
conf.npage = conf.mem[0].npage;
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 */
}
static 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;
}
int
isaconfig(char *class, int ctlrno, ISAConf *isa)
{
int i;
char cc[KNAMELEN], *p;
sprint(cc, "%s%d", class, ctlrno);
p = getconf(cc);
if(p == 0)
return 0;
isa->nopt = tokenize(p, 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;
}
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;
}