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