]> git.lizzy.rs Git - plan9front.git/blob - sys/src/9/alphapc/main.c
merge
[plan9front.git] / sys / src / 9 / alphapc / 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        "init.h"
8 #include        "pool.h"
9 #include        "/sys/src/boot/alphapc/conf.h"
10 #include        "axp.h"
11
12 char argbuf[128];       /* arguments passed to initcode and /boot */
13
14 Hwrpb *hwrpb;
15 Bootconf *bootconf;
16 Conf    conf;
17 FPsave  initfp;
18         /* setfcr(FPPDBL|FPRNR|FPINVAL|FPZDIV|FPOVFL) */
19 uvlong initfpcr = (1LL<62)|(1LL<61)|(1LL<60)|(2LL<<58)|(1LL<48);
20
21 char bootargs[BOOTARGSLEN];
22 char *confname[MAXCONF];
23 char *confval[MAXCONF];
24 int     nconf;
25
26 static void
27 options(void)
28 {
29         long i, n;
30         char *cp, *line[MAXCONF], *p, *q;
31
32         cp = bootargs;
33         strncpy(cp, bootconf->bootargs, BOOTARGSLEN);
34         cp[BOOTARGSLEN-1] = 0;
35         /* can't print in this routine, see below in main() */
36
37         /*
38          * Strip out '\r', change '\t' -> ' '.
39          */
40         p = cp;
41         for(q = cp; *q; q++){
42                 if(*q == '\r')
43                         continue;
44                 if(*q == '\t')
45                         *q = ' ';
46                 *p++ = *q;
47         }
48         *p = 0;
49
50         n = getfields(cp, line, MAXCONF, 1, "\n");
51         for(i = 0; i < n; i++){
52                 if(*line[i] == '#')
53                         continue;
54                 cp = strchr(line[i], '=');
55                 if(cp == nil)
56                         continue;
57                 *cp++ = '\0';
58                 confname[nconf] = line[i];
59                 confval[nconf] = cp;
60                 nconf++;
61         }
62 }
63
64 /* debugging only */
65 static void
66 dumpopts(void)
67 {
68         int i;
69
70         print("dumpopts: found /alpha/conf options at %#p\n",
71                 bootconf->bootargs);
72         for(i = 0; i < nconf; i++)
73                 print("dumpopts: read %s=%s\n", confname[i], confval[i]);
74 }
75
76 extern void (*i8237alloc)(void);
77
78 void
79 main(void)
80 {
81         hwrpb = (Hwrpb*)0x10000000;
82         hwrpb = (Hwrpb*)(KZERO|hwrpb->phys);
83         arginit();
84         machinit();
85         options();
86         ioinit();
87         clockinit();
88         confinit();
89         archinit();
90         xinit();
91         memholes();
92         if(i8237alloc != nil)
93                 i8237alloc();
94         mmuinit();
95         if(arch->coreinit)
96                 arch->coreinit();
97         trapinit();
98         screeninit();
99         printinit();
100         /* it's now safe to print */
101         /* dumpopts();                  /* DEBUG */
102         i8250console();
103         quotefmtinstall();
104         print("\nPlan 9\n");
105
106         cpuidprint();
107         if(arch->corehello)
108                 arch->corehello();
109
110         procinit0();
111         initseg();
112         timersinit();
113         links();
114         chandevreset();
115         pageinit();
116         swapinit();
117         savefpregs(&initfp);
118 initfp.fpstatus = 0x68028000;
119         userinit();
120         schedinit();
121 }
122
123 /* cpu->state bits */
124 enum {
125         Cpubootinprog   = 1,    /* boot in progress */
126         Cpucanrestart   = 2,    /* restart possible */
127         Cpuavail        = 4,    /* processor available */
128         Cpuexists       = 8,    /* processor present */
129         Cpuuserhalted   = 0x10, /* user halted */
130         Cpuctxtokay     = 0x20, /* context valid */
131         Cpupalokay      = 0x40, /* PALcode valid */
132         Cpupalmemokay   = 0x80, /* PALcode memory valid */
133         Cpupalloaded    = 0x100, /* PALcode loaded */
134         Cpuhaltmask     = 0xff0000, /* halt request mask */
135         Cpuhaltdflt     = 0,
136         Cpuhaltsaveexit = 0x10000,
137         Cpuhaltcoldboot = 0x20000,
138         Cpuhaltwarmboot = 0x30000,
139         Cpuhaltstayhalted = 0x40000,
140         Cpumustbezero = 0xffffffffff000000ULL,  /* 24:63 -- must be zero */
141 };
142
143 /*
144  *  initialize a processor's mach structure.  each processor does this
145  *  for itself.
146  */
147 void
148 machinit(void)
149 {
150         int n;
151         Hwcpu *cpu;
152
153         icflush();
154         n = m->machno;
155         memset(m, 0, sizeof(Mach));
156         m->machno = n;
157
158         active.exiting = 0;
159         active.machs = 1;
160
161         cpu = (Hwcpu*) ((ulong)hwrpb + hwrpb->cpuoff + n*hwrpb->cpulen);
162         cpu->state &= ~Cpubootinprog;
163         if (0)
164                 cpu->state |= Cpuhaltstayhalted;
165 }
166
167 void
168 init0(void)
169 {
170         int i;
171         char buf[2*KNAMELEN];
172
173         up->nerrlab = 0;
174
175         spllo();
176
177         /*
178          * These are o.k. because rootinit is null.
179          * Then early kproc's will have a root and dot.
180          */
181         up->slash = namec("#/", Atodir, 0, 0);
182         pathclose(up->slash->path);
183         up->slash->path = newpath("/");
184         up->dot = cclone(up->slash);
185
186         chandevinit();
187
188         if(!waserror()){
189                 snprint(buf, sizeof(buf), "alpha %s alphapc", conffile);
190                 ksetenv("terminal", buf, 0);
191                 ksetenv("cputype", "alpha", 0);
192                 if(cpuserver)
193                         ksetenv("service", "cpu", 0);
194                 else
195                         ksetenv("service", "terminal", 0);
196                 for(i = 0; i < nconf; i++)
197                         if(confname[i]){
198                                 if(confname[i][0] != '*')
199                                         ksetenv(confname[i], confval[i], 0);
200                                 ksetenv(confname[i], confval[i], 1);
201                         }
202                 poperror();
203         }
204
205         kproc("alarm", alarmkproc, 0);
206         touser((uchar*)(USTKTOP - sizeof(argbuf)));
207 }
208
209 void
210 userinit(void)
211 {
212         Proc *p;
213         Segment *s;
214         KMap *k;
215         char **av;
216         Page *pg;
217
218         p = newproc();
219         p->pgrp = newpgrp();
220         p->egrp = smalloc(sizeof(Egrp));
221         p->egrp->ref = 1;
222         p->fgrp = dupfgrp(nil);
223         p->rgrp = newrgrp();
224         p->procmode = 0640;
225
226         kstrdup(&eve, "");
227         kstrdup(&p->text, "*init*");
228         kstrdup(&p->user, eve);
229
230         procsetup(p);
231
232         /*
233          * Kernel Stack
234          */
235         p->sched.pc = (ulong)init0;
236         p->sched.sp = (ulong)p->kstack+KSTACK-MAXSYSARG*BY2WD;
237         /*
238          * User Stack, pass input arguments to boot process
239          */
240         s = newseg(SG_STACK, USTKTOP-USTKSIZE, USTKSIZE/BY2PG);
241         p->seg[SSEG] = s;
242         pg = newpage(1, 0, USTKTOP-BY2PG);
243         segpage(s, pg);
244         k = kmap(pg);
245         for(av = (char**)argbuf; *av; av++)
246                 *av += (USTKTOP - sizeof(argbuf)) - (ulong)argbuf;
247
248         memmove((uchar*)VA(k) + BY2PG - sizeof(argbuf), argbuf, sizeof argbuf);
249         kunmap(k);
250
251         /*
252          * Text
253          */
254         s = newseg(SG_TEXT, UTZERO, 1);
255         s->flushme++;
256         p->seg[TSEG] = s;
257         pg = newpage(1, 0, UTZERO);
258         memset(pg->cachectl, PG_TXTFLUSH, sizeof(pg->cachectl));
259         segpage(s, pg);
260         k = kmap(s->map[0]->pages[0]);
261         memmove((uchar*)VA(k), initcode, sizeof initcode);
262         kunmap(k);
263
264         ready(p);
265 }
266
267 void
268 procsetup(Proc *p)
269 {
270         p->fpstate = FPinit;
271         fpenab(0);
272 }
273
274 void
275 procfork(Proc *)
276 {
277 }
278
279 void
280 procsave(Proc *p)
281 {
282         if(p->fpstate == FPactive){
283                 if(p->state == Moribund)
284                         fpenab(0);
285                 else
286                         savefpregs(&up->fpsave);
287                 p->fpstate = FPinactive;
288         }
289
290         /*
291          * Switch to the prototype page tables for this processor.
292          * While this processor is in the scheduler, the process could run
293          * on another processor and exit, returning the page tables to
294          * the free list where they could be reallocated and overwritten.
295          * When this processor eventually has to get an entry from the
296          * trashed page tables it will crash.
297          */
298         mmupark();
299 }
300
301 void
302 setupboot(int halt)
303 {
304         int n = 0;              // cpu id of primary cpu, not just m->machno
305         Hwcpu *cpu = (Hwcpu*)((ulong)hwrpb + hwrpb->cpuoff + n*hwrpb->cpulen);
306
307         cpu->state &= ~(Cpucanrestart | Cpuhaltmask);
308         cpu->state |= (halt? Cpuhaltstayhalted: Cpuhaltwarmboot);
309 }
310
311 /* from ../pc */
312 static void
313 shutdown(int ispanic)
314 {
315         int ms, once;
316
317         lock(&active);
318         if(ispanic)
319                 active.ispanic = ispanic;
320         else if(m->machno == 0 && (active.machs & (1<<m->machno)) == 0)
321                 active.ispanic = 0;
322         once = active.machs & (1<<m->machno);
323         active.machs &= ~(1<<m->machno);
324         active.exiting = 1;
325         unlock(&active);
326
327         if(once)
328                 print("cpu%d: exiting\n", m->machno);
329         spllo();
330         for(ms = 5*1000; ms > 0; ms -= TK2MS(2)){
331                 delay(TK2MS(2));
332                 if(active.machs == 0 && consactive() == 0)
333                         break;
334         }
335
336         if(active.ispanic && m->machno == 0) {
337                 if(cpuserver)
338                         delay(10000);
339                 else
340                         for (;;)
341                                 continue;
342         } else
343                 delay(1000);
344 }
345
346 /* from ../pc: */
347 void
348 reboot(void *entry, void *code, ulong size)
349 {
350         // writeconf();         // pass kernel environment to next kernel
351         shutdown(0);
352
353         /*
354          * should be the only processor running now
355          */
356         print("shutting down...\n");
357         delay(200);
358
359         splhi();
360
361         /* turn off buffered serial console */
362         serialoq = nil;
363
364         /* shutdown devices */
365         chandevshutdown();
366
367 #ifdef FUTURE
368 {
369         ulong *pdb;
370         /*
371          * Modify the machine page table to directly map the low 4MB of memory
372          * This allows the reboot code to turn off the page mapping
373          */
374         pdb = m->pdb;
375         pdb[PDX(0)] = pdb[PDX(KZERO)];
376         mmuflushtlb(PADDR(pdb));
377 }
378         /* setup reboot trampoline function */
379 {
380         void (*f)(ulong, ulong, ulong) = (void*)REBOOTADDR;
381
382         memmove(f, rebootcode, sizeof(rebootcode));
383 #else
384         USED(entry, code, size);
385 #endif
386
387         print("rebooting...\n");
388 #ifdef FUTURE
389         /* off we go - never to return */
390         (*f)(PADDR(entry), PADDR(code), size);
391 }
392 #endif
393         setupboot(0);           // reboot, don't halt
394         exit(0);
395 }
396
397 void
398 exit(int ispanic)
399 {
400         canlock(&active);
401         active.machs &= ~(1<<m->machno);
402         active.exiting = 1;
403         unlock(&active);
404
405         spllo();
406         print("cpu %d exiting\n", m->machno);
407         do
408                 delay(100);
409         while(consactive());
410
411         splhi();
412         delay(1000);    /* give serial fifo time to finish flushing */
413         if (getconf("*debug") != nil) {
414                 USED(ispanic);
415                 delay(60*1000);         /* give us time to read the screen */
416         }
417         if(arch->coredetach)
418                 arch->coredetach();
419         setupboot(1);                   // set up to halt
420         for (; ; )
421                 firmware();
422
423         // on PC is just:
424         //if (0) {
425         //      shutdown(ispanic);
426         //      arch->reset();
427         //}
428 }
429
430 void
431 confinit(void)
432 {
433         ulong ktop, kpages;
434         Bank *b, *eb;
435         extern void _main(void);
436         int userpcnt;
437         char *p;
438
439         if(p = getconf("*kernelpercent"))
440                 userpcnt = 100 - strtol(p, 0, 0);
441         else
442                 userpcnt = 0;
443
444         /*
445          * The console firmware divides memory into 1 or more banks.
446          * FInd the bank with the kernel in it.
447          */
448         b = bootconf->bank;
449         eb = b+bootconf->nbank;
450         ktop = PGROUND((ulong)end);
451         ktop = PADDR(ktop);
452         while(b < eb) {
453                 if(b->min < ktop && ktop < b->max)
454                         break;
455                 b++;
456         }
457         if(b == eb)
458                 panic("confinit");
459
460         /*
461          * Split the bank of memory into 2 banks to fool the allocator into
462          * allocating low memory pages from bank 0 for any peripherals
463          * which only have a 24bit address counter.
464          */
465         conf.mem[0].npage = (8*1024*1024)/BY2PG;
466         conf.mem[0].base = 0;
467
468         conf.mem[1].npage = (b->max-8*1024*1024)/BY2PG;
469         conf.mem[1].base = 8*1024*1024;
470
471         conf.npage = conf.mem[0].npage+conf.mem[1].npage;
472         conf.upages = (conf.npage*70)/100;
473
474         conf.mem[0].npage -= ktop/BY2PG;
475         conf.mem[0].base += ktop;
476         conf.ialloc = ((conf.npage-conf.upages)/2)*BY2PG;
477
478         /*
479          * Fix up the bank we found to be the remnant, below the kernel.
480          * This, and the other banks, will be passed to xhole() later.
481          * BUG: conf.upages needs to be adjusted, but how?  In practice,
482          * we only have 1 bank, and the remnant is small.
483          */
484         b->max = (uvlong)_main & ~(BY2PG-1);
485
486         conf.nmach = 1;
487         conf.nproc = 100 + ((conf.npage*BY2PG)/MB)*5;
488         if(cpuserver)
489                 conf.nproc *= 3;
490         if(conf.nproc > 2000)
491                 conf.nproc = 2000;
492         conf.nimage = 200;
493         conf.nswap = conf.nproc*80;
494         conf.nswppo = 4096;
495         conf.copymode = 0;                      /* copy on write */
496
497         if(cpuserver) {
498                 if(userpcnt < 10)
499                         userpcnt = 70;
500                 kpages = conf.npage - (conf.npage*userpcnt)/100;
501
502                 /*
503                  * Hack for the big boys. Only good while physmem < 4GB.
504                  * Give the kernel a max. of 16MB + enough to allocate the
505                  * page pool.
506                  * This is an overestimate as conf.upages < conf.npages.
507                  * The patch of nimage is a band-aid, scanning the whole
508                  * page list in imagereclaim just takes too long.
509                  */
510                 if(kpages > (16*MB + conf.npage*sizeof(Page))/BY2PG){
511                         kpages = (16*MB + conf.npage*sizeof(Page))/BY2PG;
512                         conf.nimage = 2000;
513                         kpages += (conf.nproc*KSTACK)/BY2PG;
514                 }
515         } else {
516                 if(userpcnt < 10) {
517                         if(conf.npage*BY2PG < 16*MB)
518                                 userpcnt = 40;
519                         else
520                                 userpcnt = 60;
521                 }
522                 kpages = conf.npage - (conf.npage*userpcnt)/100;
523
524                 /*
525                  * Make sure terminals with low memory get at least
526                  * 4MB on the first Image chunk allocation.
527                  */
528                 if(conf.npage*BY2PG < 16*MB)
529                         imagmem->minarena = 4*1024*1024;
530         }
531         conf.upages = conf.npage - kpages;
532         conf.ialloc = (kpages/2)*BY2PG;
533
534         /*
535          * Guess how much is taken by the large permanent
536          * datastructures. Mntcache and Mntrpc are not accounted for
537          * (probably ~300KB).
538          */
539         kpages *= BY2PG;
540         kpages -= conf.upages*sizeof(Page)
541                 + conf.nproc*sizeof(Proc)
542                 + conf.nimage*sizeof(Image)
543                 + conf.nswap
544                 + conf.nswppo*sizeof(Page*);
545         mainmem->maxsize = kpages;
546         if(!cpuserver){
547                 /*
548                  * give terminals lots of image memory, too; the dynamic
549                  * allocation will balance the load properly, hopefully.
550                  * be careful with 32-bit overflow.
551                  */
552                 imagmem->maxsize = kpages;
553         }
554
555 //      conf.monitor = 1;       /* BUG */
556 }
557
558 void
559 memholes(void)
560 {
561         Bank *b, *eb;
562
563         b = bootconf->bank;
564         eb = b+bootconf->nbank;
565         while(b < eb) {
566                 if(b->min < (1LL<<32) && b->max < (1LL<<32))
567                         xhole(b->min, b->max-b->min);
568                 b++;
569         }
570 }
571
572 char *sp;
573
574 char *
575 pusharg(char *p)
576 {
577         int n;
578
579         n = strlen(p)+1;
580         sp -= n;
581         memmove(sp, p, n);
582         return sp;
583 }
584
585 void
586 arginit(void)
587 {
588         char **av;
589
590         av = (char**)argbuf;
591         sp = argbuf + sizeof(argbuf);
592         *av++ = pusharg("boot");
593         *av = 0;
594 }
595
596 char *
597 getconf(char *name)
598 {
599         int n;
600
601         for(n = 0; n < nconf; n++)
602                 if(cistrcmp(confname[n], name) == 0) {
603                         return confval[n];
604                 }
605         return 0;
606 }
607
608 int
609 isaconfig(char *class, int ctlrno, ISAConf *isa)
610 {
611         char cc[32], *p;
612         int i, n;
613
614         snprint(cc, sizeof cc, "%s%d", class, ctlrno);
615         for(n = 0; n < nconf; n++){
616                 if(cistrcmp(confname[n], cc) != 0)
617                         continue;
618                 isa->nopt = tokenize(confval[n], isa->opt, NISAOPT);
619                 for(i = 0; i < isa->nopt; i++){
620                         p = isa->opt[i];
621                         if(cistrncmp(p, "type=", 5) == 0)
622                                 isa->type = p + 5;
623                         else if(cistrncmp(p, "port=", 5) == 0)
624                                 isa->port = strtoul(p+5, &p, 0);
625                         else if(cistrncmp(p, "irq=", 4) == 0)
626                                 isa->irq = strtoul(p+4, &p, 0);
627                         else if(cistrncmp(p, "dma=", 4) == 0)
628                                 isa->dma = strtoul(p+4, &p, 0);
629                         else if(cistrncmp(p, "mem=", 4) == 0)
630                                 isa->mem = strtoul(p+4, &p, 0);
631                         else if(cistrncmp(p, "size=", 5) == 0)
632                                 isa->size = strtoul(p+5, &p, 0);
633                         else if(cistrncmp(p, "freq=", 5) == 0)
634                                 isa->freq = strtoul(p+5, &p, 0);
635                 }
636                 return 1;
637         }
638         return 0;
639 }
640
641 int
642 cistrcmp(char *a, char *b)
643 {
644         int ac, bc;
645
646         for(;;){
647                 ac = *a++;
648                 bc = *b++;
649
650                 if(ac >= 'A' && ac <= 'Z')
651                         ac = 'a' + (ac - 'A');
652                 if(bc >= 'A' && bc <= 'Z')
653                         bc = 'a' + (bc - 'A');
654                 ac -= bc;
655                 if(ac)
656                         return ac;
657                 if(bc == 0)
658                         break;
659         }
660         return 0;
661 }
662
663 int
664 cistrncmp(char *a, char *b, int n)
665 {
666         unsigned ac, bc;
667
668         while(n > 0){
669                 ac = *a++;
670                 bc = *b++;
671                 n--;
672
673                 if(ac >= 'A' && ac <= 'Z')
674                         ac = 'a' + (ac - 'A');
675                 if(bc >= 'A' && bc <= 'Z')
676                         bc = 'a' + (bc - 'A');
677
678                 ac -= bc;
679                 if(ac)
680                         return ac;
681                 if(bc == 0)
682                         break;
683         }
684
685         return 0;
686 }
687
688 int
689 getcfields(char* lp, char** fields, int n, char* sep)
690 {
691         int i;
692
693         for(i = 0; lp && *lp && i < n; i++){
694                 while(*lp && strchr(sep, *lp) != 0)
695                         *lp++ = 0;
696                 if(*lp == 0)
697                         break;
698                 fields[i] = lp;
699                 while(*lp && strchr(sep, *lp) == 0){
700                         if(*lp == '\\' && *(lp+1) == '\n')
701                                 *lp++ = ' ';
702                         lp++;
703                 }
704         }
705
706         return i;
707 }