1 #include "include.h"
2 #include "fs.h"
3
4 enum {
5 Dontprint,
6 Print,
7
8 Datamagic = 0xfacebabe,
9 };
10
11 int securemem;
12
13 static char *etherparts[] = { "*", 0 };
14 static char *etherinis[] = {
15 "/cfg/pxe/%E",
16 0
17 };
18
19 Type types[] = {
20 { Tether,
21 Fini|Fbootp,
22 etherinit, etherinitdev,
23 pxegetfspart, 0, bootpboot,
24 etherprintdevs,
25 etherparts,
26 etherinis,
27 },
28 };
29
30 static char *typenm[] = {
31 [Tether] "ether",
32 };
33
34 typedef struct Mode Mode;
35
36 enum {
37 Dany = -1,
38 Nmedia = 2, /* size reduction; was 16 */
39 };
40
41 enum { /* mode */
42 Mauto,
43 Mlocal,
44 Manual,
45 NMode,
46 };
47
48 typedef struct Medium Medium;
49 struct Medium {
50 Type* type;
51 ushort flag;
52 ushort dev;
53 char name[NAMELEN];
54
55 Fs *inifs;
56 char *part;
57 char *ini;
58
59 Medium* next;
60 };
61
62 typedef struct Mode {
63 char* name;
64 ushort mode;
65 } Mode;
66
67 extern char bdata[], edata[], end[], etext[];
68
69 static Medium media[Nmedia];
70 static Medium *curmedium = media;
71
72 static Mode modes[NMode+1] = {
73 [Mauto] { "auto", Mauto, },
74 [Mlocal] { "local", Mlocal, },
75 [Manual] { "manual", Manual, },
76 };
77
78 Mach* machptr[MAXMACH];
79
80 ulong cpuentry = 0;
81
82 char **ini;
83 char *defaultpartition;
84 char *persist;
85
86 int debugload;
87 int iniread;
88 int pxe = 1;
89 int scsi0port;
90 int vga;
91
92 uintptr memstart; /* set before main called */
93 uintptr vectorbase; /* set before main called */
94
95 static uintptr memsz;
96
97 static Medium*
parse(char * line,char ** file)98 parse(char *line, char **file)
99 {
100 char *p;
101 Type *tp;
102 Medium *mp;
103
104 if(p = strchr(line, '!')) {
105 *p++ = 0;
106 *file = p;
107 } else
108 *file = "";
109
110 tp = types;
111 for(mp = tp->media; mp; mp = mp->next)
112 if(strcmp(mp->name, line) == 0)
113 return mp;
114 if(p)
115 *--p = '!';
116 return nil;
117 }
118
119 static int
boot(Medium * mp,char * file)120 boot(Medium *mp, char *file)
121 {
122 Type *tp;
123 Medium *xmp;
124 static int didaddconf;
125 Boot b;
126
127 memset(&b, 0, sizeof b);
128 b.state = INITKERNEL;
129
130 if(didaddconf == 0) {
131 didaddconf = 1;
132 tp = types;
133 if(tp->addconf)
134 for(xmp = tp->media; xmp; xmp = xmp->next)
135 (*tp->addconf)(xmp->dev);
136 }
137
138 seprint(BOOTLINE, BOOTLINE + BOOTLINELEN, "%s!%s", mp->name, file);
139 print("booting %s!%s\n", mp->name, file);
140 return (*mp->type->boot)(mp->dev, file, &b);
141 }
142
143 static Medium*
allocm(Type * tp)144 allocm(Type *tp)
145 {
146 Medium **l;
147
148 if(curmedium >= &media[Nmedia])
149 return 0;
150
151 for(l = &tp->media; *l; l = &(*l)->next)
152 ;
153 *l = curmedium++;
154 return *l;
155 }
156
157 Medium*
probe(int type,int flag,int dev)158 probe(int type, int flag, int dev)
159 {
160 Type *tp;
161 int i;
162 Medium *mp;
163 File f;
164 Fs *fs;
165 char **partp;
166
167 tp = types;
168 if(type != Tany && type != tp->type)
169 return 0;
170
171 if(flag != Fnone)
172 for(mp = tp->media; mp; mp = mp->next)
173 if((flag & mp->flag) && (dev == Dany || dev == mp->dev))
174 return mp;
175 if((tp->flag & Fprobe) == 0){
176 tp->flag |= Fprobe;
177 tp->mask = (*tp->init)();
178 }
179
180 for(i = 0; tp->mask; i++){
181 if((tp->mask & (1<<i)) == 0)
182 continue;
183 tp->mask &= ~(1<<i);
184
185 if((mp = allocm(tp)) == 0)
186 continue;
187
188 mp->dev = i;
189 mp->flag = tp->flag;
190 mp->type = tp;
191 (*tp->initdev)(i, mp->name);
192
193 if(mp->flag & Fini){
194 mp->flag &= ~Fini;
195 for(partp = tp->parts; *partp; partp++){
196 if((fs = (*tp->getfspart)(i, *partp, 0)) == nil)
197 continue;
198
199 for(ini = tp->inis; *ini; ini++)
200 if(fswalk(fs, *ini, &f) > 0){
201 mp->inifs = fs;
202 mp->part = *partp;
203 mp->ini = f.path;
204 mp->flag |= Fini;
205 goto Break2;
206 }
207 }
208 }
209 Break2:
210 if((flag & mp->flag) && (dev == Dany || dev == i))
211 return mp;
212 }
213 return 0;
214 }
215
216 enum {
217 Kilo = 1024,
218 };
219
220 /* make sure we don't get the write system call from libc */
221 long
write(int fd,void * buf,long nbytes)222 write(int fd, void *buf, long nbytes)
223 {
224 USED(fd);
225 vuartputs(buf, nbytes);
226 return nbytes;
227 }
228
229 /*
230 * write zero words to an entire cache line (the one containing addr).
231 * does not flush the data cache.
232 */
233 void
cacheline0(uintptr addr)234 cacheline0(uintptr addr)
235 {
236 ulong *sp, *endmem;
237
238 addr &= ~(DCACHELINESZ - 1);
239 endmem = (ulong *)(addr + DCACHELINESZ);
240 for (sp = (ulong *)addr; sp < endmem; sp++)
241 *sp = 0;
242 // coherence();
243 }
244
245 /* force the four qtm write buffers to be retired to dram by filling them. */
246 void
flushwrbufs(void)247 flushwrbufs(void)
248 {
249 if (!securemem)
250 return;
251 cacheline0(PHYSDRAM);
252 cacheline0(PHYSDRAM + DCACHELINESZ);
253 cacheline0(PHYSDRAM + 2*DCACHELINESZ);
254 cacheline0(PHYSDRAM + 3*DCACHELINESZ);
255 coherence();
256 }
257
258 static void
vfyzeros(ulong * addr,ulong * end)259 vfyzeros(ulong *addr, ulong *end)
260 {
261 ulong wd;
262 ulong *sp;
263
264 for (sp = addr; sp < end; sp++) {
265 wd = *sp;
266 if (wd != 0) {
267 PROG('?')
268 panic("bad dram: %#p read back as %#lux not 0", sp, wd);
269 }
270 }
271 }
272
273 static int
memreset(void)274 memreset(void)
275 {
276 int i, cnt;
277 uintptr addr, endmem;
278
279 cnt = 0;
280 if (securemem)
281 cnt = qtmmemreset();
282 else
283 /* normal dram init. should take 100—250 ms. */
284 for (i = 10*1000*1000; i-- > 0; )
285 cnt++;
286 PROG('t')
287 /*
288 * dram must be done initialising now,
289 * but qtm needs us to zero it *all* before any other use,
290 * to set the macs. even for non-qtm dram, it might be wise
291 * to ensure that all the ecc bits are set.
292 */
293 memsz = memsize(); /* may carefully probe qtm dram */
294 qtmerrtest("sizing memory");
295
296 dcflush(PHYSSRAM, (1ULL << 32) - PHYSSRAM);
297 cachesinvalidate();
298
299 endmem = PHYSDRAM + memsz;
300 for (addr = PHYSDRAM; addr < endmem; addr += DCACHELINESZ) {
301 cacheline0(addr);
302 qtmerrtestaddr(addr);
303 }
304 assert(addr == endmem);
305 coherence();
306 flushwrbufs();
307 qtmerrtest("zeroing dram");
308
309 #ifdef PARANOID
310 vfyzeros((ulong *)PHYSDRAM, (ulong *)endmem);
311 #else
312 vfyzeros((ulong *)(endmem - MB), (ulong *)endmem);
313 #endif
314 dcflush(PHYSDRAM, memsz);
315 dcflush(PHYSSRAM, (1ULL << 32) - PHYSSRAM);
316 cachesinvalidate();
317
318 /*
319 * Hallelujah! We can finally treat qtm dram just like real memory,
320 * except that the last (partial) page is funny and should be avoided
321 * after initialising it.
322 * It happens even with caches off, so it's a bit hard to explain
323 * why it should be funny.
324 */
325 memsz &= ~(BY2PG - 1);
326 endmem = PHYSDRAM + memsz;
327
328 #ifdef PARANOID
329 vfyzeros((ulong *)PHYSDRAM, (ulong *)endmem);
330 #else
331 vfyzeros((ulong *)PHYSDRAM, (ulong *)(PHYSDRAM + MB));
332 vfyzeros((ulong *)(endmem - MB), (ulong *)endmem);
333 #endif
334 qtmerrtest("reading back dram");
335 return cnt;
336 }
337
338 static void
memtest(void)339 memtest(void)
340 {
341 ulong wd;
342 ulong *sp, *endmem;
343
344 /*
345 * verify that (possibly secure) dram is more or less working.
346 * write address of each word into that word.
347 */
348 #ifdef PARANOID
349 endmem = (ulong *)(PHYSDRAM + memsz);
350 #else
351 endmem = (ulong *)(PHYSDRAM + MB); /* just the first MB */
352 #endif
353 for (sp = (ulong *)PHYSDRAM; sp < endmem; sp++)
354 *sp = (ulong)sp;
355 coherence();
356 /* no need to flush caches, caches are off */
357
358 /*
359 * now verify that each word contains its address.
360 */
361 for (sp = (ulong *)PHYSDRAM; sp < endmem; sp++) {
362 wd = *sp;
363 if (wd != (ulong)sp) {
364 PROG('?')
365 panic("bad dram: %#p read back as %#lux", sp, wd);
366 }
367 }
368 PROG('t')
369 /* memset((void *)PHYSDRAM, 0, memsz); /* good hygiene? */
370 }
371
372 enum {
373 Testbase = PHYSDRAM + 0x4000,
374 };
375
376 void
meminit(void)377 meminit(void)
378 {
379 int i;
380 uchar *memc;
381 ulong *mem;
382
383 // iprint("sanity: writing...");
384 mem = (ulong *)Testbase;
385 memc = (uchar *)Testbase;
386
387 memset(mem, 0252, Kilo);
388 coherence();
389 dcflush(Testbase, Kilo);
390
391 // iprint("reading...");
392 for (i = 0; i < Kilo; i++)
393 if (memc[i] != 0252)
394 panic("dram not retaining data");
395
396 // iprint("zeroing...");
397 memset(mem, '\0', Kilo);
398 coherence();
399 dcflush(Testbase, Kilo);
400 if (*mem)
401 panic("zeroed dram not zero");
402 // iprint("\n");
403 }
404
405 static int idx;
406 static char numb[32];
407
408 static void
gendigs(ulong n)409 gendigs(ulong n)
410 {
411 int dig;
412
413 do {
414 dig = n % 16;
415 if (dig > 9)
416 numb[idx--] = 'A' + dig - 10;
417 else
418 numb[idx--] = '0' + dig;
419 } while ((n /= 16) > 0);
420 }
421
422 static void
prnum(ulong n)423 prnum(ulong n)
424 {
425 // PROG(' ')
426 idx = nelem(numb) - 1;
427 gendigs(n);
428 for (; idx < nelem(numb); idx++)
429 PROG(numb[idx])
430 PROG('\n')
431 PROG('\r')
432 }
433
434 extern uintptr vectorbase;
435
436 void
main(void)437 main(void)
438 {
439 int flag, i, j, mode, tried;
440 char def[2*NAMELEN], line[80], *p, *file;
441 Medium *mp;
442 Type *tp;
443 static int savcnt, caching;
444 static ulong vfy = Datamagic;
445
446 /*
447 * all cpus start executing at reset address, thus start of sram.
448 * cpu0 loads the kernel;
449 * all others just jump to the (by now) loaded kernel.
450 */
451 /* "\r\nPlan " already printed by l.s */
452 if (getpir() != 0) {
453 for (j = 0; j < 6; j++)
454 for (i = 2*1000*1000*1000; i > 0; i--)
455 ;
456
457 cachesinvalidate();
458 while(cpuentry == 0)
459 cachesinvalidate();
460
461 for (j = 0; j < 6; j++)
462 for (i = 2*1000*1000*1000; i > 0; i--)
463 ;
464 warp9(PADDR(cpuentry));
465 }
466
467 /*
468 * we may have to realign the data segment; apparently ql -R4096
469 * does not pad the text segment.
470 */
471 if (vfy != Datamagic)
472 memmove(bdata, etext, edata - bdata);
473 if (vfy != Datamagic) {
474 PROG('?')
475 panic("misaligned data segment");
476 }
477 // memset(edata, 0, end - edata); /* zero bss */
478
479 PROG('9')
480 /*
481 * trap vectors are in sram, so we don't have to wait for dram
482 * to become ready to initialise them.
483 */
484 trapinit();
485 PROG(' ')
486 securemem = (probeaddr(Qtm) >= 0);
487 if (securemem)
488 PROG('q')
489 else
490 PROG('n')
491 PROG(' ')
492
493 /*
494 * the stack is now at top of sram, and entry to main just pushed
495 * stuff onto it. the new stack will be at the top of dram,
496 * when dram finishes initialising itself.
497 */
498 PROG('B')
499 PROG('o')
500 PROG('o')
501 /* do voodoo to make dram usable; prints "t". sets memsz. */
502 savcnt = memreset();
503 PROG('s')
504 memtest(); /* also prints "t" */
505 intrinit();
506
507 caching = cacheson();
508
509 /*
510 * switch to the dram stack just below the end of dram.
511 * have to allow enough room for main's local variables,
512 * to avoid address faults.
513 */
514
515 PROG('r')
516 setsp(memsz - BY2PG);
517
518 PROG('a')
519 meminit();
520 /* memory is now more or less normal from a software perspective. */
521
522 memset(m, 0, sizeof(Mach));
523 m->machno = 0;
524 m->up = nil;
525 MACHP(0) = m;
526
527 /*
528 * the Mach struct is now initialised, so we can print safely.
529 */
530
531 // print("\nPlan 9 bootstrap"); /* already printed, 1 char at a time */
532 print("p");
533 // print("\n%d iterations waiting for %s init done\n",
534 // savcnt, (securemem? "qtm": "dram"));
535 if (securemem)
536 print("; secure memory");
537 print("; caches %s\n", (caching? "on": "off"));
538 print("\n");
539 if ((uintptr)end < PHYSSRAM)
540 panic("too big; end %#p before sram @ %#ux", end, PHYSSRAM);
541 print("memory found: %,lud (%lux)\n", memsz, memsz);
542
543 spllo();
544 clockinit();
545 prcpuid();
546 // etherinit(); /* probe() calls this */
547 kbdinit();
548
549 /*
550 * find and read plan9.ini, setting configuration variables.
551 */
552 tp = types;
553 // debug = debugload = 1; // DEBUG
554 if(pxe && (mp = probe(tp->type, Fini, Dany)) && mp->flag & Fini){
555 if (debug)
556 print("using %s!%s!%s\n", mp->name, mp->part, mp->ini);
557 // iniread = !dotini(mp->inifs);
558 }
559
560 /*
561 * we should now have read plan9.ini, if any.
562 */
563 persist = getconf("*bootppersist");
564
565 tried = 0;
566 mode = Mauto;
567
568 p = getconf("bootfile");
569 if(p != 0) {
570 mode = Manual;
571 for(i = 0; i < NMode; i++){
572 if(strcmp(p, modes[i].name) == 0){
573 mode = modes[i].mode;
574 goto done;
575 }
576 }
577 if((mp = parse(p, &file)) == nil)
578 print("Unknown boot device: %s\n", p);
579 else
580 tried = boot(mp, file);
581 }
582 done:
583 if(tried == 0 && mode != Manual){
584 flag = Fany;
585 if(mode == Mlocal)
586 flag &= ~Fbootp;
587 if((mp = probe(Tany, flag, Dany)))
588 boot(mp, "");
589 if (debugload)
590 print("end auto probe\n");
591 }
592
593 def[0] = 0;
594 if(p = getconf("bootdef"))
595 strecpy(def, def + sizeof def, p);
596 flag = 0;
597 tp = types;
598 for(mp = tp->media; mp; mp = mp->next){
599 if(flag == 0){
600 flag = 1;
601 print("Boot devices:");
602 }
603 (*tp->printdevs)(mp->dev);
604 }
605 if(flag)
606 print("\n");
607
608 /*
609 * e.g., *bootppersist=ether0
610 *
611 * previously, we looped in bootpopen if we were pxeload or if
612 * *bootppersist was set. that doesn't work well for pxeload where
613 * bootp will never succeed on the first interface but only on another
614 * interface.
615 */
616 //print("boot mode %s\n", modes[mode].name);
617 if (mode == Mauto && persist != nil &&
618 (mp = parse(persist, &file)) != nil) {
619 boot(mp, file);
620 print("pausing before retry...");
621 delay(30*1000);
622 print("\n");
623 }
624
625 for(;;){
626 if(getstr("boot from", line, sizeof(line), def,
627 (mode != Manual)*15) >= 0)
628 if(mp = parse(line, &file))
629 boot(mp, file);
630 def[0] = 0;
631 }
632 }
633
634 int
getfields(char * lp,char ** fields,int n,char sep)635 getfields(char *lp, char **fields, int n, char sep)
636 {
637 int i;
638
639 for(i = 0; lp && *lp && i < n; i++){
640 while(*lp == sep)
641 *lp++ = 0;
642 if(*lp == 0)
643 break;
644 fields[i] = lp;
645 while(*lp && *lp != sep){
646 if(*lp == '\\' && *(lp+1) == '\n')
647 *lp++ = ' ';
648 lp++;
649 }
650 }
651 return i;
652 }
653
654 int
cistrcmp(char * a,char * b)655 cistrcmp(char *a, char *b)
656 {
657 int ac, bc;
658
659 for(;;){
660 ac = *a++;
661 bc = *b++;
662
663 if(ac >= 'A' && ac <= 'Z')
664 ac = 'a' + (ac - 'A');
665 if(bc >= 'A' && bc <= 'Z')
666 bc = 'a' + (bc - 'A');
667 ac -= bc;
668 if(ac)
669 return ac;
670 if(bc == 0)
671 break;
672 }
673 return 0;
674 }
675
676 int
cistrncmp(char * a,char * b,int n)677 cistrncmp(char *a, char *b, int n)
678 {
679 unsigned ac, bc;
680
681 while(n > 0){
682 ac = *a++;
683 bc = *b++;
684 n--;
685
686 if(ac >= 'A' && ac <= 'Z')
687 ac = 'a' + (ac - 'A');
688 if(bc >= 'A' && bc <= 'Z')
689 bc = 'a' + (bc - 'A');
690
691 ac -= bc;
692 if(ac)
693 return ac;
694 if(bc == 0)
695 break;
696 }
697
698 return 0;
699 }
700
701 #define PSTART (8*MB) /* start allocating here */
702 #define PEND (100*MB) /* below stack */
703
704 static ulong palloc = PSTART;
705
706 void*
ialloc(ulong n,int align)707 ialloc(ulong n, int align)
708 {
709 ulong p;
710 int a;
711
712 assert(palloc >= PSTART);
713 p = palloc;
714 if(align <= 0)
715 align = 4;
716 if(a = n % align)
717 n += align - a;
718 if(a = p % align)
719 p += align - a;
720
721 palloc = p+n;
722 if(palloc > PEND)
723 panic("ialloc(%lud, %d) called from %#p",
724 n, align, getcallerpc(&n));
725 return memset((void*)p, 0, n);
726 }
727
728 void*
xspanalloc(ulong size,int align,ulong span)729 xspanalloc(ulong size, int align, ulong span)
730 {
731 ulong a, v;
732
733 if((palloc + (size+align+span)) > PEND)
734 panic("xspanalloc(%lud, %d, 0x%lux) called from %#p",
735 size, align, span, getcallerpc(&size));
736
737 a = (ulong)ialloc(size+align+span, 0);
738
739 if(span > 2)
740 v = (a + span) & ~(span-1);
741 else
742 v = a;
743
744 if(align > 1)
745 v = (v + align) & ~(align-1);
746
747 return (void*)v;
748 }
749
750 static Block *allocbp;
751
752 Block*
allocb(int size)753 allocb(int size)
754 {
755 Block *bp, **lbp;
756 ulong addr;
757
758 lbp = &allocbp;
759 for(bp = *lbp; bp; bp = bp->next){
760 if((bp->lim - bp->base) >= size){
761 *lbp = bp->next;
762 break;
763 }
764 lbp = &bp->next;
765 }
766 if(bp == 0){
767 if((palloc + (sizeof(Block)+size+64)) > PEND)
768 panic("allocb(%d) called from %#p",
769 size, getcallerpc(&size));
770 bp = ialloc(sizeof(Block)+size+64, 0);
771 addr = (ulong)bp;
772 addr = ROUNDUP(addr + sizeof(Block), 8);
773 bp->base = (uchar*)addr;
774 bp->lim = ((uchar*)bp) + sizeof(Block)+size+64;
775 }
776
777 if(bp->flag)
778 panic("allocb reuse");
779
780 bp->rp = bp->base;
781 bp->wp = bp->rp;
782 bp->next = 0;
783 bp->flag = 1;
784
785 return bp;
786 }
787
788 void
freeb(Block * bp)789 freeb(Block* bp)
790 {
791 bp->next = allocbp;
792 allocbp = bp;
793
794 bp->flag = 0;
795 }
796
797 void (*etherdetach)(void);
798
799 void
warp9(ulong entry)800 warp9(ulong entry)
801 {
802 ulong inst;
803 ulong *mem;
804
805 if(etherdetach)
806 etherdetach();
807 // consdrain();
808 delay(10);
809
810 splhi();
811 trapdisable();
812 coherence();
813 syncall();
814
815 qtmerrtest("syncs before kernel entry");
816 syncall();
817 putmsr(getmsr() & ~MSR_ME); /* disable machine check traps */
818 syncall();
819 clrmchk();
820 syncall();
821
822 mem = (ulong *)PADDR(entry);
823 inst = *mem;
824 if (inst == 0)
825 panic("word at entry addr is zero, kernel not loaded");
826 /*
827 * This is where to push things on the stack to
828 * boot *BSD systems, e.g.
829 * (*((void (*)(void*, void*, void*, void*, ulong, ulong))PADDR(entry)))
830 * (0, 0, 0, 0, 8196, 640);
831 * will enable NetBSD boot (the real memory size needs to
832 * go in the 5th argument).
833 */
834 coherence();
835 syncall();
836 (*(void (*)(void))mem)();
837
838 for (;;)
839 ;
840 }
841