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