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 }