]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/xen/main.c
merge
[plan9front.git] / sys / src / 9 / xen / main.c
1 #include        "u.h"
2 #include        "../port/lib.h"
3 #include        "mem.h"
4 #include        "dat.h"
5 #include        "fns.h"
6 #include        "io.h"
7 #include        "ureg.h"
8 #include        "init.h"
9 #include        "pool.h"
10 #include        "reboot.h"
11 #include        <tos.h>
12
13 Mach *m;
14
15 #define BOOTARGS        (xenstart->cmd_line)
16 #define BOOTARGSLEN     (sizeof xenstart->cmd_line)
17 #define MAXCONF         64
18
19 enum {
20         /* space for syscall args, return PC, top-of-stack struct */
21         Ustkheadroom    = sizeof(Sargs) + sizeof(uintptr) + sizeof(Tos),
22 };
23
24 Conf conf;
25 char *confname[MAXCONF];
26 char *confval[MAXCONF];
27 int nconf;
28 uchar *sp;      /* user stack of init proc */
29 int idle_spin;
30
31 static void
32 options(void)
33 {
34         long i, n;
35         char *cp, *line[MAXCONF], *p, *q;
36
37         /*
38          *  parse configuration args from dos file plan9.ini
39          */
40         cp = BOOTARGS;  /* where b.com leaves its config */
41         cp[BOOTARGSLEN-1] = 0;
42
43         /*
44          * Strip out '\r', change '\t' -> ' '.
45          */
46         p = cp;
47         for(q = cp; *q; q++){
48                 if(*q == '\r')
49                         continue;
50                 if(*q == '\t')
51                         *q = ' ';
52                 *p++ = *q;
53         }
54         *p = 0;
55
56         n = getfields(cp, line, MAXCONF, 1, "\n");
57         for(i = 0; i < n; i++){
58                 if(*line[i] == '#')
59                         continue;
60                 cp = strchr(line[i], '=');
61                 if(cp == nil)
62                         continue;
63                 *cp++ = '\0';
64                 confname[nconf] = line[i];
65                 confval[nconf] = cp;
66                 nconf++;
67         }
68 }
69
70 void
71 main(void)
72 {
73         mach0init();
74         options();
75         ioinit();
76         xenconsinit();
77         quotefmtinstall();
78
79         //consdebug = rdb;
80         print("\nPlan 9 (%s)\n", xenstart->magic);
81
82         cpuidentify();
83         // meminit() is not for us
84         confinit();
85         archinit();
86         xinit();
87         trapinit();
88         printinit();
89         cpuidprint();
90         mmuinit();
91         if(arch->intrinit)      /* launches other processors on an mp */
92                 arch->intrinit();
93         timersinit();
94         mathinit();
95         kbdenable();
96         xengrantinit();
97         if(arch->clockenable)
98                 arch->clockenable();
99         procinit0();
100         initseg();
101
102         links();
103 //      conf.monitor = 1;
104         chandevreset();
105         pageinit();
106
107         swapinit();
108         userinit();
109         schedinit();
110 }
111
112 void
113 mach0init(void)
114 {
115         m = (Mach*)MACHADDR;
116         m->machno = 0;
117         conf.nmach = 1;
118         MACHP(0) = (Mach*)CPU0MACH;
119         m->pdb = (ulong*)xenstart->pt_base;
120
121         machinit();
122
123         active.machs[0] = 1;
124         active.exiting = 0;
125 }
126
127 void
128 machinit(void)
129 {
130         int machno;
131         ulong *pdb;
132
133         machno = m->machno;
134         pdb = m->pdb;
135         memset(m, 0, sizeof(Mach));
136         m->machno = machno;
137         m->pdb = pdb;
138         m->perf.period = 1;
139
140         /*
141          * For polled uart output at boot, need
142          * a default delay constant. 100000 should
143          * be enough for a while. Cpuidentify will
144          * calculate the real value later.
145          */
146         m->loopconst = 100000;
147         m->cpumhz = 1000;                               // XXX! 
148
149         HYPERVISOR_shared_info = (shared_info_t*)mmumapframe(XENSHARED, (xenstart->shared_info)>>PGSHIFT);
150         
151         // XXX m->shared = &HYPERVISOR_shared_info->vcpu_data[m->machno];
152 }
153
154 void
155 init0(void)
156 {
157         int i;
158         char buf[2*KNAMELEN];
159
160         up->nerrlab = 0;
161
162         spllo();
163
164         /*
165          * These are o.k. because rootinit is null.
166          * Then early kproc's will have a root and dot.
167          */
168         up->slash = namec("#/", Atodir, 0, 0);
169         pathclose(up->slash->path);
170         up->slash->path = newpath("/");
171         up->dot = cclone(up->slash);
172
173         chandevinit();
174
175         if(!waserror()){
176                 snprint(buf, sizeof(buf), "%s %s", arch->id, conffile);
177                 ksetenv("terminal", buf, 0);
178                 ksetenv("cputype", "386", 0);
179                 if(cpuserver)
180                         ksetenv("service", "cpu", 0);
181                 else
182                         ksetenv("service", "terminal", 0);
183                 ksetenv("readparts", "1", 0);
184                 for(i = 0; i < nconf; i++){
185                         if(confname[i][0] != '*')
186                                 ksetenv(confname[i], confval[i], 0);
187                         ksetenv(confname[i], confval[i], 1);
188                 }
189                 poperror();
190         }
191
192         kproc("alarm", alarmkproc, 0);
193         touser(sp);
194 }
195
196 void
197 userinit(void)
198 {
199         Proc *p;
200         Segment *s;
201         KMap *k;
202         Page *pg;
203
204         p = newproc();
205         p->pgrp = newpgrp();
206         p->egrp = smalloc(sizeof(Egrp));
207         p->egrp->ref = 1;
208         p->fgrp = dupfgrp(nil);
209         p->rgrp = newrgrp();
210         p->procmode = 0640;
211
212         kstrdup(&eve, "");
213         kstrdup(&p->text, "*init*");
214         kstrdup(&p->user, eve);
215
216         p->fpstate = FPinit;
217         fpoff();
218
219         /*
220          * Kernel Stack
221          *
222          * N.B. make sure there's enough space for syscall to check
223          *      for valid args and 
224          *      4 bytes for gotolabel's return PC
225          */
226         p->sched.pc = (ulong)init0;
227         p->sched.sp = (ulong)p->kstack+KSTACK-(sizeof(Sargs)+BY2WD);
228
229         /*
230          * User Stack
231          */
232         s = newseg(SG_STACK, USTKTOP-USTKSIZE, USTKSIZE/BY2PG);
233         p->seg[SSEG] = s;
234         pg = newpage(1, 0, USTKTOP-BY2PG);
235         segpage(s, pg);
236         k = kmap(pg);
237         bootargs(VA(k));
238         kunmap(k);
239
240         /*
241          * Text
242          */
243         s = newseg(SG_TEXT, UTZERO, 1);
244         s->flushme++;
245         p->seg[TSEG] = s;
246         pg = newpage(1, 0, UTZERO);
247         pg->txtflush = ~0;
248         segpage(s, pg);
249         k = kmap(s->map[0]->pages[0]);
250         memmove((ulong*)VA(k), initcode, sizeof initcode);
251         kunmap(k);
252         ready(p);
253 }
254
255 uchar *
256 pusharg(char *p)
257 {
258         int n;
259
260         n = strlen(p)+1;
261         sp -= n;
262         memmove(sp, p, n);
263         return sp;
264 }
265
266 void
267 bootargs(ulong base)
268 {
269         int i, ac;
270         uchar *av[32];
271         uchar **lsp;
272
273         sp = (uchar*)base + BY2PG - Ustkheadroom;
274
275         ac = 0;
276         av[ac++] = pusharg("boot");
277         av[ac++] = pusharg("-D");
278
279         /* 4 byte word align stack */
280         sp = (uchar*)((ulong)sp & ~3);
281
282         /* build argc, argv on stack */
283         sp -= (ac+1)*sizeof(sp);
284         lsp = (uchar**)sp;
285         for(i = 0; i < ac; i++)
286                 *lsp++ = av[i] + ((USTKTOP - BY2PG) - base);
287         *lsp = 0;
288         sp += (USTKTOP - BY2PG) - base - sizeof(ulong);
289 }
290
291 char*
292 getconf(char *name)
293 {
294         int i;
295
296         for(i = 0; i < nconf; i++)
297                 if(cistrcmp(confname[i], name) == 0)
298                         return confval[i];
299         return 0;
300 }
301
302 static void
303 writeconf(void)
304 {
305         char *p, *q;
306         int n;
307
308         p = getconfenv();
309
310         if(waserror()) {
311                 free(p);
312                 nexterror();
313         }
314
315         /* convert to name=value\n format */
316         for(q=p; *q; q++) {
317                 q += strlen(q);
318                 *q = '=';
319                 q += strlen(q);
320                 *q = '\n';
321         }
322         n = q - p + 1;
323         if(n >= BOOTARGSLEN)
324                 error("kernel configuration too large");
325         memmove(BOOTARGS, p, n);
326         poperror();
327         free(p);
328 }
329
330 void
331 confinit(void)
332 {
333         char *p;
334         int i, userpcnt;
335         ulong kpages;
336
337         for(i = 0; i < nconf; i++)
338                 print("%s=%s\n", confname[i], confval[i]);
339         /* 
340          * all ram above xentop is free, but must be mappable
341          * to virt addrs less than VIRT_START.
342          */
343         kpages = PADDR(hypervisor_virt_start)>>PGSHIFT;
344         if(xenstart->nr_pages <= kpages)
345                 kpages = xenstart->nr_pages;
346         else
347                 print("Warning: Plan 9 / Xen limitation - "
348                           "using only %lud of %lud available RAM pages\n",
349                           kpages, xenstart->nr_pages);
350         xentop = PGROUND(PADDR(xentop));
351         conf.mem[0].npage = kpages - (xentop>>PGSHIFT);
352         conf.mem[0].base = xentop;
353
354         if(p = getconf("*kernelpercent"))
355                 userpcnt = 100 - strtol(p, 0, 0);
356         else
357                 userpcnt = 0;
358
359         conf.npage = 0;
360         for(i=0; i<nelem(conf.mem); i++)
361                 conf.npage += conf.mem[i].npage;
362
363         conf.nproc = 100 + ((conf.npage*BY2PG)/MB)*5;
364         if(cpuserver)
365                 conf.nproc *= 3;
366         if(conf.nproc > 2000)
367                 conf.nproc = 2000;
368         conf.nimage = 200;
369         conf.nswap = conf.nproc*80;
370         conf.nswppo = 4096;
371
372         if(cpuserver) {
373                 if(userpcnt < 10)
374                         userpcnt = 70;
375                 kpages = conf.npage - (conf.npage*userpcnt)/100;
376
377                 /*
378                  * Hack for the big boys. Only good while physmem < 4GB.
379                  * Give the kernel fixed max + enough to allocate the
380                  * page pool.
381                  * This is an overestimate as conf.upages < conf.npages.
382                  * The patch of nimage is a band-aid, scanning the whole
383                  * page list in imagereclaim just takes too long.
384                  */
385                 if(kpages > (64*MB + conf.npage*sizeof(Page))/BY2PG){
386                         kpages = (64*MB + conf.npage*sizeof(Page))/BY2PG;
387                         conf.nimage = 2000;
388                         kpages += (conf.nproc*KSTACK)/BY2PG;
389                 }
390         } else {
391                 if(userpcnt < 10) {
392                         if(conf.npage*BY2PG < 16*MB)
393                                 userpcnt = 40;
394                         else
395                                 userpcnt = 60;
396                 }
397                 kpages = conf.npage - (conf.npage*userpcnt)/100;
398
399                 /*
400                  * Make sure terminals with low memory get at least
401                  * 4MB on the first Image chunk allocation.
402                  */
403                 if(conf.npage*BY2PG < 16*MB)
404                         imagmem->minarena = 4*1024*1024;
405         }
406
407         /*
408          * can't go past the end of virtual memory
409          * (ulong)-KZERO is 2^32 - KZERO
410          */
411         if(kpages > ((ulong)-KZERO)/BY2PG)
412                 kpages = ((ulong)-KZERO)/BY2PG;
413
414         conf.upages = conf.npage - kpages;
415         conf.ialloc = (kpages/2)*BY2PG;
416
417         /*
418          * Guess how much is taken by the large permanent
419          * datastructures. Mntcache and Mntrpc are not accounted for.
420          */
421         kpages *= BY2PG;
422         kpages -= conf.upages*sizeof(Page)
423                 + conf.nproc*sizeof(Proc)
424                 + conf.nimage*sizeof(Image)
425                 + conf.nswap
426                 + conf.nswppo*sizeof(Page*);
427         mainmem->maxsize = kpages;
428         if(!cpuserver){
429                 /*
430                  * give terminals lots of image memory, too; the dynamic
431                  * allocation will balance the load properly, hopefully.
432                  * be careful with 32-bit overflow.
433                  */
434                 imagmem->maxsize = kpages;
435         }
436 }
437
438 static char* mathmsg[] =
439 {
440         nil,    /* handled below */
441         "denormalized operand",
442         "division by zero",
443         "numeric overflow",
444         "numeric underflow",
445         "precision loss",
446 };
447
448 static void
449 mathnote(void)
450 {
451         int i;
452         ulong status;
453         char *msg, note[ERRMAX];
454
455         status = up->fpsave.status;
456
457         /*
458          * Some attention should probably be paid here to the
459          * exception masks and error summary.
460          */
461         msg = "unknown exception";
462         for(i = 1; i <= 5; i++){
463                 if(!((1<<i) & status))
464                         continue;
465                 msg = mathmsg[i];
466                 break;
467         }
468         if(status & 0x01){
469                 if(status & 0x40){
470                         if(status & 0x200)
471                                 msg = "stack overflow";
472                         else
473                                 msg = "stack underflow";
474                 }else
475                         msg = "invalid operation";
476         }
477         snprint(note, sizeof note, "sys: fp: %s fppc=0x%lux status=0x%lux",
478                 msg, up->fpsave.pc, status);
479         postnote(up, 1, note, NDebug);
480 }
481
482 /*
483  *  math coprocessor error
484  */
485 static void
486 matherror(Ureg *ur, void*)
487 {
488         /*
489          *  a write cycle to port 0xF0 clears the interrupt latch attached
490          *  to the error# line from the 387
491          */
492         if(!(m->cpuiddx & 0x01))
493                 outb(0xF0, 0xFF);
494
495         /*
496          *  save floating point state to check out error
497          */
498         fpenv(&up->fpsave);
499         mathnote();
500
501         if(ur->pc & KZERO)
502                 panic("fp: status %ux fppc=0x%lux pc=0x%lux",
503                         up->fpsave.status, up->fpsave.pc, ur->pc);
504 }
505
506 /*
507  *  math coprocessor emulation fault
508  */
509 static void
510 mathemu(Ureg *ureg, void*)
511 {
512         if(up->fpstate & FPillegal){
513                 /* someone did floating point in a note handler */
514                 postnote(up, 1, "sys: floating point in note handler", NDebug);
515                 return;
516         }
517         switch(up->fpstate){
518         case FPinit:
519                 fpinit();
520                 up->fpstate = FPactive;
521                 break;
522         case FPinactive:
523                 /*
524                  * Before restoring the state, check for any pending
525                  * exceptions, there's no way to restore the state without
526                  * generating an unmasked exception.
527                  * More attention should probably be paid here to the
528                  * exception masks and error summary.
529                  */
530                 if((up->fpsave.status & ~up->fpsave.control) & 0x07F){
531                         mathnote();
532                         break;
533                 }
534                 fprestore(&up->fpsave);
535                 up->fpstate = FPactive;
536                 break;
537         case FPactive:
538                 panic("math emu pid %ld %s pc 0x%lux", 
539                         up->pid, up->text, ureg->pc);
540                 break;
541         }
542 }
543
544 /*
545  *  math coprocessor segment overrun
546  */
547 static void
548 mathover(Ureg*, void*)
549 {
550         pexit("math overrun", 0);
551 }
552
553 void
554 mathinit(void)
555 {
556         trapenable(VectorCERR, matherror, 0, "matherror");
557         //if(X86FAMILY(m->cpuidax) == 3)
558         //      intrenable(IrqIRQ13, matherror, 0, BUSUNKNOWN, "matherror");
559         trapenable(VectorCNA, mathemu, 0, "mathemu");
560         trapenable(VectorCSO, mathover, 0, "mathover");
561 }
562
563 /*
564  *  set up floating point for a new process
565  */
566 void
567 procsetup(Proc*p)
568 {
569         p->fpstate = FPinit;
570         fpoff();
571 }
572
573 void
574 procfork(Proc *p)
575 {
576         int s;
577
578         p->kentry = up->kentry;
579         p->pcycles = -p->kentry;
580
581         /* save floating point state */
582         s = splhi();
583         switch(up->fpstate & ~FPillegal){
584         case FPactive:
585                 fpsave(&up->fpsave);
586                 up->fpstate = FPinactive;
587         case FPinactive:
588                 p->fpsave = up->fpsave;
589                 p->fpstate = FPinactive;
590         }
591         splx(s);
592 }
593
594 void
595 procrestore(Proc *p)
596 {
597         uvlong t;
598
599         if(p->kp)
600                 return;
601         cycles(&t);
602         p->pcycles -= t;
603 }
604
605 /*
606  *  Save the mach dependent part of the process state.
607  */
608 void
609 procsave(Proc *p)
610 {
611         uvlong t;
612
613         cycles(&t);
614         p->pcycles += t;
615         if(p->fpstate == FPactive){
616                 if(p->state == Moribund)
617                         fpclear();
618                 else{
619                         /*
620                          * Fpsave() stores without handling pending
621                          * unmasked exeptions. Postnote() can't be called
622                          * here as sleep() already has up->rlock, so
623                          * the handling of pending exceptions is delayed
624                          * until the process runs again and generates an
625                          * emulation fault to activate the FPU.
626                          */
627                         fpsave(&p->fpsave);
628                 }
629                 p->fpstate = FPinactive;
630         }
631
632         /*
633          * While this processor is in the scheduler, the process could run
634          * on another processor and exit, returning the page tables to
635          * the free list where they could be reallocated and overwritten.
636          * When this processor eventually has to get an entry from the
637          * trashed page tables it will crash.
638          *
639          * If there's only one processor, this can't happen.
640          * You might think it would be a win not to do this in that case,
641          * especially on VMware, but it turns out not to matter.
642          */
643         mmuflushtlb(0);
644 }
645
646 void
647 reboot(void *entry, void *code, ulong size)
648 {
649         void (*f)(ulong, ulong, ulong);
650
651         writeconf();
652         cpushutdown();
653
654         splhi();
655
656         /* turn off buffered serial console */
657         serialoq = nil;
658
659         /* shutdown devices */
660         chandevshutdown();
661
662         /* reboot(0, ...) on Xen causes domU shutdown */
663         if(entry == 0)
664                 HYPERVISOR_shutdown(0);
665
666         mmuflushtlb(0);
667
668         /* setup reboot trampoline function */
669         f = (void*)REBOOTADDR;
670         memmove(f, rebootcode, sizeof(rebootcode));
671
672         /* off we go - never to return */
673         (*f)(PADDR(entry), PADDR(code), size);
674 }
675
676 void
677 exit(int)
678 {
679         cpushutdown();
680         arch->reset();
681 }