]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/pc/main.c
pc, pc64: more conservative pcirouting
[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
15 /*
16  * Where configuration info is left for the loaded programme.
17  * This will turn into a structure as more is done by the boot loader
18  * (e.g. why parse the .ini file twice?).
19  * There are 3584 bytes available at CONFADDR.
20  */
21 #define BOOTLINE        ((char*)CONFADDR)
22 #define BOOTLINELEN     64
23 #define BOOTARGS        ((char*)(CONFADDR+BOOTLINELEN))
24 #define BOOTARGSLEN     (4096-0x200-BOOTLINELEN)
25 #define MAXCONF         64
26
27 char bootdisk[KNAMELEN];
28 Conf conf;
29 char *confname[MAXCONF];
30 char *confval[MAXCONF];
31 int nconf;
32 uchar *sp;      /* user stack of init proc */
33 int delaylink;
34 int idle_spin;
35
36 static void
37 multibootargs(void)
38 {
39         char *cp, *ep;
40         ulong *m, l;
41
42         extern ulong *multiboot;
43
44         if(multiboot == nil)
45                 return;
46
47         /* command line */
48         if((multiboot[0] & (1<<2)) != 0)
49                 strncpy(BOOTLINE, KADDR(multiboot[4]), BOOTLINELEN-1);
50
51         cp = BOOTARGS;
52         ep = cp + BOOTARGSLEN-1;
53
54         /* memory map */
55         if((multiboot[0] & (1<<6)) != 0 && (l = multiboot[11]) >= 24){
56                 cp = seprint(cp, ep, "*e820=");
57                 m = KADDR(multiboot[12]);
58                 while(m[0] >= 20 && m[0] <= l-4){
59                         uvlong base, size;
60                         m++;
61                         base = ((uvlong)m[0] | (uvlong)m[1]<<32);
62                         size = ((uvlong)m[2] | (uvlong)m[3]<<32);
63                         cp = seprint(cp, ep, "%.1lux %.16llux %.16llux ",
64                                 m[4] & 0xF, base, base+size);
65                         l -= m[-1]+4;
66                         m = (ulong*)((ulong)m + m[-1]);
67                 }
68                 cp[-1] = '\n';
69         }
70
71         /* plan9.ini passed as the first module */
72         if((multiboot[0] & (1<<3)) != 0 && multiboot[5] > 0){
73                 m = KADDR(multiboot[6]);
74                 l = m[1] - m[0];
75                 m = KADDR(m[0]);
76                 if(cp+l > ep)
77                         l = ep - cp;
78                 memmove(cp, m, l);
79                 cp += l;
80         }
81         *cp = 0;
82 }
83
84 static void
85 options(void)
86 {
87         long i, n;
88         char *cp, *line[MAXCONF], *p, *q;
89
90         multibootargs();
91
92         /*
93          *  parse configuration args from dos file plan9.ini
94          */
95         cp = BOOTARGS;  /* where b.com leaves its config */
96         cp[BOOTARGSLEN-1] = 0;
97
98         /*
99          * Strip out '\r', change '\t' -> ' '.
100          */
101         p = cp;
102         for(q = cp; *q; q++){
103                 if(*q == '\r')
104                         continue;
105                 if(*q == '\t')
106                         *q = ' ';
107                 *p++ = *q;
108         }
109         *p = 0;
110
111         n = getfields(cp, line, MAXCONF, 1, "\n");
112         for(i = 0; i < n; i++){
113                 if(*line[i] == '#')
114                         continue;
115                 cp = strchr(line[i], '=');
116                 if(cp == nil)
117                         continue;
118                 *cp++ = '\0';
119                 confname[nconf] = line[i];
120                 confval[nconf] = cp;
121                 nconf++;
122         }
123 }
124
125 extern void mmuinit0(void);
126 extern void (*i8237alloc)(void);
127 extern void bootscreeninit(void);
128
129 void
130 main(void)
131 {
132         mach0init();
133         options();
134         ioinit();
135         i8250console();
136         quotefmtinstall();
137         screeninit();
138
139         print("\nPlan 9\n");
140
141         trapinit0();
142         mmuinit0();
143
144         kbdinit();
145         i8253init();
146         cpuidentify();
147         meminit();
148         confinit();
149         xinit();
150         archinit();
151         bootscreeninit();
152         if(i8237alloc != nil)
153                 i8237alloc();
154         trapinit();
155         printinit();
156         cpuidprint();
157         mmuinit();
158         if(arch->intrinit)      /* launches other processors on an mp */
159                 arch->intrinit();
160         timersinit();
161         mathinit();
162         kbdenable();
163         if(arch->clockenable)
164                 arch->clockenable();
165         procinit0();
166         initseg();
167         if(delaylink){
168                 bootlinks();
169                 pcimatch(0, 0, 0);
170         }else
171                 links();
172         conf.monitor = 1;
173         chandevreset();
174         pageinit();
175         swapinit();
176         userinit();
177         active.thunderbirdsarego = 1;
178         schedinit();
179 }
180
181 void
182 mach0init(void)
183 {
184         conf.nmach = 1;
185         MACHP(0) = (Mach*)CPU0MACH;
186         m->pdb = (ulong*)CPU0PDB;
187         m->gdt = (Segdesc*)CPU0GDT;
188
189         machinit();
190
191         active.machs = 1;
192         active.exiting = 0;
193 }
194
195 void
196 machinit(void)
197 {
198         int machno;
199         ulong *pdb;
200         Segdesc *gdt;
201
202         machno = m->machno;
203         pdb = m->pdb;
204         gdt = m->gdt;
205         memset(m, 0, sizeof(Mach));
206         m->machno = machno;
207         m->pdb = pdb;
208         m->gdt = gdt;
209         m->perf.period = 1;
210
211         /*
212          * For polled uart output at boot, need
213          * a default delay constant. 100000 should
214          * be enough for a while. Cpuidentify will
215          * calculate the real value later.
216          */
217         m->loopconst = 100000;
218 }
219
220 void
221 init0(void)
222 {
223         int i;
224         char buf[2*KNAMELEN];
225
226         up->nerrlab = 0;
227
228         spllo();
229
230         /*
231          * These are o.k. because rootinit is null.
232          * Then early kproc's will have a root and dot.
233          */
234         up->slash = namec("#/", Atodir, 0, 0);
235         pathclose(up->slash->path);
236         up->slash->path = newpath("/");
237         up->dot = cclone(up->slash);
238
239         chandevinit();
240
241         if(!waserror()){
242                 snprint(buf, sizeof(buf), "%s %s", arch->id, conffile);
243                 ksetenv("terminal", buf, 0);
244                 ksetenv("cputype", "386", 0);
245                 if(cpuserver)
246                         ksetenv("service", "cpu", 0);
247                 else
248                         ksetenv("service", "terminal", 0);
249                 for(i = 0; i < nconf; i++){
250                         if(confname[i][0] != '*')
251                                 ksetenv(confname[i], confval[i], 0);
252                         ksetenv(confname[i], confval[i], 1);
253                 }
254                 poperror();
255         }
256         kproc("alarm", alarmkproc, 0);
257         touser(sp);
258 }
259
260 void
261 userinit(void)
262 {
263         void *v;
264         Proc *p;
265         Segment *s;
266         Page *pg;
267
268         p = newproc();
269         p->pgrp = newpgrp();
270         p->egrp = smalloc(sizeof(Egrp));
271         p->egrp->ref = 1;
272         p->fgrp = dupfgrp(nil);
273         p->rgrp = newrgrp();
274         p->procmode = 0640;
275
276         kstrdup(&eve, "");
277         kstrdup(&p->text, "*init*");
278         kstrdup(&p->user, eve);
279
280         procsetup(p);
281
282         /*
283          * Kernel Stack
284          *
285          * N.B. make sure there's enough space for syscall to check
286          *      for valid args and 
287          *      4 bytes for gotolabel's return PC
288          */
289         p->sched.pc = (ulong)init0;
290         p->sched.sp = (ulong)p->kstack+KSTACK-(sizeof(Sargs)+BY2WD);
291
292         /*
293          * User Stack
294          *
295          * N.B. cannot call newpage() with clear=1, because pc kmap
296          * requires up != nil.  use tmpmap instead.
297          */
298         s = newseg(SG_STACK, USTKTOP-USTKSIZE, USTKSIZE/BY2PG);
299         p->seg[SSEG] = s;
300         pg = newpage(0, 0, USTKTOP-BY2PG);
301         v = tmpmap(pg);
302         memset(v, 0, BY2PG);
303         segpage(s, pg);
304         bootargs(v);
305         tmpunmap(v);
306
307         /*
308          * Text
309          */
310         s = newseg(SG_TEXT, UTZERO, 1);
311         s->flushme++;
312         p->seg[TSEG] = s;
313         pg = newpage(0, 0, UTZERO);
314         memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl));
315         segpage(s, pg);
316         v = tmpmap(pg);
317         memset(v, 0, BY2PG);
318         memmove(v, initcode, sizeof initcode);
319         tmpunmap(v);
320
321         ready(p);
322 }
323
324 uchar *
325 pusharg(char *p)
326 {
327         int n;
328
329         n = strlen(p)+1;
330         sp -= n;
331         memmove(sp, p, n);
332         return sp;
333 }
334
335 void
336 bootargs(void *base)
337 {
338         int i, ac;
339         uchar *av[32];
340         uchar **lsp;
341         char *cp = BOOTLINE;
342         char buf[64];
343
344         sp = (uchar*)base + BY2PG - sizeof(Tos);
345
346         ac = 0;
347         av[ac++] = pusharg("boot");
348
349         /* when boot is changed to only use rc, this code can go away */
350         cp[BOOTLINELEN-1] = 0;
351         buf[0] = 0;
352         if(strncmp(cp, "fd", 2) == 0){
353                 sprint(buf, "local!#f/fd%lddisk", strtol(cp+2, 0, 0));
354                 av[ac++] = pusharg(buf);
355         } else if(strncmp(cp, "sd", 2) == 0){
356                 sprint(buf, "local!#S/sd%c%c/fs", *(cp+2), *(cp+3));
357                 av[ac++] = pusharg(buf);
358         } else if(strncmp(cp, "ether", 5) == 0)
359                 av[ac++] = pusharg("-n");
360
361         /* 4 byte word align stack */
362         sp = (uchar*)((ulong)sp & ~3);
363
364         /* build argc, argv on stack */
365         sp -= (ac+1)*sizeof(sp);
366         lsp = (uchar**)sp;
367         for(i = 0; i < ac; i++)
368                 lsp[i] = av[i] + ((USTKTOP - BY2PG) - (ulong)base);
369         lsp[i] = 0;
370         sp += (USTKTOP - BY2PG) - (ulong)base;
371         sp -= BY2WD;
372 }
373
374 char*
375 getconf(char *name)
376 {
377         int i;
378
379         for(i = 0; i < nconf; i++)
380                 if(cistrcmp(confname[i], name) == 0)
381                         return confval[i];
382         return 0;
383 }
384
385 static void
386 writeconf(void)
387 {
388         char *p, *q;
389         int n;
390
391         p = getconfenv();
392
393         if(waserror()) {
394                 free(p);
395                 nexterror();
396         }
397
398         /* convert to name=value\n format */
399         for(q=p; *q; q++) {
400                 q += strlen(q);
401                 *q = '=';
402                 q += strlen(q);
403                 *q = '\n';
404         }
405         n = q - p + 1;
406         if(n >= BOOTARGSLEN)
407                 error("kernel configuration too large");
408         memset(BOOTLINE, 0, BOOTLINELEN);
409         memmove(BOOTARGS, p, n);
410         poperror();
411         free(p);
412 }
413
414 void
415 confinit(void)
416 {
417         char *p;
418         int i, userpcnt;
419         ulong kpages;
420
421         if(p = getconf("service")){
422                 if(strcmp(p, "cpu") == 0)
423                         cpuserver = 1;
424                 else if(strcmp(p,"terminal") == 0)
425                         cpuserver = 0;
426         }
427
428         if(p = getconf("*kernelpercent"))
429                 userpcnt = 100 - strtol(p, 0, 0);
430         else
431                 userpcnt = 0;
432
433         conf.npage = 0;
434         for(i=0; i<nelem(conf.mem); i++)
435                 conf.npage += conf.mem[i].npage;
436
437         conf.nproc = 100 + ((conf.npage*BY2PG)/MB)*5;
438         if(cpuserver)
439                 conf.nproc *= 3;
440         if(conf.nproc > 2000)
441                 conf.nproc = 2000;
442         conf.nimage = 200;
443         conf.nswap = conf.nproc*80;
444         conf.nswppo = 4096;
445
446         if(cpuserver) {
447                 if(userpcnt < 10)
448                         userpcnt = 70;
449                 kpages = conf.npage - (conf.npage*userpcnt)/100;
450
451                 /*
452                  * Hack for the big boys. Only good while physmem < 4GB.
453                  * Give the kernel fixed max + enough to allocate the
454                  * page pool.
455                  * This is an overestimate as conf.upages < conf.npages.
456                  * The patch of nimage is a band-aid, scanning the whole
457                  * page list in imagereclaim just takes too long.
458                  */
459                 if(getconf("*imagemaxmb") == 0)
460                 if(kpages > (64*MB + conf.npage*sizeof(Page))/BY2PG){
461                         kpages = (64*MB + conf.npage*sizeof(Page))/BY2PG;
462                         conf.nimage = 2000;
463                         kpages += (conf.nproc*KSTACK)/BY2PG;
464                 }
465         } else {
466                 if(userpcnt < 10) {
467                         if(conf.npage*BY2PG < 16*MB)
468                                 userpcnt = 50;
469                         else
470                                 userpcnt = 60;
471                 }
472                 kpages = conf.npage - (conf.npage*userpcnt)/100;
473
474                 /*
475                  * Make sure terminals with low memory get at least
476                  * 4MB on the first Image chunk allocation.
477                  */
478                 if(conf.npage*BY2PG < 16*MB)
479                         imagmem->minarena = 4*MB;
480         }
481
482         /*
483          * can't go past the end of virtual memory
484          * (ulong)-KZERO is 2^32 - KZERO
485          */
486         if(kpages > ((ulong)-KZERO)/BY2PG)
487                 kpages = ((ulong)-KZERO)/BY2PG;
488
489         conf.upages = conf.npage - kpages;
490         conf.ialloc = (kpages/2)*BY2PG;
491
492         /*
493          * Guess how much is taken by the large permanent
494          * datastructures. Mntcache and Mntrpc are not accounted for
495          * (probably ~300KB).
496          */
497         kpages *= BY2PG;
498         kpages -= conf.upages*sizeof(Page)
499                 + conf.nproc*sizeof(Proc)
500                 + conf.nimage*sizeof(Image)
501                 + conf.nswap
502                 + conf.nswppo*sizeof(Page*);
503         mainmem->maxsize = kpages;
504
505         /*
506          * the dynamic allocation will balance the load properly,
507          * hopefully. be careful with 32-bit overflow.
508          */
509         imagmem->maxsize = kpages - (kpages/10);
510         if(p = getconf("*imagemaxmb")){
511                 imagmem->maxsize = strtol(p, nil, 0)*MB;
512                 if(imagmem->maxsize > mainmem->maxsize)
513                         imagmem->maxsize = mainmem->maxsize;
514         }
515 }
516
517 /*
518  * we keep FPsave structure in sse format emulating FXSAVE / FXRSTOR
519  * instructions for legacy x87 fpu.
520  *
521  * Note that fpx87restore() and fpxsserestore() do modify the FPsave
522  * data structure for conversion / realignment shuffeling. this means
523  * that p->fpsave is only valid when p->fpstate == FPinactive.
524  */
525 void
526 fpx87save(FPsave *fps)
527 {
528         ushort tag;
529
530         fpx87save0(fps);
531
532         /*
533          * convert x87 tag word to fxsave tag byte:
534          * 00, 01, 10 -> 1, 11 -> 0
535          */
536         tag = ~fps->tag;
537         tag = (tag | (tag >> 1)) & 0x5555;
538         tag = (tag | (tag >> 1)) & 0x3333;
539         tag = (tag | (tag >> 2)) & 0x0F0F;
540         tag = (tag | (tag >> 4)) & 0x00FF;
541
542         /* NOP fps->fcw = fps->control; */
543         fps->fsw = fps->status;
544         fps->ftw = tag;
545         fps->fop = fps->opcode;
546         fps->fpuip = fps->pc;
547         fps->cs = fps->selector;
548         fps->fpudp = fps->operand;
549         fps->ds = fps->oselector;
550
551 #define MOVA(d,s) \
552         *((ushort*)(d+8)) = *((ushort*)(s+8)), \
553         *((ulong*)(d+4)) = *((ulong*)(s+4)), \
554         *((ulong*)(d)) = *((ulong*)(s))
555
556         MOVA(fps->xregs+0x70, fps->regs+70);
557         MOVA(fps->xregs+0x60, fps->regs+60);
558         MOVA(fps->xregs+0x50, fps->regs+50);
559         MOVA(fps->xregs+0x40, fps->regs+40);
560         MOVA(fps->xregs+0x30, fps->regs+30);
561         MOVA(fps->xregs+0x20, fps->regs+20);
562         MOVA(fps->xregs+0x10, fps->regs+10);
563         MOVA(fps->xregs+0x00, fps->regs+00);
564
565 #undef MOVA
566
567 #define CLR6(d) \
568         *((ulong*)(d)) = 0, \
569         *((ushort*)(d+4)) = 0
570
571         CLR6(fps->xregs+0x70+10);
572         CLR6(fps->xregs+0x60+10);
573         CLR6(fps->xregs+0x50+10);
574         CLR6(fps->xregs+0x40+10);
575         CLR6(fps->xregs+0x30+10);
576         CLR6(fps->xregs+0x20+10);
577         CLR6(fps->xregs+0x10+10);
578         CLR6(fps->xregs+0x00+10);
579
580 #undef CLR6
581
582         fps->rsrvd1 = fps->rsrvd2 = fps->mxcsr = fps->mxcsr_mask = 0;
583 }
584
585 void
586 fpx87restore(FPsave *fps)
587 {
588         ushort msk, tos, tag, *reg;
589
590         /* convert fxsave tag byte to x87 tag word */
591         tag = 0;
592         tos = 7 - ((fps->fsw >> 11) & 7);
593         for(msk = 0x80; msk != 0; tos--, msk >>= 1){
594                 tag <<= 2;
595                 if((fps->ftw & msk) != 0){
596                         reg = (ushort*)&fps->xregs[(tos & 7) << 4];
597                         switch(reg[4] & 0x7fff){
598                         case 0x0000:
599                                 if((reg[0] | reg[1] | reg[2] | reg[3]) == 0){
600                                         tag |= 1;       /* 01 zero */
601                                         break;
602                                 }
603                                 /* no break */
604                         case 0x7fff:
605                                 tag |= 2;               /* 10 special */
606                                 break;
607                         default:
608                                 if((reg[3] & 0x8000) == 0)
609                                         break;          /* 00 valid */
610                                 tag |= 2;               /* 10 special */
611                                 break;
612                         }
613                 }else{
614                         tag |= 3;                       /* 11 empty */
615                 }
616         }
617
618 #define MOVA(d,s) \
619         *((ulong*)(d)) = *((ulong*)(s)), \
620         *((ulong*)(d+4)) = *((ulong*)(s+4)), \
621         *((ushort*)(d+8)) = *((ushort*)(s+8))
622
623         MOVA(fps->regs+00, fps->xregs+0x00);
624         MOVA(fps->regs+10, fps->xregs+0x10);
625         MOVA(fps->regs+20, fps->xregs+0x20);
626         MOVA(fps->regs+30, fps->xregs+0x30);
627         MOVA(fps->regs+40, fps->xregs+0x40);
628         MOVA(fps->regs+50, fps->xregs+0x50);
629         MOVA(fps->regs+60, fps->xregs+0x60);
630         MOVA(fps->regs+70, fps->xregs+0x70);
631
632 #undef MOVA
633
634         fps->oselector = fps->ds;
635         fps->operand = fps->fpudp;
636         fps->opcode = fps->fop & 0x7ff;
637         fps->selector = fps->cs;
638         fps->pc = fps->fpuip;
639         fps->tag = tag;
640         fps->status = fps->fsw;
641         /* NOP fps->control = fps->fcw;  */
642
643         fps->r1 = fps->r2 = fps->r3 = fps->r4 = 0;
644
645         fpx87restore0(fps);
646 }
647
648 /*
649  * sse fp save and restore buffers have to be 16-byte (FPalign) aligned,
650  * so we shuffle the data up and down as needed or make copies.
651  */
652 void
653 fpssesave(FPsave *fps)
654 {
655         FPsave *afps;
656
657         afps = (FPsave *)ROUND(((uintptr)fps), FPalign);
658         fpssesave0(afps);
659         if(fps != afps)  /* not aligned? shuffle down from aligned buffer */
660                 memmove(fps, afps, sizeof(FPssestate) - FPalign);
661 }
662
663 void
664 fpsserestore(FPsave *fps)
665 {
666         FPsave *afps;
667
668         afps = (FPsave *)ROUND(((uintptr)fps), FPalign);
669         if(fps != afps)  /* shuffle up to make aligned */
670                 memmove(afps, fps, sizeof(FPssestate) - FPalign);
671         fpsserestore0(afps);
672 }
673
674 static char* mathmsg[] =
675 {
676         nil,    /* handled below */
677         "denormalized operand",
678         "division by zero",
679         "numeric overflow",
680         "numeric underflow",
681         "precision loss",
682 };
683
684 static void
685 mathnote(ulong status, ulong pc)
686 {
687         char *msg, note[ERRMAX];
688         int i;
689
690         /*
691          * Some attention should probably be paid here to the
692          * exception masks and error summary.
693          */
694         msg = "unknown exception";
695         for(i = 1; i <= 5; i++){
696                 if(!((1<<i) & status))
697                         continue;
698                 msg = mathmsg[i];
699                 break;
700         }
701         if(status & 0x01){
702                 if(status & 0x40){
703                         if(status & 0x200)
704                                 msg = "stack overflow";
705                         else
706                                 msg = "stack underflow";
707                 }else
708                         msg = "invalid operation";
709         }
710         snprint(note, sizeof note, "sys: fp: %s fppc=0x%lux status=0x%lux",
711                 msg, pc, status);
712         postnote(up, 1, note, NDebug);
713 }
714
715 /*
716  *  math coprocessor error
717  */
718 static void
719 matherror(Ureg*, void*)
720 {
721         /*
722          *  a write cycle to port 0xF0 clears the interrupt latch attached
723          *  to the error# line from the 387
724          */
725         if(!(m->cpuiddx & Fpuonchip))
726                 outb(0xF0, 0xFF);
727
728         /*
729          *  get floating point state to check out error
730          */
731         fpenv(&up->fpsave);
732         mathnote(up->fpsave.status, up->fpsave.pc);
733 }
734
735 /*
736  *  SIMD error
737  */
738 static void
739 simderror(Ureg *ureg, void*)
740 {
741         fpsave(&up->fpsave);
742         up->fpstate = FPinactive;
743         mathnote(up->fpsave.mxcsr & 0x3f, ureg->pc);
744 }
745
746 /*
747  *  math coprocessor emulation fault
748  */
749 static void
750 mathemu(Ureg *ureg, void*)
751 {
752         ulong status, control;
753
754         if(up->fpstate & FPillegal){
755                 /* someone did floating point in a note handler */
756                 postnote(up, 1, "sys: floating point in note handler", NDebug);
757                 return;
758         }
759         switch(up->fpstate){
760         case FPinit:
761                 fpinit();
762                 if(fpsave == fpssesave)
763                         ldmxcsr(0);     /* no simd exceptions on 386 */
764                 up->fpstate = FPactive;
765                 break;
766         case FPinactive:
767                 /*
768                  * Before restoring the state, check for any pending
769                  * exceptions, there's no way to restore the state without
770                  * generating an unmasked exception.
771                  * More attention should probably be paid here to the
772                  * exception masks and error summary.
773                  */
774                 status = up->fpsave.fsw;
775                 control = up->fpsave.fcw;
776                 if((status & ~control) & 0x07F){
777                         mathnote(status, up->fpsave.fpuip);
778                         break;
779                 }
780                 fprestore(&up->fpsave);
781                 up->fpstate = FPactive;
782                 break;
783         case FPactive:
784                 panic("math emu pid %ld %s pc 0x%lux", 
785                         up->pid, up->text, ureg->pc);
786                 break;
787         }
788 }
789
790 /*
791  *  math coprocessor segment overrun
792  */
793 static void
794 mathover(Ureg*, void*)
795 {
796         pexit("math overrun", 0);
797 }
798
799 void
800 mathinit(void)
801 {
802         trapenable(VectorCERR, matherror, 0, "matherror");
803         if(X86FAMILY(m->cpuidax) == 3)
804                 intrenable(IrqIRQ13, matherror, 0, BUSUNKNOWN, "matherror");
805         trapenable(VectorCNA, mathemu, 0, "mathemu");
806         trapenable(VectorCSO, mathover, 0, "mathover");
807         trapenable(VectorSIMD, simderror, 0, "simderror");
808 }
809
810 /*
811  *  set up floating point for a new process
812  */
813 void
814 procsetup(Proc *p)
815 {
816         p->fpstate = FPinit;
817         fpoff();
818
819         cycles(&p->kentry);
820         p->pcycles = -p->kentry;
821
822         memset(p->gdt, 0, sizeof(p->gdt));
823         p->ldt = nil;
824         p->nldt = 0;
825 }
826
827 void
828 procfork(Proc *p)
829 {
830         int s;
831
832         p->kentry = up->kentry;
833         p->pcycles = -p->kentry;
834
835         /* inherit user descriptors */
836         memmove(p->gdt, up->gdt, sizeof(p->gdt));
837
838         /* copy local descriptor table */
839         if(up->ldt != nil && up->nldt > 0){
840                 p->ldt = smalloc(sizeof(Segdesc) * up->nldt);
841                 memmove(p->ldt, up->ldt, sizeof(Segdesc) * up->nldt);
842                 p->nldt = up->nldt;
843         }
844
845         /* save floating point state */
846         s = splhi();
847         switch(up->fpstate & ~FPillegal){
848         case FPactive:
849                 fpsave(&up->fpsave);
850                 up->fpstate = FPinactive;
851         case FPinactive:
852                 p->fpsave = up->fpsave;
853                 p->fpstate = FPinactive;
854         }
855         splx(s);
856 }
857
858 void
859 procrestore(Proc *p)
860 {
861         uvlong t;
862
863         if(p->kp)
864                 return;
865
866         cycles(&t);
867         p->kentry += t;
868         p->pcycles -= t;
869 }
870
871 /*
872  *  Save the mach dependent part of the process state.
873  */
874 void
875 procsave(Proc *p)
876 {
877         uvlong t;
878
879         cycles(&t);
880         p->kentry -= t;
881         p->pcycles += t;
882
883         if(p->fpstate == FPactive){
884                 if(p->state == Moribund)
885                         fpclear();
886                 else{
887                         /*
888                          * Fpsave() stores without handling pending
889                          * unmasked exeptions. Postnote() can't be called
890                          * here as sleep() already has up->rlock, so
891                          * the handling of pending exceptions is delayed
892                          * until the process runs again and generates an
893                          * emulation fault to activate the FPU.
894                          */
895                         fpsave(&p->fpsave);
896                 }
897                 p->fpstate = FPinactive;
898         }
899
900         /*
901          * While this processor is in the scheduler, the process could run
902          * on another processor and exit, returning the page tables to
903          * the free list where they could be reallocated and overwritten.
904          * When this processor eventually has to get an entry from the
905          * trashed page tables it will crash.
906          *
907          * If there's only one processor, this can't happen.
908          * You might think it would be a win not to do this in that case,
909          * especially on VMware, but it turns out not to matter.
910          */
911         mmuflushtlb(PADDR(m->pdb));
912 }
913
914 static void
915 shutdown(int ispanic)
916 {
917         int ms, once;
918
919         lock(&active);
920         if(ispanic)
921                 active.ispanic = ispanic;
922         else if(m->machno == 0 && (active.machs & (1<<m->machno)) == 0)
923                 active.ispanic = 0;
924         once = active.machs & (1<<m->machno);
925         /*
926          * setting exiting will make hzclock() on each processor call exit(0),
927          * which calls shutdown(0) and arch->reset(), which on mp systems is
928          * mpshutdown, from which there is no return: the processor is idled
929          * or initiates a reboot.  clearing our bit in machs avoids calling
930          * exit(0) from hzclock() on this processor.
931          */
932         active.machs &= ~(1<<m->machno);
933         active.exiting = 1;
934         unlock(&active);
935
936         if(once)
937                 iprint("cpu%d: exiting\n", m->machno);
938
939         /* wait for any other processors to shutdown */
940         spllo();
941         for(ms = 5*1000; ms > 0; ms -= TK2MS(2)){
942                 delay(TK2MS(2));
943                 if(active.machs == 0 && consactive() == 0)
944                         break;
945         }
946
947         if(active.ispanic){
948                 if(!cpuserver)
949                         for(;;)
950                                 halt();
951                 if(getconf("*debug"))
952                         delay(5*60*1000);
953                 else
954                         delay(10000);
955         }
956 }
957
958 void
959 reboot(void *entry, void *code, ulong size)
960 {
961         void (*f)(ulong, ulong, ulong);
962         ulong *pdb;
963
964         writeconf();
965
966         /*
967          * the boot processor is cpu0.  execute this function on it
968          * so that the new kernel has the same cpu0.  this only matters
969          * because the hardware has a notion of which processor was the
970          * boot processor and we look at it at start up.
971          */
972         if (m->machno != 0) {
973                 procwired(up, 0);
974                 sched();
975         }
976         shutdown(0);
977
978         iprint("shutting down...\n");
979         delay(200);
980
981         splhi();
982
983         /* turn off buffered serial console */
984         serialoq = nil;
985
986         /* shutdown devices */
987         chandevshutdown();
988         arch->introff();
989
990         /*
991          * Modify the machine page table to directly map the low 4MB of memory
992          * This allows the reboot code to turn off the page mapping
993          */
994         pdb = m->pdb;
995         pdb[PDX(0)] = pdb[PDX(KZERO)];
996         mmuflushtlb(PADDR(pdb));
997
998         /* setup reboot trampoline function */
999         f = (void*)REBOOTADDR;
1000         memmove(f, rebootcode, sizeof(rebootcode));
1001
1002         /* off we go - never to return */
1003         coherence();
1004         (*f)((ulong)entry & ~0xF0000000UL, PADDR(code), size);
1005 }
1006
1007
1008 void
1009 exit(int ispanic)
1010 {
1011         shutdown(ispanic);
1012         arch->reset();
1013 }