main.c - vx32 - Local 9vx git repository for patches.
 (HTM) git clone git://r-36.net/vx32
 (DIR) Log
 (DIR) Files
 (DIR) Refs
       ---
       main.c (13970B)
       ---
            1 /*
            2  * Plan 9 VX
            3  */
            4 
            5 #define        WANT_M
            6 
            7 #ifdef __APPLE__
            8 #define __DARWIN_UNIX03 0
            9 #endif
           10 
           11 #include        "u.h"
           12 #include        "libvx32/vx32.h"
           13 #include        <sys/mman.h>
           14 #include        <signal.h>
           15 #include        <pwd.h>
           16 #include        <pthread.h>
           17 #include        "lib.h"
           18 #include        "mem.h"
           19 #include        "dat.h"
           20 #include        "fns.h"
           21 #include        "io.h"
           22 #include        "ureg.h"
           23 #include        "init.h"
           24 #include        "error.h"
           25 #include        "arg.h"
           26 #include        "tos.h"
           27 
           28 #include        "fs.h"
           29 
           30 #include        "conf.h"
           31 
           32 #include        "netif.h"
           33 #include        "etherif.h"
           34 #include        "vether.h"
           35 
           36 #define Image IMAGE
           37 #include        "draw.h"
           38 #include        "memdraw.h"
           39 #include        "cursor.h"
           40 #include        "screen.h"
           41 
           42 extern Dev ipdevtab;
           43 extern Dev pipdevtab;
           44 extern Dev drawdevtab;
           45 extern Dev fsdevtab;
           46 extern Dev audiodevtab;
           47 
           48 int        doabort = 1;        // for now
           49 int        abortonfault;
           50 int        nocpuload;
           51 char*        argv0;
           52 char*        conffile = "9vx";
           53 Conf        conf;
           54 
           55 static Mach mach0;
           56 
           57 extern int        tracemmu;
           58 extern int tracekdev;
           59 extern int nuspace;
           60 static int singlethread;
           61 
           62 static void        siginit(void);
           63 static void machkeyinit(void);
           64 
           65 static char*        getuser(void);
           66 
           67 void
           68 usage(void)
           69 {
           70         // TODO(yy): add debug and other options by ron
           71         fprint(2, "usage: 9vx [-gt] [-f inifile | inifields ... ] [-i initarg] [-r localroot] [-u user]\n");
           72         exit(1);
           73 }
           74 
           75 void
           76 nop(void)
           77 {
           78 }
           79 
           80 int
           81 main(int argc, char **argv)
           82 {
           83         char *file;
           84 
           85         /* Minimal set up to make print work. */
           86 #ifndef TLS
           87         machkeyinit();
           88 #endif
           89         setmach(&mach0);
           90         coherence = nop;
           91         cmpswap = oscmpswap;
           92         quotefmtinstall();
           93 
           94         cpulimit = 0;
           95         memset(inifield, 0, MAXCONF);
           96         memsize = 256;
           97         canopen = "/";
           98         nogui = 0;
           99         nofork = 0;
          100         nve = 0;
          101         usetty = 0;
          102 readargs:
          103         ARGBEGIN{
          104         /* debugging options */
          105         case '1':
          106                 singlethread = 1;
          107                 break;
          108         case 'A':
          109                 doabort++;
          110                 break;
          111         case 'B':
          112                 abortonfault++;
          113                 break;
          114         case 'F':
          115                 nofork = 1;
          116                 break;
          117         case 'K':
          118                 tracekdev++;
          119                 break;
          120         case 'L':
          121                 nocpuload++;
          122                 break;
          123         case 'M':
          124                 tracemmu++;
          125                 break;
          126         case 'P':
          127                 traceprocs++;
          128                 break;
          129         case 'S':
          130                 tracesyscalls++;
          131                 break;
          132         case 'U':
          133                 nuspace = atoi(EARGF(usage()));
          134                 break;
          135         case 'X':
          136                 vx32_debugxlate++;
          137                 break;
          138         
          139         /* real options */
          140         case 'g':
          141                 nogui = 1;
          142                 usetty = 1;
          143                 break;
          144         case 't':
          145                 usetty = 1;
          146                 break;
          147         
          148         /* ini values */
          149         case 'f':
          150                 file = EARGF(usage());
          151                 if(addinifile(file) < 0)
          152                         panic("error reading config file %s", file);
          153                 break;
          154         case 'i':
          155                 /*
          156                  * Pass additional flag after -i to init 
          157                  * This is convenient for -ic and -im
          158                  */
          159                 if(_args[0] != 0){
          160                         initarg = smprint("-%c", _args[0]);
          161                         _args++;
          162                 }
          163                 else
          164                         initarg = EARGF(usage());
          165                 break;
          166         case 'r':
          167                 localroot = EARGF(usage());
          168                 break;
          169         case 'u':
          170                 username = EARGF(usage());
          171                 break;
          172 
          173         default:
          174                 usage();
          175         }ARGEND
          176 
          177         while(argc > 0){
          178                 if(argv[0][0] == '-'){
          179                         /*
          180                          * ARGBEGIN will do: argv++; argc--;
          181                          * to skip argv0, but argv[0] is not argv0 now
          182                          */
          183                         argc++; argv--;
          184                         goto readargs;
          185                 }
          186                 addini(strdup(argv[0]));
          187                 argc--; argv++;
          188         }
          189 
          190         if(username == nil && (username = getuser()) == nil)
          191                 username = "tor";
          192         eve = strdup(username);
          193         if(eve == nil)
          194                 panic("strdup eve");
          195 
          196         mmusize(memsize);
          197         mach0init();
          198         mmuinit();
          199         confinit();
          200         conf.monitor = !nogui;
          201 
          202         /*
          203          * Unless we're going to use the terminal for input/output,
          204          * fork into the background.  This is a little dicey, since we
          205          * haven't allocated the screen yet, but that would kick off
          206          * a kproc, and we need to fork before we start any pthreads.
          207          * Cannot fork on OS X - it can't handle it.
          208          */
          209 #ifndef __APPLE__
          210         if(!usetty && !nofork && fork() > 0)
          211                 _exit(0);
          212 #endif
          213 
          214         /*
          215          * Have to do this after fork; on OS X child does
          216          * not inherit sigaltstack.
          217          */
          218         siginit();
          219 
          220         printconfig(argv0);
          221 
          222         if(nve == 0)
          223                 ipdevtab = pipdevtab;
          224 
          225         printinit();
          226         procinit0();
          227         initseg();
          228         if(nve > 0)
          229                 links();
          230 
          231         chandevreset();
          232         if(!singlethread){
          233                 if(nve == 0)
          234                         makekprocdev(&ipdevtab);
          235                 makekprocdev(&fsdevtab);
          236                 makekprocdev(&drawdevtab);
          237                 makekprocdev(&audiodevtab);
          238                 if(nocpuload == 0)
          239                         kproc("pload", &ploadproc, nil);
          240                 if(cpulimit > 0 && cpulimit < 100)
          241                         kproc("plimit", &plimitproc, &cpulimit);
          242         }
          243         bootinit();
          244         pageinit();
          245 #ifdef __APPLE__
          246         if(conf.monitor)
          247                 screeninit();
          248         extern void machsiginit(void);
          249         machsiginit();
          250 #endif
          251         userinit();
          252         terminit(!usetty);
          253         uartinit(usetty);
          254         timersinit();
          255         active.thunderbirdsarego = 1;
          256         schedinit();
          257         return 0;  // Not reached
          258 }
          259 
          260 static char*
          261 getuser(void)
          262 {
          263         struct passwd *pw;
          264 
          265         pw = getpwuid(getuid());
          266         if(pw == nil)
          267                 return nil;
          268         return strdup(pw->pw_name);
          269 }
          270 
          271 /*
          272  * Initial config.
          273  */
          274 void
          275 confinit(void)
          276 {
          277         int i;
          278 
          279         conf.npage = 0;
          280         for(i=0; i<nelem(conf.mem); i++)
          281                 conf.npage += conf.mem[i].npage;
          282         conf.upages = conf.npage;
          283         conf.nproc = 100 + ((conf.npage*BY2PG)/MB)*5;
          284         if(conf.nproc > 2000)
          285                 conf.nproc = 2000;
          286         conf.nimage = 200;
          287         conf.nswap = 0;
          288         conf.nswppo = 0;
          289         conf.ialloc = 1<<20;
          290 }
          291 
          292 static uchar *sp;        /* user stack of init proc */
          293 static void init0(void);
          294 
          295 /*
          296  * Set up first process.
          297  */
          298 void
          299 userinit(void)
          300 {
          301         void *v;
          302         Proc *p;
          303         Segment *s;
          304         Page *pg;
          305 
          306         p = newproc();
          307         p->pgrp = newpgrp();
          308         p->egrp = smalloc(sizeof(Egrp));
          309         p->egrp->ref.ref = 1;
          310         p->fgrp = dupfgrp(nil);
          311         p->rgrp = newrgrp();
          312         p->procmode = 0640;
          313 
          314         kstrdup(&eve, username);
          315         kstrdup(&p->text, "*init*");
          316         kstrdup(&p->user, eve);
          317 
          318         p->fpstate = FPinit;
          319         fpoff();
          320 
          321         /*
          322          * Kernel Stack
          323          *
          324          * N.B. make sure there's enough space for syscall to check
          325          *        for valid args and 
          326          *        4 bytes for gotolabel's return PC
          327          */
          328         labelinit(&p->sched, (ulong)init0, (ulong)p->kstack+KSTACK-(sizeof(Sargs)+BY2WD));
          329 
          330         /*
          331          * User Stack
          332          *
          333          * N.B. cannot call newpage() with clear=1, because pc kmap
          334          * requires up != nil.  use tmpmap instead.
          335          */
          336         s = newseg(SG_STACK, USTKTOP-USTKSIZE, USTKSIZE/BY2PG);
          337         p->seg[SSEG] = s;
          338         pg = newpage(0, 0, USTKTOP-BY2PG);
          339         v = tmpmap(pg);
          340         memset(v, 0, BY2PG);
          341         segpage(s, pg);
          342         bootargs(v);
          343         tmpunmap(v);
          344 
          345         /*
          346          * Text
          347          */
          348         s = newseg(SG_TEXT, UTZERO, 1);
          349         s->flushme++;
          350         p->seg[TSEG] = s;
          351         pg = newpage(0, 0, UTZERO);
          352         segpage(s, pg);
          353         v = tmpmap(pg);
          354         memset(v, 0, BY2PG);
          355         memmove(v, initcode, sizeof initcode);
          356         tmpunmap(v);
          357 
          358         ready(p);
          359 }
          360 
          361 static uchar*
          362 pusharg(char *p)
          363 {
          364         int n;
          365 
          366         n = strlen(p)+1;
          367         sp -= n;
          368         memmove(sp, p, n);
          369         return sp;
          370 }
          371 
          372 void
          373 bootargs(void *base)
          374 {
          375          int i, ac;
          376         uchar *av[32];
          377         uint32 *lsp;
          378 
          379         sp = (uchar*)base + BY2PG - MAXSYSARG*BY2WD - sizeof(Tos);
          380 
          381         ac = 0;
          382         av[ac++] = pusharg("9vx");
          383         for(i = 0; i < bootargc && ac < 32; i++)
          384                 av[ac++] = pusharg(bootargv[i]);
          385         if(i == 0)
          386                 av[ac++] = pusharg(BOOTARG);
          387 
          388         /* 4 byte word align stack */
          389         sp = (uchar*)((uintptr)sp & ~3);
          390 
          391         /* build argc, argv on stack */
          392         sp -= (ac+2)*sizeof(uint32);
          393         lsp = (uint32*)sp;
          394         *lsp++ = ac;
          395         for(i = 0; i < ac; i++)
          396                 *lsp++ = (uint32)(uintptr)(av[i] + ((USTKTOP - BY2PG) - (ulong)base));
          397         *lsp = 0;
          398         sp += (USTKTOP - BY2PG) - (ulong)base;
          399 }
          400 
          401 void
          402 showexec(ulong sp)
          403 {
          404         uint32 *a, *argv;
          405         int i, n;
          406         uchar *uzero;
          407         
          408         uzero = up->pmmu.uzero;
          409         iprint("showexec %p\n", (uintptr)sp);
          410         if(sp >= USTKTOP || sp < USTKTOP-USTKSIZE)
          411                 panic("showexec: bad sp");
          412         a = (uint32*)(uzero + sp);
          413         n = *a++;
          414         iprint("argc=%d\n", n);
          415         argv = a;
          416         iprint("argv=%p\n", argv);
          417         for(i=0; i<n; i++){
          418                 iprint("argv[%d]=%p\n", i, (uintptr)argv[i]);
          419                 iprint("\t%s\n", (uzero + argv[i]));
          420         }
          421         iprint("argv[%d]=%p\n", i, argv[i]);
          422 }
          423 
          424 
          425 /*
          426  * First process starts executing, with up set, here.
          427  */
          428 static void
          429 init0(void)
          430 {
          431         char buf[2*KNAMELEN];
          432 
          433         up->nerrlab = 0;
          434         if(waserror())
          435                 panic("init0: %r");
          436 
          437         spllo();
          438 
          439         /*
          440          * These are o.k. because rootinit is null.
          441          * Then early kproc's will have a root and dot.
          442          */
          443         up->slash = namec("#/", Atodir, 0, 0);
          444         pathclose(up->slash->path);
          445         up->slash->path = newpath("/");
          446         up->dot = cclone(up->slash);
          447 
          448         chandevinit();
          449 
          450         /* set up environment */
          451         snprint(buf, sizeof(buf), "%s %s", "vx32" /*arch->id*/, conffile);
          452         ksetenv("terminal", buf, 0);
          453         ksetenv("cputype", "386", 0);
          454         ksetenv("rootdir", "/root", 0);
          455         ksetenv("service", "terminal", 0);
          456         ksetenv("sysname", "vx32", 0);
          457 //        ksetenv("init", "/386/init -t", 0);
          458         ksetenv("user", username, 0);
          459         setinienv();
          460 
          461         poperror();
          462 
          463 //showexec(sp);
          464         touser(sp);        /* infinity, and beyond. */
          465 }
          466 
          467 int invx32;        /* shared with sbcl-signal.c */
          468 
          469 /*
          470  * SIGSEGV handler.  If we get SIGSEGV while executing
          471  * in the kernel on behalf of user code, then we call fault
          472  * to map in the missing page, just as we would on a MIPS
          473  * or any other architecture with a software-managed TLB.
          474  */
          475 void
          476 sigsegv(int signo, siginfo_t *info, void *v)
          477 {
          478         int read;
          479         ulong addr, eip, esp;
          480         ucontext_t *uc;
          481         uchar *uzero;
          482 
          483         if(m == nil)
          484                 panic("sigsegv: m == nil");
          485         if(m->machno != 0)
          486                 panic("sigsegv on cpu%d", m->machno);
          487         if(up == nil)
          488                 panic("sigsegv: up == nil");
          489 
          490         uzero = up->pmmu.uzero;
          491 
          492         uc = v;
          493 #if defined(__APPLE__)
          494         mcontext_t mc;
          495         mc = uc->uc_mcontext;
          496         addr = (ulong)info->si_addr;
          497         read = !(mc->es.err&2);
          498         eip = mc->ss.eip;
          499         esp = mc->ss.esp;
          500 #elif defined(__linux__)
          501         mcontext_t *mc;
          502         struct sigcontext *ctx;
          503         mc = &uc->uc_mcontext;
          504         ctx = (struct sigcontext*)mc;
          505         addr = (ulong)info->si_addr;
          506         read = !(ctx->err&2);
          507 #ifdef i386
          508         eip = ctx->eip;
          509         esp = ctx->esp;
          510 #else
          511         eip = ctx->rip;
          512         esp = ctx->rsp;
          513 #endif
          514 #elif defined(__FreeBSD__)
          515         mcontext_t *mc;
          516         mc = &uc->uc_mcontext;
          517 #ifdef __i386__
          518         eip = mc->mc_eip;
          519         esp = mc->mc_esp;
          520 #elif defined(__amd64__)
          521         eip = mc->mc_rip;
          522         esp = mc->mc_rsp;
          523 #endif
          524         addr = (ulong)info->si_addr;
          525         if(__FreeBSD__ < 7){
          526                 /*
          527                  * FreeBSD /usr/src/sys/i386/i386/trap.c kludgily reuses
          528                  * frame->tf_err as somewhere to put the faulting address
          529                  * (cr2) when calling into the generic signal dispatcher.
          530                  * Unfortunately, that means that the bit in tf_err that says
          531                  * whether this is a read or write fault is irretrievably gone.
          532                  * So we have to figure it out.  Let's assume that if the page
          533                  * is already mapped in core, it is a write fault.  If not, it is a
          534                  * read fault.  
          535                  *
          536                  * This is apparently fixed in FreeBSD 7, but I don't have any
          537                  * FreeBSD 7 machines on which to verify this.
          538                  */
          539                 char vec;
          540                 int r;
          541 
          542                 vec = 0;
          543                 r = mincore((void*)addr, 1, &vec);
          544 //iprint("FreeBSD fault [%d]: addr=%p[%p] mincore=%d vec=%#x errno=%d\n", signo, addr, (uchar*)addr-uzero, r, vec, errno);
          545                 if(r < 0 || vec == 0)
          546                         mc->mc_err = 0;        /* read fault */
          547                 else
          548                         mc->mc_err = 2;        /* write fault */
          549         }
          550         read = !(mc->mc_err&2);
          551 #else
          552 #        error        "Unknown OS in sigsegv"
          553 #endif
          554 
          555         if(0)
          556                 iprint("cpu%d: %ld %s sigsegv [stack=%p eip=%p esp=%p addr=%p[%p] %d]\n",
          557                         m->machno, up ? up->pid : 0, up ? up->text : nil,
          558                         &signo, eip, esp, addr, (uchar*)addr-uzero, read);
          559 
          560         /*
          561          * In vx32?  It better handle it.
          562          */
          563         if(invx32){
          564                 if(vx32_sighandler(signo, info, v))
          565                         return;
          566                 panic("user fault: signo=%d addr=%p [useraddr=%p] read=%d eip=%p esp=%p",
          567                         signo, addr, (uchar*)addr-uzero, read, eip, esp);
          568         }
          569 
          570         /*
          571          * Otherwise, invoke the Plan 9 fault handler.
          572          * This means we must have been executing in the "kernel",
          573          * not user space code.  If the fault can't be fixed,
          574          * we screwed up.
          575          */
          576         if(!isuaddr((uchar*)addr) || fault((uchar*)addr - uzero, read) < 0)
          577                 panic("kernel fault: signo=%d addr=%p[%p] %d eip=%p esp=%p", signo, addr, (uchar*)addr-uzero, read, eip, esp);
          578 }
          579 
          580 /*
          581  * No-op handler for SIGUSR1 and SIGURG.
          582  */
          583 static void
          584 signop(int signo, siginfo_t *info, void *v)
          585 {
          586 }
          587 
          588 #ifdef TLS
          589 /* __thread means thread-local */
          590 __thread Mach *m;
          591 __thread Proc *up;
          592 #else
          593 static pthread_key_t machkey;
          594 
          595 static void
          596 machkeyinit(void)
          597 {
          598         if(pthread_key_create(&machkey, nil) < 0)
          599                 panic("pthread_key_create: %s", strerror(errno));
          600         pthread_setspecific(machkey, machp[0]);
          601 }
          602 
          603 Mach*
          604 getmach(void)
          605 {
          606         return pthread_getspecific(machkey);
          607 }
          608 
          609 void
          610 setmach(Mach *xm)
          611 {
          612         if(pthread_setspecific(machkey, xm) < 0)
          613                 panic("pthread_setspecific: %s", strerror(errno));
          614 }
          615 #endif
          616 
          617 Mach *machp[MAXMACH] = { &mach0 };
          618 
          619 /*
          620  * We use one signal handler for SIGSEGV, which can happen
          621  * both during kernel execution and during vx32 execution,
          622  * but we only want to run on an alternate stack during the latter.
          623  * The fact that we the signal handler flags are not per-pthread
          624  * is one thing that keeps us from running parallel vx32 instances.
          625  */
          626 void
          627 setsigsegv(int vx32)
          628 {
          629         int flags;
          630         struct sigaction act;
          631         stack_t ss;
          632         
          633         // Paranoia: better not be on signal stack.
          634         // Could disable if this is too expensive.
          635         if (sigaltstack(NULL, &ss) >= 0){
          636                 if(ss.ss_flags & SS_ONSTACK)
          637                         panic("setsigsegv on signal stack");
          638                 if(vx32 && (ss.ss_flags & SS_DISABLE))
          639                         panic("setsigsegv vx32 without alt stack");
          640         }
          641 
          642         invx32 = vx32;
          643         flags = SA_SIGINFO;
          644         if(vx32)
          645                 flags |= SA_ONSTACK|SA_NODEFER;        /* run on vx32 alternate stack */
          646         else
          647                 flags |= SA_RESTART|SA_NODEFER;        /* allow recursive faults */
          648         memset(&act, 0, sizeof act);
          649         act.sa_sigaction = sigsegv;
          650         act.sa_flags = flags;
          651         sigaction(SIGSEGV, &act, nil);
          652         sigaction(SIGBUS, &act, nil);
          653 }
          654 
          655 /*
          656  * Boot-time config of processor 0.
          657  */
          658 void
          659 mach0init(void)
          660 {
          661         conf.nmach = 1;
          662         machinit();        /* common per-processor init */
          663         active.machs = 1;
          664         active.exiting = 0;
          665 }
          666 
          667 static void
          668 siginit(void)
          669 {
          670         struct sigaction act;
          671 
          672         /* Install vx32signal handlers ... */
          673         vx32_siginit();
          674         
          675         /* ... and then our own */
          676         setsigsegv(0);
          677 
          678         memset(&act, 0, sizeof act);
          679         act.sa_sigaction = signop;
          680         act.sa_flags = SA_SIGINFO;
          681         sigaction(SIGUSR1, &act, nil);
          682         sigaction(SIGURG, &act, nil);
          683 }
          684 
          685 void
          686 machinit(void)
          687 {
          688         sigset_t sigs;
          689         
          690         m->perf.period = 1;        /* devcons divides by this */
          691 
          692         /* Block SIGURG except when in timer kproc */
          693         sigemptyset(&sigs);
          694         sigaddset(&sigs, SIGURG);
          695         pthread_sigmask(SIG_BLOCK, &sigs, nil);
          696 
          697 }
          698 
          699 void*
          700 squidboy(void *v)
          701 {
          702 //        iprint("Hello Squidboy\n");
          703 
          704         setmach(v);
          705         machinit();
          706         lock(&active.lk);
          707         active.machs |= 1<<m->machno;
          708         unlock(&active.lk);
          709         schedinit();        /* never returns */
          710         return 0;
          711 }
          712 
          713 /*
          714  * Allocate a new processor, just like that.
          715  */
          716 void
          717 newmach(void)
          718 {
          719         int i;
          720         Mach *mm;
          721         pthread_t pid;
          722 
          723         if(singlethread)
          724                 return;
          725 
          726         i = conf.nmach;
          727         if(i >= MAXMACH)
          728                 panic("out of processors");
          729         mm = mallocz(sizeof *mm, 1);
          730         mm->machno = i;
          731         mm->new = 1;
          732         machp[i] = mm;
          733         conf.nmach++;
          734         
          735         if(pthread_create(&pid, 0, squidboy, mm) < 0)
          736                 panic("pthread_create");
          737 }