#define BOOTARGSLEN (4096-0x200-BOOTLINELEN)
#define MAXCONF 64
-char bootdisk[KNAMELEN];
Conf conf;
char *confname[MAXCONF];
char *confval[MAXCONF];
int nconf;
-uchar *sp; /* user stack of init proc */
+char *sp; /* user stack of init proc */
int delaylink;
+int idle_spin;
+
+static void
+multibootargs(void)
+{
+ char *cp, *ep;
+ ulong *m, l;
+
+ extern ulong *multiboot;
+
+ if(multiboot == nil)
+ return;
+
+ /* command line */
+ if((multiboot[0] & (1<<2)) != 0)
+ strncpy(BOOTLINE, KADDR(multiboot[4]), BOOTLINELEN-1);
+
+ cp = BOOTARGS;
+ ep = cp + BOOTARGSLEN-1;
+
+ /* memory map */
+ if((multiboot[0] & (1<<6)) != 0 && (l = multiboot[11]) >= 24){
+ cp = seprint(cp, ep, "*e820=");
+ m = KADDR(multiboot[12]);
+ while(m[0] >= 20 && m[0] <= l-4){
+ uvlong base, size;
+ m++;
+ base = ((uvlong)m[0] | (uvlong)m[1]<<32);
+ size = ((uvlong)m[2] | (uvlong)m[3]<<32);
+ cp = seprint(cp, ep, "%.1lux %.16llux %.16llux ",
+ m[4] & 0xF, base, base+size);
+ l -= m[-1]+4;
+ m = (ulong*)((ulong)m + m[-1]);
+ }
+ cp[-1] = '\n';
+ }
+
+ /* plan9.ini passed as the first module */
+ if((multiboot[0] & (1<<3)) != 0 && multiboot[5] > 0){
+ m = KADDR(multiboot[6]);
+ l = m[1] - m[0];
+ m = KADDR(m[0]);
+ if(cp+l > ep)
+ l = ep - cp;
+ memmove(cp, m, l);
+ cp += l;
+ }
+ *cp = 0;
+}
static void
options(void)
long i, n;
char *cp, *line[MAXCONF], *p, *q;
+ multibootargs();
+
/*
* parse configuration args from dos file plan9.ini
*/
}
}
-extern void mmuinit0(void);
extern void (*i8237alloc)(void);
+extern void bootscreeninit(void);
void
main(void)
print("\nPlan 9\n");
trapinit0();
- mmuinit0();
-
- kbdinit();
i8253init();
cpuidentify();
meminit();
confinit();
- archinit();
xinit();
+ archinit();
+ bootscreeninit();
if(i8237alloc != nil)
i8237alloc();
trapinit();
arch->intrinit();
timersinit();
mathinit();
- kbdenable();
if(arch->clockenable)
arch->clockenable();
procinit0();
pcimatch(0, 0, 0);
}else
links();
- conf.monitor = 1;
chandevreset();
pageinit();
swapinit();
userinit();
- active.thunderbirdsarego = 1;
schedinit();
}
machinit();
- active.machs = 1;
+ active.machs[0] = 1;
active.exiting = 0;
}
s->flushme++;
p->seg[TSEG] = s;
pg = newpage(0, 0, UTZERO);
- memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl));
+ pg->txtflush = ~0;
segpage(s, pg);
v = tmpmap(pg);
memset(v, 0, BY2PG);
ready(p);
}
-uchar *
-pusharg(char *p)
-{
- int n;
-
- n = strlen(p)+1;
- sp -= n;
- memmove(sp, p, n);
- return sp;
-}
-
void
bootargs(void *base)
{
- int i, ac;
- uchar *av[32];
- uchar **lsp;
- char *cp = BOOTLINE;
- char buf[64];
-
- sp = (uchar*)base + BY2PG - sizeof(Tos);
-
- ac = 0;
- av[ac++] = pusharg("boot");
-
- /* when boot is changed to only use rc, this code can go away */
- cp[BOOTLINELEN-1] = 0;
- buf[0] = 0;
- if(strncmp(cp, "fd", 2) == 0){
- sprint(buf, "local!#f/fd%lddisk", strtol(cp+2, 0, 0));
- av[ac++] = pusharg(buf);
- } else if(strncmp(cp, "sd", 2) == 0){
- sprint(buf, "local!#S/sd%c%c/fs", *(cp+2), *(cp+3));
- av[ac++] = pusharg(buf);
- } else if(strncmp(cp, "ether", 5) == 0)
- av[ac++] = pusharg("-n");
+ char *argv[8];
+ int i, argc;
+
+#define UA(ka) ((char*)(ka) + ((uintptr)(USTKTOP - BY2PG) - (uintptr)base))
+ sp = (char*)base + BY2PG - sizeof(Tos);
+
+ /* push boot command line onto the stack */
+ sp -= BOOTLINELEN;
+ sp[BOOTLINELEN-1] = '\0';
+ memmove(sp, BOOTLINE, BOOTLINELEN-1);
+
+ /* parse boot command line */
+ argc = tokenize(sp, argv, nelem(argv));
+ if(argc < 1){
+ strcpy(sp, "boot");
+ argc = 0;
+ argv[argc++] = sp;
+ }
/* 4 byte word align stack */
- sp = (uchar*)((ulong)sp & ~3);
-
- /* build argc, argv on stack */
- sp -= (ac+1)*sizeof(sp);
- lsp = (uchar**)sp;
- for(i = 0; i < ac; i++)
- lsp[i] = av[i] + ((USTKTOP - BY2PG) - (ulong)base);
- lsp[i] = 0;
- sp += (USTKTOP - BY2PG) - (ulong)base;
+ sp = (char*)((uintptr)sp & ~3);
+
+ /* build argv on stack */
+ sp -= (argc+1)*BY2WD;
+ for(i=0; i<argc; i++)
+ ((char**)sp)[i] = UA(argv[i]);
+ ((char**)sp)[i] = nil;
+
+ sp = UA(sp);
+#undef UA
sp -= BY2WD;
}
int i, userpcnt;
ulong kpages;
+ if(p = getconf("service")){
+ if(strcmp(p, "cpu") == 0)
+ cpuserver = 1;
+ else if(strcmp(p,"terminal") == 0)
+ cpuserver = 0;
+ }
+
if(p = getconf("*kernelpercent"))
userpcnt = 100 - strtol(p, 0, 0);
else
if(userpcnt < 10)
userpcnt = 70;
kpages = conf.npage - (conf.npage*userpcnt)/100;
+ conf.nimage = conf.nproc;
/*
* Hack for the big boys. Only good while physmem < 4GB.
* The patch of nimage is a band-aid, scanning the whole
* page list in imagereclaim just takes too long.
*/
+ if(getconf("*imagemaxmb") == 0)
if(kpages > (64*MB + conf.npage*sizeof(Page))/BY2PG){
kpages = (64*MB + conf.npage*sizeof(Page))/BY2PG;
- conf.nimage = 2000;
kpages += (conf.nproc*KSTACK)/BY2PG;
}
} else {
/*
* Guess how much is taken by the large permanent
- * datastructures. Mntcache and Mntrpc are not accounted for
- * (probably ~300KB).
+ * datastructures. Mntcache and Mntrpc are not accounted for.
*/
kpages *= BY2PG;
kpages -= conf.upages*sizeof(Page)
* the dynamic allocation will balance the load properly,
* hopefully. be careful with 32-bit overflow.
*/
- imagmem->maxsize = mainmem->maxsize;
+ imagmem->maxsize = kpages - (kpages/10);
if(p = getconf("*imagemaxmb")){
imagmem->maxsize = strtol(p, nil, 0)*MB;
if(imagmem->maxsize > mainmem->maxsize)
}
}
+/*
+ * we keep FPsave structure in sse format emulating FXSAVE / FXRSTOR
+ * instructions for legacy x87 fpu.
+ *
+ * Note that fpx87restore() and fpxsserestore() do modify the FPsave
+ * data structure for conversion / realignment shuffeling. this means
+ * that p->fpsave is only valid when p->fpstate == FPinactive.
+ */
+void
+fpx87save(FPsave *fps)
+{
+ ushort tag;
+
+ fpx87save0(fps);
+
+ /*
+ * convert x87 tag word to fxsave tag byte:
+ * 00, 01, 10 -> 1, 11 -> 0
+ */
+ tag = ~fps->tag;
+ tag = (tag | (tag >> 1)) & 0x5555;
+ tag = (tag | (tag >> 1)) & 0x3333;
+ tag = (tag | (tag >> 2)) & 0x0F0F;
+ tag = (tag | (tag >> 4)) & 0x00FF;
+
+ /* NOP fps->fcw = fps->control; */
+ fps->fsw = fps->status;
+ fps->ftw = tag;
+ fps->fop = fps->opcode;
+ fps->fpuip = fps->pc;
+ fps->cs = fps->selector;
+ fps->fpudp = fps->operand;
+ fps->ds = fps->oselector;
+
+#define MOVA(d,s) \
+ *((ushort*)(d+8)) = *((ushort*)(s+8)), \
+ *((ulong*)(d+4)) = *((ulong*)(s+4)), \
+ *((ulong*)(d)) = *((ulong*)(s))
+
+ MOVA(fps->xregs+0x70, fps->regs+70);
+ MOVA(fps->xregs+0x60, fps->regs+60);
+ MOVA(fps->xregs+0x50, fps->regs+50);
+ MOVA(fps->xregs+0x40, fps->regs+40);
+ MOVA(fps->xregs+0x30, fps->regs+30);
+ MOVA(fps->xregs+0x20, fps->regs+20);
+ MOVA(fps->xregs+0x10, fps->regs+10);
+ MOVA(fps->xregs+0x00, fps->regs+00);
+
+#undef MOVA
+
+#define CLR6(d) \
+ *((ulong*)(d)) = 0, \
+ *((ushort*)(d+4)) = 0
+
+ CLR6(fps->xregs+0x70+10);
+ CLR6(fps->xregs+0x60+10);
+ CLR6(fps->xregs+0x50+10);
+ CLR6(fps->xregs+0x40+10);
+ CLR6(fps->xregs+0x30+10);
+ CLR6(fps->xregs+0x20+10);
+ CLR6(fps->xregs+0x10+10);
+ CLR6(fps->xregs+0x00+10);
+
+#undef CLR6
+
+ fps->rsrvd1 = fps->rsrvd2 = fps->mxcsr = fps->mxcsr_mask = 0;
+}
+
+void
+fpx87restore(FPsave *fps)
+{
+ ushort msk, tos, tag, *reg;
+
+ /* convert fxsave tag byte to x87 tag word */
+ tag = 0;
+ tos = 7 - ((fps->fsw >> 11) & 7);
+ for(msk = 0x80; msk != 0; tos--, msk >>= 1){
+ tag <<= 2;
+ if((fps->ftw & msk) != 0){
+ reg = (ushort*)&fps->xregs[(tos & 7) << 4];
+ switch(reg[4] & 0x7fff){
+ case 0x0000:
+ if((reg[0] | reg[1] | reg[2] | reg[3]) == 0){
+ tag |= 1; /* 01 zero */
+ break;
+ }
+ /* no break */
+ case 0x7fff:
+ tag |= 2; /* 10 special */
+ break;
+ default:
+ if((reg[3] & 0x8000) == 0)
+ break; /* 00 valid */
+ tag |= 2; /* 10 special */
+ break;
+ }
+ }else{
+ tag |= 3; /* 11 empty */
+ }
+ }
+
+#define MOVA(d,s) \
+ *((ulong*)(d)) = *((ulong*)(s)), \
+ *((ulong*)(d+4)) = *((ulong*)(s+4)), \
+ *((ushort*)(d+8)) = *((ushort*)(s+8))
+
+ MOVA(fps->regs+00, fps->xregs+0x00);
+ MOVA(fps->regs+10, fps->xregs+0x10);
+ MOVA(fps->regs+20, fps->xregs+0x20);
+ MOVA(fps->regs+30, fps->xregs+0x30);
+ MOVA(fps->regs+40, fps->xregs+0x40);
+ MOVA(fps->regs+50, fps->xregs+0x50);
+ MOVA(fps->regs+60, fps->xregs+0x60);
+ MOVA(fps->regs+70, fps->xregs+0x70);
+
+#undef MOVA
+
+ fps->oselector = fps->ds;
+ fps->operand = fps->fpudp;
+ fps->opcode = fps->fop & 0x7ff;
+ fps->selector = fps->cs;
+ fps->pc = fps->fpuip;
+ fps->tag = tag;
+ fps->status = fps->fsw;
+ /* NOP fps->control = fps->fcw; */
+
+ fps->r1 = fps->r2 = fps->r3 = fps->r4 = 0;
+
+ fpx87restore0(fps);
+}
+
+/*
+ * sse fp save and restore buffers have to be 16-byte (FPalign) aligned,
+ * so we shuffle the data up and down as needed or make copies.
+ */
+void
+fpssesave(FPsave *fps)
+{
+ FPsave *afps;
+
+ afps = (FPsave *)ROUND(((uintptr)fps), FPalign);
+ fpssesave0(afps);
+ if(fps != afps) /* not aligned? shuffle down from aligned buffer */
+ memmove(fps, afps, sizeof(FPssestate) - FPalign);
+}
+
+void
+fpsserestore(FPsave *fps)
+{
+ FPsave *afps;
+
+ afps = (FPsave *)ROUND(((uintptr)fps), FPalign);
+ if(fps != afps) /* shuffle up to make aligned */
+ memmove(afps, fps, sizeof(FPssestate) - FPalign);
+ fpsserestore0(afps);
+}
+
static char* mathmsg[] =
{
nil, /* handled below */
};
static void
-mathnote(void)
+mathnote(ulong status, ulong pc)
{
- int i;
- ulong status;
char *msg, note[ERRMAX];
-
- status = up->fpsave.status;
+ int i;
/*
* Some attention should probably be paid here to the
msg = "invalid operation";
}
snprint(note, sizeof note, "sys: fp: %s fppc=0x%lux status=0x%lux",
- msg, up->fpsave.pc, status);
+ msg, pc, status);
postnote(up, 1, note, NDebug);
}
* math coprocessor error
*/
static void
-matherror(Ureg *ur, void*)
+matherror(Ureg*, void*)
{
/*
* a write cycle to port 0xF0 clears the interrupt latch attached
* to the error# line from the 387
*/
- if(!(m->cpuiddx & 0x01))
+ if(!(m->cpuiddx & Fpuonchip))
outb(0xF0, 0xFF);
/*
- * save floating point state to check out error
+ * get floating point state to check out error
*/
- fpenv(&up->fpsave);
- mathnote();
+ fpsave(&up->fpsave);
+ up->fpstate = FPinactive;
+ mathnote(up->fpsave.fsw, up->fpsave.fpuip);
+}
- if((ur->pc & 0xf0000000) == KZERO)
- panic("fp: status %ux fppc=0x%lux pc=0x%lux",
- up->fpsave.status, up->fpsave.pc, ur->pc);
+/*
+ * SIMD error
+ */
+static void
+simderror(Ureg *ureg, void*)
+{
+ fpsave(&up->fpsave);
+ up->fpstate = FPinactive;
+ mathnote(up->fpsave.mxcsr & 0x3f, ureg->pc);
}
/*
static void
mathemu(Ureg *ureg, void*)
{
+ ulong status, control;
+
if(up->fpstate & FPillegal){
/* someone did floating point in a note handler */
postnote(up, 1, "sys: floating point in note handler", NDebug);
switch(up->fpstate){
case FPinit:
fpinit();
+ if(fpsave == fpssesave)
+ ldmxcsr(0); /* no simd exceptions on 386 */
up->fpstate = FPactive;
break;
case FPinactive:
* More attention should probably be paid here to the
* exception masks and error summary.
*/
- if((up->fpsave.status & ~up->fpsave.control) & 0x07F){
- mathnote();
+ status = up->fpsave.fsw;
+ control = up->fpsave.fcw;
+ if((status & ~control) & 0x07F){
+ mathnote(status, up->fpsave.fpuip);
break;
}
fprestore(&up->fpsave);
intrenable(IrqIRQ13, matherror, 0, BUSUNKNOWN, "matherror");
trapenable(VectorCNA, mathemu, 0, "mathemu");
trapenable(VectorCSO, mathover, 0, "mathover");
+ trapenable(VectorSIMD, simderror, 0, "simderror");
}
/*
void
procfork(Proc *p)
{
+ int s;
+
p->kentry = up->kentry;
p->pcycles = -p->kentry;
memmove(p->ldt, up->ldt, sizeof(Segdesc) * up->nldt);
p->nldt = up->nldt;
}
+
+ /* save floating point state */
+ s = splhi();
+ switch(up->fpstate & ~FPillegal){
+ case FPactive:
+ fpsave(&up->fpsave);
+ up->fpstate = FPinactive;
+ case FPinactive:
+ p->fpsave = up->fpsave;
+ p->fpstate = FPinactive;
+ }
+ splx(s);
}
void
mmuflushtlb(PADDR(m->pdb));
}
-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);
- /*
- * setting exiting will make hzclock() on each processor call exit(0),
- * which calls shutdown(0) and arch->reset(), which on mp systems is
- * mpshutdown, from which there is no return: the processor is idled
- * or initiates a reboot. clearing our bit in machs avoids calling
- * exit(0) from hzclock() on this processor.
- */
- active.machs &= ~(1<<m->machno);
- active.exiting = 1;
- unlock(&active);
-
- if(once)
- iprint("cpu%d: exiting\n", m->machno);
-
- /* wait for any other processors to shutdown */
- spllo();
- for(ms = 5*1000; ms > 0; ms -= TK2MS(2)){
- delay(TK2MS(2));
- if(active.machs == 0 && consactive() == 0)
- break;
- }
-
- if(active.ispanic){
- if(!cpuserver)
- for(;;)
- halt();
- if(getconf("*debug"))
- delay(5*60*1000);
- else
- delay(10000);
- }else
- delay(1000);
-}
-
void
reboot(void *entry, void *code, ulong size)
{
procwired(up, 0);
sched();
}
-
- shutdown(0);
-
- /*
- * should be the only processor running now
- */
- if (m->machno != 0)
- print("on cpu%d (not 0)!\n", m->machno);
- if (active.machs)
- print("still have active ap processors!\n");
-
- print("shutting down...\n");
- delay(200);
+ cpushutdown();
splhi();
f = (void*)REBOOTADDR;
memmove(f, rebootcode, sizeof(rebootcode));
- print("rebooting...\n");
-
/* off we go - never to return */
coherence();
- (*f)(PADDR(entry), PADDR(code), size);
+ (*f)((ulong)entry & ~0xF0000000UL, PADDR(code), size);
}
void
-exit(int ispanic)
+exit(int)
{
- shutdown(ispanic);
+ cpushutdown();
arch->reset();
}
-
-int
-isaconfig(char *class, int ctlrno, ISAConf *isa)
-{
- char cc[32], *p;
- int i;
-
- snprint(cc, sizeof cc, "%s%d", class, ctlrno);
- p = getconf(cc);
- if(p == nil)
- return 0;
-
- isa->type = "";
- 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;
-}
-
-/*
- * put the processor in the halt state if we've no processes to run.
- * an interrupt will get us going again.
- */
-void
-idlehands(void)
-{
- extern int nrdy;
-
- if(conf.nmach == 1)
- halt();
- else if(m->cpuidcx & Monitor)
- mwait(&nrdy);
-}