xref: /plan9-contrib/sys/src/boot/vt4/load.c (revision da917039c7f233c1a27d212bf012c6afa758af39)
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