512 lines
8.9 KiB
C
512 lines
8.9 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"
|
|
#include "tos.h"
|
|
|
|
#define MAXCONF 64
|
|
|
|
typedef struct Plan9ini Plan9ini;
|
|
struct Plan9ini
|
|
{
|
|
char *name;
|
|
char *val;
|
|
};
|
|
|
|
char *plan9inistr;
|
|
Plan9ini plan9ini[MAXCONF];
|
|
int nconf;
|
|
|
|
Conf conf;
|
|
FPsave initfp;
|
|
Lock testlock;
|
|
|
|
static void plan9iniinit(void);
|
|
|
|
char *
|
|
cpuid(void)
|
|
{
|
|
char *id;
|
|
|
|
id = "unknown PowerPC";
|
|
switch(m->cputype) {
|
|
case 8:
|
|
id = "PowerPC 750";
|
|
break;
|
|
case 9:
|
|
id = "PowerPC 604e";
|
|
break;
|
|
case 0x81:
|
|
id = "PowerPC 8260";
|
|
break;
|
|
case 0x8081:
|
|
id = "PowerPC 826xA";
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
return id;
|
|
}
|
|
|
|
void
|
|
cpuidprint(void)
|
|
{
|
|
print("cpu0: %s, rev 0x%lux, cpu hz %lld, bus hz %ld\n",
|
|
cpuid(), getpvr()&0xffff, m->cpuhz, m->bushz);
|
|
}
|
|
|
|
void
|
|
main(void)
|
|
{
|
|
memset(edata, 0, (ulong)end-(ulong)edata);
|
|
conf.nmach = 1;
|
|
machinit();
|
|
confinit();
|
|
xinit();
|
|
trapinit();
|
|
mmuinit();
|
|
plan9iniinit();
|
|
hwintrinit();
|
|
clockinit();
|
|
timerinit();
|
|
console();
|
|
quotefmtinstall();
|
|
printinit();
|
|
cpuidprint();
|
|
print("\nPlan 9 from Bell Labs\n");
|
|
procinit0();
|
|
initseg();
|
|
timersinit();
|
|
links();
|
|
chandevreset();
|
|
pageinit();
|
|
swapinit();
|
|
sharedseginit();
|
|
fpsave(&initfp);
|
|
initfp.fpscr = 0;
|
|
userinit();
|
|
schedinit();
|
|
}
|
|
|
|
char*
|
|
getconf(char *name)
|
|
{
|
|
int i;
|
|
|
|
for(i = 0; i < nconf; i++)
|
|
if(cistrcmp(name, plan9ini[i].name) == 0)
|
|
return plan9ini[i].val;
|
|
return nil;
|
|
}
|
|
|
|
static void
|
|
plan9iniinit(void)
|
|
{
|
|
long i;
|
|
int c;
|
|
char *cp, line[MAXCONF], *p, *q;
|
|
|
|
/*
|
|
* parse configuration args from dos file plan9.ini
|
|
*/
|
|
|
|
cp = plan9inistr;
|
|
for(i = 0; i < MAXCONF; i++){
|
|
/*
|
|
* Strip out '\r', change '\t' -> ' ', test for 0xff which is end of file
|
|
*/
|
|
p = line;
|
|
for(q = cp; c = (uchar)*q; q++){
|
|
if(c == '\r')
|
|
continue;
|
|
if(c == '\t')
|
|
c = ' ';
|
|
if(c == 0xff || c == '\n')
|
|
break;
|
|
*p++ = c;
|
|
}
|
|
*p = 0;
|
|
if (*line == 0)
|
|
break;
|
|
if(*line != '#' && (cp = strchr(line, '='))){
|
|
*cp++ = '\0';
|
|
kstrdup(&plan9ini[nconf].name, line);
|
|
kstrdup(&plan9ini[nconf].val, cp);
|
|
nconf++;
|
|
}
|
|
if (c == 0xff)
|
|
break;
|
|
|
|
cp = q + 1;
|
|
}
|
|
}
|
|
|
|
void
|
|
init0(void)
|
|
{
|
|
// char **p, *q, name[KNAMELEN];
|
|
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), "power %s mtx", conffile);
|
|
ksetenv("terminal", buf, 0);
|
|
ksetenv("cputype", "power", 0);
|
|
if(cpuserver)
|
|
ksetenv("service", "cpu", 0);
|
|
else
|
|
ksetenv("service", "terminal", 0);
|
|
|
|
for(i = 0; i < nconf; i++){
|
|
if(plan9ini[i].name[0] != '*')
|
|
ksetenv(plan9ini[i].name, plan9ini[i].val, 0);
|
|
ksetenv(plan9ini[i].name, plan9ini[i].val, 1);
|
|
}
|
|
poperror();
|
|
}
|
|
kproc("alarm", alarmkproc, 0);
|
|
kproc("mmusweep", mmusweep, 0);
|
|
touser((void*)(USTKTOP-sizeof(Tos)));
|
|
}
|
|
|
|
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;
|
|
|
|
/*
|
|
* 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);
|
|
}
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
/*
|
|
* set up floating point for a new process
|
|
*/
|
|
void
|
|
procsetup(Proc *p)
|
|
{
|
|
p->fpstate = FPinit;
|
|
}
|
|
|
|
void
|
|
procrestore(Proc *p)
|
|
{
|
|
uvlong t;
|
|
|
|
if(p->kp)
|
|
return;
|
|
cycles(&t);
|
|
p->pcycles -= t;
|
|
}
|
|
|
|
/*
|
|
* Save the mach dependent part of the process state.
|
|
*/
|
|
void
|
|
procsave(Proc *p)
|
|
{
|
|
uvlong t;
|
|
|
|
cycles(&t);
|
|
p->pcycles += t;
|
|
if(p->fpstate == FPactive){
|
|
if(p->state != Moribund)
|
|
fpsave(&up->fpsave);
|
|
p->fpstate = FPinactive;
|
|
}
|
|
}
|
|
|
|
void
|
|
confinit(void)
|
|
{
|
|
char *p;
|
|
int userpcnt;
|
|
ulong pa, kpages;
|
|
/* passed in from ROM monitor: */
|
|
|
|
if(p = getconf("*kernelpercent"))
|
|
userpcnt = 100 - strtol(p, 0, 0);
|
|
else
|
|
userpcnt = 0;
|
|
|
|
pa = PGROUND(PADDR(end));
|
|
|
|
/* Blast Board specific */
|
|
conf.mem[0].npage = (MEM1SIZE - pa)/BY2PG;
|
|
conf.mem[0].base = pa;
|
|
|
|
conf.mem[1].npage = MEM2SIZE/BY2PG;
|
|
conf.mem[1].base = MEM2BASE;
|
|
|
|
conf.npage = conf.mem[0].npage + conf.mem[1].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;
|
|
}
|