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 }