summaryrefslogtreecommitdiff
path: root/sys/src/9/alphapc/main.c
diff options
context:
space:
mode:
authorTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
committerTaru Karttunen <taruti@taruti.net>2011-03-30 15:46:40 +0300
commite5888a1ffdae813d7575f5fb02275c6bb07e5199 (patch)
treed8d51eac403f07814b9e936eed0c9a79195e2450 /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-xsys/src/9/alphapc/main.c703
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;
+}