vx32

Local 9vx git repository for patches.
git clone git://r-36.net/vx32
Log | Files | 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 }