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