![cinap_lenrek](/assets/img/avatar_default.png)
there are no kernels currently that do page coloring, so the only use of cachectl[] is flushing the icache (on arm and ppc). on pc64, cachectl consumes 32 bytes in each page resulting in over 200 megabytes of overhead for 32gb of ram with 4K pages. this change removes cachectl[] and adds txtflush ulong that is set to ~0 by pio() to instruct putmmu() to flush the icache.
469 lines
8.1 KiB
C
469 lines
8.1 KiB
C
#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();
|
|
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);
|
|
pg->txtflush = ~0;
|
|
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;
|
|
}
|
|
|
|
void
|
|
procfork(Proc *)
|
|
{
|
|
}
|
|
|
|
/*
|
|
* 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.
|
|
*/
|
|
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;
|
|
}
|