]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/main.c
devip: cleanup rudp.c
[plan9front.git] / sys / src / 9 / pc / 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        "tos.h"
8 #include        "ureg.h"
9 #include        "init.h"
10 #include        "pool.h"
11 #include        "reboot.h"
12
13 Mach *m;
14 Conf conf;
15
16 int delaylink;
17 int idle_spin;
18
19 extern void (*i8237alloc)(void);
20 extern void bootscreeninit(void);
21 extern void multibootdebug(void);
22
23 void
24 main(void)
25 {
26         mach0init();
27         bootargsinit();
28         ioinit();
29         i8250console();
30         quotefmtinstall();
31         screeninit();
32
33         print("\nPlan 9\n");
34         
35         trapinit0();
36         i8253init();
37         cpuidentify();
38         meminit();
39         confinit();
40         xinit();
41         archinit();
42         bootscreeninit();
43         if(i8237alloc != nil)
44                 i8237alloc();
45         trapinit();
46         printinit();
47         cpuidprint();
48         mmuinit();
49         if(arch->intrinit)      /* launches other processors on an mp */
50                 arch->intrinit();
51         timersinit();
52         mathinit();
53         if(arch->clockenable)
54                 arch->clockenable();
55         procinit0();
56         initseg();
57         if(delaylink){
58                 bootlinks();
59                 pcimatch(0, 0, 0);
60         }else
61                 links();
62         chandevreset();
63         pageinit();
64         userinit();
65         schedinit();
66 }
67
68 void
69 mach0init(void)
70 {
71         conf.nmach = 1;
72         MACHP(0) = (Mach*)CPU0MACH;
73         m->pdb = (ulong*)CPU0PDB;
74         m->gdt = (Segdesc*)CPU0GDT;
75
76         machinit();
77
78         active.machs[0] = 1;
79         active.exiting = 0;
80 }
81
82 void
83 machinit(void)
84 {
85         int machno;
86         ulong *pdb;
87         Segdesc *gdt;
88
89         machno = m->machno;
90         pdb = m->pdb;
91         gdt = m->gdt;
92         memset(m, 0, sizeof(Mach));
93         m->machno = machno;
94         m->pdb = pdb;
95         m->gdt = gdt;
96         m->perf.period = 1;
97
98         /*
99          * For polled uart output at boot, need
100          * a default delay constant. 100000 should
101          * be enough for a while. Cpuidentify will
102          * calculate the real value later.
103          */
104         m->loopconst = 100000;
105 }
106
107 void
108 init0(void)
109 {
110         char buf[2*KNAMELEN], **sp;
111
112         up->nerrlab = 0;
113
114         spllo();
115
116         /*
117          * These are o.k. because rootinit is null.
118          * Then early kproc's will have a root and dot.
119          */
120         up->slash = namec("#/", Atodir, 0, 0);
121         pathclose(up->slash->path);
122         up->slash->path = newpath("/");
123         up->dot = cclone(up->slash);
124
125         chandevinit();
126
127         if(!waserror()){
128                 snprint(buf, sizeof(buf), "%s %s", arch->id, conffile);
129                 ksetenv("terminal", buf, 0);
130                 ksetenv("cputype", "386", 0);
131                 if(cpuserver)
132                         ksetenv("service", "cpu", 0);
133                 else
134                         ksetenv("service", "terminal", 0);
135                 setconfenv();
136                 poperror();
137         }
138         kproc("alarm", alarmkproc, 0);
139
140         sp = (char**)(USTKTOP - sizeof(Tos) - 8 - sizeof(sp[0])*4);
141         sp[3] = sp[2] = nil;
142         strcpy(sp[1] = (char*)&sp[4], "boot");
143         sp[0] = nil;
144         touser(sp);
145 }
146
147 void
148 userinit(void)
149 {
150         void *v;
151         Proc *p;
152         Segment *s;
153         Page *pg;
154
155         p = newproc();
156         p->pgrp = newpgrp();
157         p->egrp = smalloc(sizeof(Egrp));
158         p->egrp->ref = 1;
159         p->fgrp = dupfgrp(nil);
160         p->rgrp = newrgrp();
161         p->procmode = 0640;
162
163         kstrdup(&eve, "");
164         kstrdup(&p->text, "*init*");
165         kstrdup(&p->user, eve);
166
167         procsetup(p);
168
169         /*
170          * Kernel Stack
171          *
172          * N.B. make sure there's enough space for syscall to check
173          *      for valid args and 
174          *      4 bytes for gotolabel's return PC
175          */
176         p->sched.pc = (ulong)init0;
177         p->sched.sp = (ulong)p->kstack+KSTACK-(sizeof(Sargs)+BY2WD);
178
179         /*
180          * User Stack
181          *
182          * N.B. cannot call newpage() with clear=1, because pc kmap
183          * requires up != nil.  use tmpmap instead.
184          */
185         s = newseg(SG_STACK, USTKTOP-USTKSIZE, USTKSIZE/BY2PG);
186         p->seg[SSEG] = s;
187         pg = newpage(0, 0, USTKTOP-BY2PG);
188         segpage(s, pg);
189         v = tmpmap(pg);
190         memset(v, 0, BY2PG);
191         tmpunmap(v);
192
193         /*
194          * Text
195          */
196         s = newseg(SG_TEXT, UTZERO, 1);
197         s->flushme++;
198         p->seg[TSEG] = s;
199         pg = newpage(0, 0, UTZERO);
200         pg->txtflush = ~0;
201         segpage(s, pg);
202         v = tmpmap(pg);
203         memset(v, 0, BY2PG);
204         memmove(v, initcode, sizeof initcode);
205         tmpunmap(v);
206
207         ready(p);
208 }
209
210 void
211 confinit(void)
212 {
213         char *p;
214         int i, userpcnt;
215         ulong kpages;
216
217         if(p = getconf("service")){
218                 if(strcmp(p, "cpu") == 0)
219                         cpuserver = 1;
220                 else if(strcmp(p,"terminal") == 0)
221                         cpuserver = 0;
222         }
223
224         if(p = getconf("*kernelpercent"))
225                 userpcnt = 100 - strtol(p, 0, 0);
226         else
227                 userpcnt = 0;
228
229         conf.npage = 0;
230         for(i=0; i<nelem(conf.mem); i++)
231                 conf.npage += conf.mem[i].npage;
232
233         conf.nproc = 100 + ((conf.npage*BY2PG)/MB)*5;
234         if(cpuserver)
235                 conf.nproc *= 3;
236         if(conf.nproc > 2000)
237                 conf.nproc = 2000;
238         conf.nimage = 200;
239         conf.nswap = conf.nproc*80;
240         conf.nswppo = 4096;
241
242         if(cpuserver) {
243                 if(userpcnt < 10)
244                         userpcnt = 70;
245                 kpages = conf.npage - (conf.npage*userpcnt)/100;
246                 conf.nimage = conf.nproc;
247
248                 /*
249                  * Hack for the big boys. Only good while physmem < 4GB.
250                  * Give the kernel fixed max + enough to allocate the
251                  * page pool.
252                  * This is an overestimate as conf.upages < conf.npages.
253                  * The patch of nimage is a band-aid, scanning the whole
254                  * page list in imagereclaim just takes too long.
255                  */
256                 if(getconf("*imagemaxmb") == 0)
257                 if(kpages > (64*MB + conf.npage*sizeof(Page))/BY2PG){
258                         kpages = (64*MB + conf.npage*sizeof(Page))/BY2PG;
259                         kpages += (conf.nproc*KSTACK)/BY2PG;
260                 }
261         } else {
262                 if(userpcnt < 10) {
263                         if(conf.npage*BY2PG < 16*MB)
264                                 userpcnt = 50;
265                         else
266                                 userpcnt = 60;
267                 }
268                 kpages = conf.npage - (conf.npage*userpcnt)/100;
269
270                 /*
271                  * Make sure terminals with low memory get at least
272                  * 4MB on the first Image chunk allocation.
273                  */
274                 if(conf.npage*BY2PG < 16*MB)
275                         imagmem->minarena = 4*MB;
276         }
277
278         /*
279          * can't go past the end of virtual memory
280          * (ulong)-KZERO is 2^32 - KZERO
281          */
282         if(kpages > ((ulong)-KZERO)/BY2PG)
283                 kpages = ((ulong)-KZERO)/BY2PG;
284
285         conf.upages = conf.npage - kpages;
286         conf.ialloc = (kpages/2)*BY2PG;
287
288         /*
289          * Guess how much is taken by the large permanent
290          * datastructures. Mntcache and Mntrpc are not accounted for.
291          */
292         kpages *= BY2PG;
293         kpages -= conf.upages*sizeof(Page)
294                 + conf.nproc*sizeof(Proc)
295                 + conf.nimage*sizeof(Image)
296                 + conf.nswap
297                 + conf.nswppo*sizeof(Page*);
298         mainmem->maxsize = kpages;
299
300         /*
301          * the dynamic allocation will balance the load properly,
302          * hopefully. be careful with 32-bit overflow.
303          */
304         imagmem->maxsize = kpages - (kpages/10);
305         if(p = getconf("*imagemaxmb")){
306                 imagmem->maxsize = strtol(p, nil, 0)*MB;
307                 if(imagmem->maxsize > mainmem->maxsize)
308                         imagmem->maxsize = mainmem->maxsize;
309         }
310 }
311
312 /*
313  * we keep FPsave structure in SSE format emulating FXSAVE / FXRSTOR
314  * instructions for legacy x87 fpu.
315  */
316 void
317 fpx87save(FPsave *fps)
318 {
319         ushort tag;
320
321         fpx87save0(fps);
322
323         /*
324          * convert x87 tag word to fxsave tag byte:
325          * 00, 01, 10 -> 1, 11 -> 0
326          */
327         tag = ~fps->tag;
328         tag = (tag | (tag >> 1)) & 0x5555;
329         tag = (tag | (tag >> 1)) & 0x3333;
330         tag = (tag | (tag >> 2)) & 0x0F0F;
331         tag = (tag | (tag >> 4)) & 0x00FF;
332
333         /* NOP fps->fcw = fps->control; */
334         fps->fsw = fps->status;
335         fps->ftw = tag;
336         fps->fop = fps->opcode;
337         fps->fpuip = fps->pc;
338         fps->cs = fps->selector;
339         fps->fpudp = fps->operand;
340         fps->ds = fps->oselector;
341
342 #define MOVA(d,s) \
343         *((ushort*)(d+8)) = *((ushort*)(s+8)), \
344         *((ulong*)(d+4)) = *((ulong*)(s+4)), \
345         *((ulong*)(d)) = *((ulong*)(s))
346
347         MOVA(fps->xregs+0x70, fps->regs+70);
348         MOVA(fps->xregs+0x60, fps->regs+60);
349         MOVA(fps->xregs+0x50, fps->regs+50);
350         MOVA(fps->xregs+0x40, fps->regs+40);
351         MOVA(fps->xregs+0x30, fps->regs+30);
352         MOVA(fps->xregs+0x20, fps->regs+20);
353         MOVA(fps->xregs+0x10, fps->regs+10);
354         MOVA(fps->xregs+0x00, fps->regs+00);
355
356 #undef MOVA
357
358 #define CLR6(d) \
359         *((ulong*)(d)) = 0, \
360         *((ushort*)(d+4)) = 0
361
362         CLR6(fps->xregs+0x70+10);
363         CLR6(fps->xregs+0x60+10);
364         CLR6(fps->xregs+0x50+10);
365         CLR6(fps->xregs+0x40+10);
366         CLR6(fps->xregs+0x30+10);
367         CLR6(fps->xregs+0x20+10);
368         CLR6(fps->xregs+0x10+10);
369         CLR6(fps->xregs+0x00+10);
370
371 #undef CLR6
372
373         fps->rsrvd1 = fps->rsrvd2 = fps->mxcsr = fps->mxcsr_mask = 0;
374 }
375
376 void
377 fpx87restore(FPsave *fps)
378 {
379         ushort msk, tos, tag, *reg;
380
381         /* convert fxsave tag byte to x87 tag word */
382         tag = 0;
383         tos = 7 - ((fps->fsw >> 11) & 7);
384         for(msk = 0x80; msk != 0; tos--, msk >>= 1){
385                 tag <<= 2;
386                 if((fps->ftw & msk) != 0){
387                         reg = (ushort*)&fps->xregs[(tos & 7) << 4];
388                         switch(reg[4] & 0x7fff){
389                         case 0x0000:
390                                 if((reg[0] | reg[1] | reg[2] | reg[3]) == 0){
391                                         tag |= 1;       /* 01 zero */
392                                         break;
393                                 }
394                                 /* no break */
395                         case 0x7fff:
396                                 tag |= 2;               /* 10 special */
397                                 break;
398                         default:
399                                 if((reg[3] & 0x8000) == 0)
400                                         break;          /* 00 valid */
401                                 tag |= 2;               /* 10 special */
402                                 break;
403                         }
404                 }else{
405                         tag |= 3;                       /* 11 empty */
406                 }
407         }
408
409 #define MOVA(d,s) \
410         *((ulong*)(d)) = *((ulong*)(s)), \
411         *((ulong*)(d+4)) = *((ulong*)(s+4)), \
412         *((ushort*)(d+8)) = *((ushort*)(s+8))
413
414         MOVA(fps->regs+00, fps->xregs+0x00);
415         MOVA(fps->regs+10, fps->xregs+0x10);
416         MOVA(fps->regs+20, fps->xregs+0x20);
417         MOVA(fps->regs+30, fps->xregs+0x30);
418         MOVA(fps->regs+40, fps->xregs+0x40);
419         MOVA(fps->regs+50, fps->xregs+0x50);
420         MOVA(fps->regs+60, fps->xregs+0x60);
421         MOVA(fps->regs+70, fps->xregs+0x70);
422
423 #undef MOVA
424
425         fps->oselector = fps->ds;
426         fps->operand = fps->fpudp;
427         fps->opcode = fps->fop & 0x7ff;
428         fps->selector = fps->cs;
429         fps->pc = fps->fpuip;
430         fps->tag = tag;
431         fps->status = fps->fsw;
432         /* NOP fps->control = fps->fcw;  */
433
434         fps->r1 = fps->r2 = fps->r3 = fps->r4 = 0;
435
436         fpx87restore0(fps);
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(ulong status, ulong pc)
451 {
452         char *msg, note[ERRMAX];
453         int i;
454
455         /*
456          * Some attention should probably be paid here to the
457          * exception masks and error summary.
458          */
459         msg = "unknown exception";
460         for(i = 1; i <= 5; i++){
461                 if(!((1<<i) & status))
462                         continue;
463                 msg = mathmsg[i];
464                 break;
465         }
466         if(status & 0x01){
467                 if(status & 0x40){
468                         if(status & 0x200)
469                                 msg = "stack overflow";
470                         else
471                                 msg = "stack underflow";
472                 }else
473                         msg = "invalid operation";
474         }
475         snprint(note, sizeof note, "sys: fp: %s fppc=0x%lux status=0x%lux",
476                 msg, pc, status);
477         postnote(up, 1, note, NDebug);
478 }
479
480 /*
481  *  math coprocessor error
482  */
483 static void
484 matherror(Ureg*, void*)
485 {
486         /*
487          *  a write cycle to port 0xF0 clears the interrupt latch attached
488          *  to the error# line from the 387
489          */
490         if(!(m->cpuiddx & Fpuonchip))
491                 outb(0xF0, 0xFF);
492
493         /*
494          *  get floating point state to check out error
495          */
496         fpsave(up->fpsave);
497         up->fpstate = FPinactive;
498         mathnote(up->fpsave->fsw, up->fpsave->fpuip);
499 }
500
501 /*
502  *  SIMD error
503  */
504 static void
505 simderror(Ureg *ureg, void*)
506 {
507         fpsave(up->fpsave);
508         up->fpstate = FPinactive;
509         mathnote(up->fpsave->mxcsr & 0x3f, ureg->pc);
510 }
511
512 /*
513  *  math coprocessor emulation fault
514  */
515 static void
516 mathemu(Ureg *ureg, void*)
517 {
518         ulong status, control;
519
520         if(up->fpstate & FPillegal){
521                 /* someone did floating point in a note handler */
522                 postnote(up, 1, "sys: floating point in note handler", NDebug);
523                 return;
524         }
525         switch(up->fpstate){
526         case FPinit:
527                 fpinit();
528                 if(fpsave == fpssesave)
529                         ldmxcsr(0x1f80);        /* no simd exceptions on 386 */
530                 while(up->fpsave == nil)
531                         up->fpsave = mallocalign(sizeof(FPsave), FPalign, 0, 0);
532                 up->fpstate = FPactive;
533                 break;
534         case FPinactive:
535                 /*
536                  * Before restoring the state, check for any pending
537                  * exceptions, there's no way to restore the state without
538                  * generating an unmasked exception.
539                  * More attention should probably be paid here to the
540                  * exception masks and error summary.
541                  */
542                 status = up->fpsave->fsw;
543                 control = up->fpsave->fcw;
544                 if((status & ~control) & 0x07F){
545                         mathnote(status, up->fpsave->fpuip);
546                         break;
547                 }
548                 fprestore(up->fpsave);
549                 up->fpstate = FPactive;
550                 break;
551         case FPactive:
552                 panic("math emu pid %ld %s pc 0x%lux", 
553                         up->pid, up->text, ureg->pc);
554                 break;
555         }
556 }
557
558 /*
559  *  math coprocessor segment overrun
560  */
561 static void
562 mathover(Ureg*, void*)
563 {
564         pexit("math overrun", 0);
565 }
566
567 void
568 mathinit(void)
569 {
570         trapenable(VectorCERR, matherror, 0, "matherror");
571         if(X86FAMILY(m->cpuidax) == 3)
572                 intrenable(IrqIRQ13, matherror, 0, BUSUNKNOWN, "matherror");
573         trapenable(VectorCNA, mathemu, 0, "mathemu");
574         trapenable(VectorCSO, mathover, 0, "mathover");
575         trapenable(VectorSIMD, simderror, 0, "simderror");
576 }
577
578 /*
579  *  set up floating point for a new process
580  */
581 void
582 procsetup(Proc *p)
583 {
584         p->fpstate = FPinit;
585         fpoff();
586
587         cycles(&p->kentry);
588         p->pcycles = -p->kentry;
589
590         memset(p->gdt, 0, sizeof(p->gdt));
591         p->ldt = nil;
592         p->nldt = 0;
593         
594         memset(p->dr, 0, sizeof(p->dr));
595 }
596
597 void
598 procfork(Proc *p)
599 {
600         int s;
601
602         p->kentry = up->kentry;
603         p->pcycles = -p->kentry;
604
605         /* inherit user descriptors */
606         memmove(p->gdt, up->gdt, sizeof(p->gdt));
607
608         /* copy local descriptor table */
609         if(up->ldt != nil && up->nldt > 0){
610                 p->ldt = smalloc(sizeof(Segdesc) * up->nldt);
611                 memmove(p->ldt, up->ldt, sizeof(Segdesc) * up->nldt);
612                 p->nldt = up->nldt;
613         }
614
615         /* save floating point state */
616         s = splhi();
617         switch(up->fpstate & ~FPillegal){
618         case FPactive:
619                 fpsave(up->fpsave);
620                 up->fpstate = FPinactive;
621         case FPinactive:
622                 while(p->fpsave == nil)
623                         p->fpsave = mallocalign(sizeof(FPsave), FPalign, 0, 0);
624                 memmove(p->fpsave, up->fpsave, sizeof(FPsave));
625                 p->fpstate = FPinactive;
626         }
627         
628         /* clear debug registers */
629         memset(p->dr, 0, sizeof(p->dr));
630         splx(s);
631 }
632
633 void
634 procrestore(Proc *p)
635 {
636         uvlong t;
637         
638         if(p->dr[7] != 0){
639                 m->dr7 = p->dr[7];
640                 putdr(p->dr);
641         }
642         
643         if(p->vmx != nil)
644                 vmxprocrestore(p);
645
646         if(p->kp)
647                 return;
648
649         cycles(&t);
650         p->kentry += t;
651         p->pcycles -= t;
652 }
653
654 /*
655  *  Save the mach dependent part of the process state.
656  */
657 void
658 procsave(Proc *p)
659 {
660         uvlong t;
661         
662         /* we could just always putdr7(0) but accessing DR7 might be slow in a VM */
663         if(m->dr7 != 0){
664                 m->dr7 = 0;
665                 putdr7(0);
666         }
667
668         cycles(&t);
669         p->kentry -= t;
670         p->pcycles += t;
671
672         if(p->fpstate == FPactive){
673                 if(p->state == Moribund)
674                         fpclear();
675                 else{
676                         /*
677                          * Fpsave() stores without handling pending
678                          * unmasked exeptions. Postnote() can't be called
679                          * here as sleep() already has up->rlock, so
680                          * the handling of pending exceptions is delayed
681                          * until the process runs again and generates an
682                          * emulation fault to activate the FPU.
683                          */
684                         fpsave(p->fpsave);
685                 }
686                 p->fpstate = FPinactive;
687         }
688
689         /*
690          * While this processor is in the scheduler, the process could run
691          * on another processor and exit, returning the page tables to
692          * the free list where they could be reallocated and overwritten.
693          * When this processor eventually has to get an entry from the
694          * trashed page tables it will crash.
695          *
696          * If there's only one processor, this can't happen.
697          * You might think it would be a win not to do this in that case,
698          * especially on VMware, but it turns out not to matter.
699          */
700         mmuflushtlb(PADDR(m->pdb));
701 }
702
703 void
704 reboot(void *entry, void *code, ulong size)
705 {
706         void (*f)(ulong, ulong, ulong);
707         ulong *pdb;
708
709         writeconf();
710         vmxshutdown();
711
712         /*
713          * the boot processor is cpu0.  execute this function on it
714          * so that the new kernel has the same cpu0.  this only matters
715          * because the hardware has a notion of which processor was the
716          * boot processor and we look at it at start up.
717          */
718         if (m->machno != 0) {
719                 procwired(up, 0);
720                 sched();
721         }
722         cpushutdown();
723
724         splhi();
725
726         /* turn off buffered serial console */
727         serialoq = nil;
728
729         /* shutdown devices */
730         chandevshutdown();
731         arch->introff();
732
733         /*
734          * Modify the machine page table to directly map the low 4MB of memory
735          * This allows the reboot code to turn off the page mapping
736          */
737         pdb = m->pdb;
738         pdb[PDX(0)] = pdb[PDX(KZERO)];
739         mmuflushtlb(PADDR(pdb));
740
741         /* setup reboot trampoline function */
742         f = (void*)REBOOTADDR;
743         memmove(f, rebootcode, sizeof(rebootcode));
744
745         /* off we go - never to return */
746         coherence();
747         (*f)((ulong)entry & ~0xF0000000UL, PADDR(code), size);
748 }
749
750
751 void
752 exit(int)
753 {
754         cpushutdown();
755         arch->reset();
756 }