]> git.lizzy.rs Git - plan9front.git/blobdiff - sys/src/9/pc/main.c
merge
[plan9front.git] / sys / src / 9 / pc / main.c
index 1ea96d6c7a4063640939dac9482ce236eef91239..2479bc0713908217d0e6ffde0baeba0805752ead 100644 (file)
@@ -24,13 +24,61 @@ Mach *m;
 #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)
@@ -38,6 +86,8 @@ options(void)
        long i, n;
        char *cp, *line[MAXCONF], *p, *q;
 
+       multibootargs();
+
        /*
         *  parse configuration args from dos file plan9.ini
         */
@@ -71,8 +121,8 @@ options(void)
        }
 }
 
-extern void mmuinit0(void);
 extern void (*i8237alloc)(void);
+extern void bootscreeninit(void);
 
 void
 main(void)
@@ -87,15 +137,13 @@ main(void)
        print("\nPlan 9\n");
 
        trapinit0();
-       mmuinit0();
-
-       kbdinit();
        i8253init();
        cpuidentify();
        meminit();
        confinit();
-       archinit();
        xinit();
+       archinit();
+       bootscreeninit();
        if(i8237alloc != nil)
                i8237alloc();
        trapinit();
@@ -106,7 +154,6 @@ main(void)
                arch->intrinit();
        timersinit();
        mathinit();
-       kbdenable();
        if(arch->clockenable)
                arch->clockenable();
        procinit0();
@@ -116,12 +163,10 @@ main(void)
                pcimatch(0, 0, 0);
        }else
                links();
-       conf.monitor = 1;
        chandevreset();
        pageinit();
        swapinit();
        userinit();
-       active.thunderbirdsarego = 1;
        schedinit();
 }
 
@@ -135,7 +180,7 @@ mach0init(void)
 
        machinit();
 
-       active.machs = 1;
+       active.machs[0] = 1;
        active.exiting = 0;
 }
 
@@ -258,7 +303,7 @@ userinit(void)
        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);
@@ -268,53 +313,39 @@ userinit(void)
        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;
 }
 
@@ -365,6 +396,13 @@ confinit(void)
        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
@@ -387,6 +425,7 @@ confinit(void)
                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.
@@ -396,9 +435,9 @@ confinit(void)
                 * 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 {
@@ -430,8 +469,7 @@ confinit(void)
 
        /*
         * 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)
@@ -445,7 +483,7 @@ confinit(void)
         * 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)
@@ -453,6 +491,163 @@ confinit(void)
        }
 }
 
+/*
+ * 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 */
@@ -464,13 +659,10 @@ static char* mathmsg[] =
 };
 
 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
@@ -493,7 +685,7 @@ mathnote(void)
                        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);
 }
 
@@ -501,24 +693,32 @@ mathnote(void)
  *  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);
 }
 
 /*
@@ -527,6 +727,8 @@ matherror(Ureg *ur, void*)
 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);
@@ -535,6 +737,8 @@ mathemu(Ureg *ureg, void*)
        switch(up->fpstate){
        case FPinit:
                fpinit();
+               if(fpsave == fpssesave)
+                       ldmxcsr(0);     /* no simd exceptions on 386 */
                up->fpstate = FPactive;
                break;
        case FPinactive:
@@ -545,8 +749,10 @@ mathemu(Ureg *ureg, void*)
                 * 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);
@@ -576,6 +782,7 @@ mathinit(void)
                intrenable(IrqIRQ13, matherror, 0, BUSUNKNOWN, "matherror");
        trapenable(VectorCNA, mathemu, 0, "mathemu");
        trapenable(VectorCSO, mathover, 0, "mathover");
+       trapenable(VectorSIMD, simderror, 0, "simderror");
 }
 
 /*
@@ -598,6 +805,8 @@ procsetup(Proc *p)
 void
 procfork(Proc *p)
 {
+       int s;
+
        p->kentry = up->kentry;
        p->pcycles = -p->kentry;
 
@@ -610,6 +819,18 @@ procfork(Proc *p)
                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
@@ -668,51 +889,6 @@ procsave(Proc *p)
        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)
 {
@@ -731,19 +907,7 @@ 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();
 
@@ -766,112 +930,15 @@ reboot(void *entry, void *code, ulong size)
        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);
-}