xref: /plan9/sys/src/9/pcboot/bootld.c (revision 62579e3431b49107da5aa4bf80b65c6650de497d)
1 /*
2  * load kernel into memory
3  */
4 #include	"u.h"
5 #include	"../port/lib.h"
6 #include	"mem.h"
7 #include	"dat.h"
8 #include	"fns.h"
9 #include	"io.h"
10 #include	"ureg.h"
11 #include	"pool.h"
12 #include	"../port/netif.h"
13 #include	"../ip/ip.h"
14 #include	"pxe.h"
15 
16 #include	<a.out.h>
17 #include 	"/sys/src/libmach/elf.h"
18 
19 #undef KADDR
20 #undef PADDR
21 
22 #define KADDR(a)	((void*)((ulong)(a) | KZERO))
23 #define PADDR(a)	((ulong)(a) & ~KSEGM)
24 
25 extern int debug;
26 
27 extern void pagingoff(ulong);
28 
29 static uchar elfident[] = {
30 	'\177', 'E', 'L', 'F',
31 };
32 static Ehdr ehdr, rehdr;
33 static E64hdr e64hdr;
34 static Phdr *phdr;
35 static P64hdr *p64hdr;
36 
37 static int curphdr;
38 static ulong curoff;
39 static ulong elftotal;
40 
41 static uvlong (*swav)(uvlong);
42 static long (*swal)(long);
43 static ushort (*swab)(ushort);
44 
45 /*
46  * big-endian short
47  */
48 ushort
beswab(ushort s)49 beswab(ushort s)
50 {
51 	uchar *p;
52 
53 	p = (uchar*)&s;
54 	return (p[0]<<8) | p[1];
55 }
56 
57 /*
58  * big-endian long
59  */
60 long
beswal(long l)61 beswal(long l)
62 {
63 	uchar *p;
64 
65 	p = (uchar*)&l;
66 	return (p[0]<<24) | (p[1]<<16) | (p[2]<<8) | p[3];
67 }
68 
69 /*
70  * big-endian vlong
71  */
72 uvlong
beswav(uvlong v)73 beswav(uvlong v)
74 {
75 	uchar *p;
76 
77 	p = (uchar*)&v;
78 	return ((uvlong)p[0]<<56) | ((uvlong)p[1]<<48) | ((uvlong)p[2]<<40)
79 				  | ((uvlong)p[3]<<32) | ((uvlong)p[4]<<24)
80 				  | ((uvlong)p[5]<<16) | ((uvlong)p[6]<<8)
81 				  | (uvlong)p[7];
82 }
83 
84 /*
85  * little-endian short
86  */
87 ushort
leswab(ushort s)88 leswab(ushort s)
89 {
90 	uchar *p;
91 
92 	p = (uchar*)&s;
93 	return (p[1]<<8) | p[0];
94 }
95 
96 /*
97  * little-endian long
98  */
99 long
leswal(long l)100 leswal(long l)
101 {
102 	uchar *p;
103 
104 	p = (uchar*)&l;
105 	return (p[3]<<24) | (p[2]<<16) | (p[1]<<8) | p[0];
106 }
107 
108 /*
109  * little-endian vlong
110  */
111 uvlong
leswav(uvlong v)112 leswav(uvlong v)
113 {
114 	uchar *p;
115 
116 	p = (uchar*)&v;
117 	return ((uvlong)p[7]<<56) | ((uvlong)p[6]<<48) | ((uvlong)p[5]<<40)
118 				  | ((uvlong)p[4]<<32) | ((uvlong)p[3]<<24)
119 				  | ((uvlong)p[2]<<16) | ((uvlong)p[1]<<8)
120 				  | (uvlong)p[0];
121 }
122 
123 /*
124  * Convert header to canonical form
125  */
126 static void
hswal(long * lp,int n,long (* swap)(long))127 hswal(long *lp, int n, long (*swap) (long))
128 {
129 	while (n--) {
130 		*lp = (*swap) (*lp);
131 		lp++;
132 	}
133 }
134 
135 static void
hswav(uvlong * lp,int n,uvlong (* swap)(uvlong))136 hswav(uvlong *lp, int n, uvlong (*swap)(uvlong))
137 {
138 	while (n--) {
139 		*lp = (*swap)(*lp);
140 		lp++;
141 	}
142 }
143 
144 static int
readehdr(Boot * b)145 readehdr(Boot *b)
146 {
147 	int i;
148 
149 	/* bitswap the header according to the DATA format */
150 	if(ehdr.ident[CLASS] != ELFCLASS32) {
151 		print("bad ELF class - not 32 bit\n");
152 		return 0;
153 	}
154 	if(ehdr.ident[DATA] == ELFDATA2LSB) {
155 		swab = leswab;
156 		swal = leswal;
157 	} else if(ehdr.ident[DATA] == ELFDATA2MSB) {
158 		swab = beswab;
159 		swal = beswal;
160 	} else {
161 		print("bad ELF encoding - not big or little endian\n");
162 		return 0;
163 	}
164 	memmove(&rehdr, &ehdr, sizeof(Ehdr));	/* copy; never used */
165 
166 	ehdr.type = swab(ehdr.type);
167 	ehdr.machine = swab(ehdr.machine);
168 	ehdr.version = swal(ehdr.version);
169 	ehdr.elfentry = swal(ehdr.elfentry);
170 	ehdr.phoff = swal(ehdr.phoff);
171 	ehdr.shoff = swal(ehdr.shoff);
172 	ehdr.flags = swal(ehdr.flags);
173 	ehdr.ehsize = swab(ehdr.ehsize);
174 	ehdr.phentsize = swab(ehdr.phentsize);
175 	ehdr.phnum = swab(ehdr.phnum);
176 	ehdr.shentsize = swab(ehdr.shentsize);
177 	ehdr.shnum = swab(ehdr.shnum);
178 	ehdr.shstrndx = swab(ehdr.shstrndx);
179 	if(ehdr.type != EXEC || ehdr.version != CURRENT)
180 		return 0;
181 	if(ehdr.phentsize != sizeof(Phdr))
182 		return 0;
183 
184 	if(debug)
185 		print("readehdr OK entry %#lux\n", ehdr.elfentry);
186 
187 	curoff = sizeof(Ehdr);
188 	i = ehdr.phoff+ehdr.phentsize*ehdr.phnum - curoff;
189 	b->state = READPHDR;
190 	b->bp = (char*)smalloc(i);
191 	b->wp = b->bp;
192 	b->ep = b->wp + i;
193 	elftotal = 0;
194 	phdr = (Phdr*)(b->bp + ehdr.phoff-sizeof(Ehdr));
195 	if(debug)
196 		print("phdr...");
197 
198 	return 1;
199 }
200 
201 static int
reade64hdr(Boot * b)202 reade64hdr(Boot *b)
203 {
204 	int i;
205 
206 	/* bitswap the header according to the DATA format */
207 	if(e64hdr.ident[CLASS] != ELFCLASS64) {
208 		print("bad ELF class - not 64 bit\n");
209 		return 0;
210 	}
211 	if(e64hdr.ident[DATA] == ELFDATA2LSB) {
212 		swab = leswab;
213 		swal = leswal;
214 		swav = leswav;
215 	} else if(e64hdr.ident[DATA] == ELFDATA2MSB) {
216 		swab = beswab;
217 		swal = beswal;
218 		swav = beswav;
219 	} else {
220 		print("bad ELF encoding - not big or little endian\n");
221 		return 0;
222 	}
223 //	memmove(&rehdr, &ehdr, sizeof(Ehdr));	/* copy; never used */
224 
225 	e64hdr.type = swab(e64hdr.type);
226 	e64hdr.machine = swab(e64hdr.machine);
227 	e64hdr.version = swal(e64hdr.version);
228 	e64hdr.elfentry = swav(e64hdr.elfentry);
229 	e64hdr.phoff = swav(e64hdr.phoff);
230 	e64hdr.shoff = swav(e64hdr.shoff);
231 	e64hdr.flags = swal(e64hdr.flags);
232 	e64hdr.ehsize = swab(e64hdr.ehsize);
233 	e64hdr.phentsize = swab(e64hdr.phentsize);
234 	e64hdr.phnum = swab(e64hdr.phnum);
235 	e64hdr.shentsize = swab(e64hdr.shentsize);
236 	e64hdr.shnum = swab(e64hdr.shnum);
237 	e64hdr.shstrndx = swab(e64hdr.shstrndx);
238 	if(e64hdr.type != EXEC || e64hdr.version != CURRENT)
239 		return 0;
240 	if(e64hdr.phentsize != sizeof(P64hdr))
241 		return 0;
242 
243 	if(debug)
244 		print("reade64hdr OK entry %#llux\n", e64hdr.elfentry);
245 
246 	curoff = sizeof(E64hdr);
247 	i = e64hdr.phoff + e64hdr.phentsize*e64hdr.phnum - curoff;
248 	b->state = READ64PHDR;
249 	b->bp = (char*)smalloc(i);
250 	b->wp = b->bp;
251 	b->ep = b->wp + i;
252 	elftotal = 0;
253 	p64hdr = (P64hdr*)(b->bp + e64hdr.phoff-sizeof(E64hdr));
254 	if(debug)
255 		print("p64hdr...");
256 
257 	return 1;
258 }
259 
260 static int
nextphdr(Boot * b)261 nextphdr(Boot *b)
262 {
263 	Phdr *php;
264 	ulong offset;
265 	char *physaddr;
266 
267 	if(debug)
268 		print("readedata %d\n", curphdr);
269 
270 	for(; curphdr < ehdr.phnum; curphdr++){
271 		php = phdr+curphdr;
272 		if(php->type != LOAD)
273 			continue;
274 		offset = php->offset;
275 		physaddr = (char*)KADDR(PADDR(php->paddr));
276 		if(offset < curoff){
277 			/*
278 			 * Can't (be bothered to) rewind the
279 			 * input, it might be from tftp. If we
280 			 * did then we could boot FreeBSD kernels
281 			 * too maybe.
282 			 */
283 			return 0;
284 		}
285 		if(php->offset > curoff){
286 			b->state = READEPAD;
287 			b->bp = (char*)smalloc(offset - curoff);
288 			b->wp = b->bp;
289 			b->ep = b->wp + offset - curoff;
290 			if(debug)
291 				print("nextphdr %lud...\n", offset - curoff);
292 			return 1;
293 		}
294 		b->state = READEDATA;
295 		b->bp = physaddr;
296 		b->wp = b->bp;
297 		b->ep = b->wp+php->filesz;
298 		print("%ud+", php->filesz);
299 		elftotal += php->filesz;
300 		if(debug)
301 			print("nextphdr %ud@%#p\n", php->filesz, physaddr);
302 
303 		return 1;
304 	}
305 
306 	if(curphdr != 0){
307 		print("=%lud\n", elftotal);
308 		b->state = TRYEBOOT;
309 		b->entry = ehdr.elfentry;
310 		// PLLONG(b->hdr.entry, b->entry);
311 		return 1;
312 	}
313 
314 	return 0;
315 }
316 
317 static int
nextp64hdr(Boot * b)318 nextp64hdr(Boot *b)
319 {
320 	P64hdr *php;
321 	uvlong offset;
322 	char *physaddr;
323 
324 	if(debug)
325 		print("reade64data %d\n", curphdr);
326 
327 	for(; curphdr < e64hdr.phnum; curphdr++){
328 		php = p64hdr+curphdr;
329 		if(php->type != LOAD)
330 			continue;
331 		offset = php->offset;
332 		physaddr = (char*)KADDR(PADDR(php->paddr));
333 		if(offset < curoff){
334 			/*
335 			 * Can't (be bothered to) rewind the
336 			 * input, it might be from tftp. If we
337 			 * did then we could boot FreeBSD kernels
338 			 * too maybe.
339 			 */
340 			return 0;
341 		}
342 		if(php->offset > curoff){
343 			b->state = READE64PAD;
344 			b->bp = (char*)smalloc(offset - curoff);
345 			b->wp = b->bp;
346 			b->ep = b->wp + offset - curoff;
347 			if(debug)
348 				print("nextp64hdr %llud...\n", offset - curoff);
349 			return 1;
350 		}
351 		b->state = READE64DATA;
352 		b->bp = physaddr;
353 		b->wp = b->bp;
354 		b->ep = b->wp+php->filesz;
355 		print("%llud+", php->filesz);
356 		elftotal += php->filesz;
357 		if(debug)
358 			print("nextp64hdr %llud@%#p\n", php->filesz, physaddr);
359 
360 		return 1;
361 	}
362 
363 	if(curphdr != 0){
364 		print("=%lud\n", elftotal);
365 		b->state = TRYE64BOOT;
366 		b->entry = e64hdr.elfentry;
367 		return 1;
368 	}
369 
370 	return 0;
371 }
372 
373 static int
readepad(Boot * b)374 readepad(Boot *b)
375 {
376 	Phdr *php;
377 
378 	php = phdr+curphdr;
379 	if(debug)
380 		print("readepad %d\n", curphdr);
381 	curoff = php->offset;
382 
383 	return nextphdr(b);
384 }
385 
386 static int
reade64pad(Boot * b)387 reade64pad(Boot *b)
388 {
389 	P64hdr *php;
390 
391 	php = p64hdr+curphdr;
392 	if(debug)
393 		print("reade64pad %d\n", curphdr);
394 	curoff = php->offset;
395 
396 	return nextp64hdr(b);
397 }
398 
399 static int
readedata(Boot * b)400 readedata(Boot *b)
401 {
402 	Phdr *php;
403 
404 	php = phdr+curphdr;
405 	if(debug)
406 		print("readedata %d\n", curphdr);
407 	if(php->filesz < php->memsz){
408 		print("%lud",  php->memsz-php->filesz);
409 		elftotal += php->memsz-php->filesz;
410 		memset((char*)KADDR(PADDR(php->paddr)+php->filesz), 0,
411 			php->memsz-php->filesz);
412 	}
413 	curoff = php->offset+php->filesz;
414 	curphdr++;
415 
416 	return nextphdr(b);
417 }
418 
419 static int
reade64data(Boot * b)420 reade64data(Boot *b)
421 {
422 	P64hdr *php;
423 
424 	php = p64hdr+curphdr;
425 	if(debug)
426 		print("reade64data %d\n", curphdr);
427 	if(php->filesz < php->memsz){
428 		print("%llud",  php->memsz - php->filesz);
429 		elftotal += php->memsz - php->filesz;
430 		memset((char*)KADDR(PADDR(php->paddr) + php->filesz), 0,
431 			php->memsz - php->filesz);
432 	}
433 	curoff = php->offset + php->filesz;
434 	curphdr++;
435 
436 	return nextp64hdr(b);
437 }
438 
439 static int
readphdr(Boot * b)440 readphdr(Boot *b)
441 {
442 	Phdr *php;
443 
444 	php = phdr;
445 	hswal((long*)php, ehdr.phentsize*ehdr.phnum/sizeof(long), swal);
446 	if(debug)
447 		print("phdr curoff %lud vaddr %#lux paddr %#lux\n",
448 			curoff, php->vaddr, php->paddr);
449 
450 	curoff = ehdr.phoff+ehdr.phentsize*ehdr.phnum;
451 	curphdr = 0;
452 
453 	return nextphdr(b);
454 }
455 
456 static int
readp64hdr(Boot * b)457 readp64hdr(Boot *b)
458 {
459 	int hdr;
460 	P64hdr *php, *p;
461 
462 	php = p = p64hdr;
463 	for (hdr = 0; hdr < e64hdr.phnum; hdr++, p++) {
464 		hswal((long*)p, 2, swal);
465 		hswav((uvlong*)&p->offset, 6, swav);
466 	}
467 	if(debug)
468 		print("p64hdr curoff %lud vaddr %#llux paddr %#llux\n",
469 			curoff, php->vaddr, php->paddr);
470 
471 	curoff = e64hdr.phoff + e64hdr.phentsize*e64hdr.phnum;
472 	curphdr = 0;
473 
474 	return nextp64hdr(b);
475 }
476 
477 static int
addbytes(char ** dbuf,char * edbuf,char ** sbuf,char * esbuf)478 addbytes(char **dbuf, char *edbuf, char **sbuf, char *esbuf)
479 {
480 	int n;
481 
482 	n = edbuf - *dbuf;
483 	if(n <= 0)
484 		return 0;			/* dest buffer is full */
485 	if(n > esbuf - *sbuf)
486 		n = esbuf - *sbuf;
487 	if(n <= 0)
488 		return -1;			/* src buffer is empty */
489 
490 	memmove(*dbuf, *sbuf, n);
491 	*sbuf += n;
492 	*dbuf += n;
493 	return edbuf - *dbuf;
494 }
495 
496 void
impulse(void)497 impulse(void)
498 {
499 	delay(500);				/* drain uart */
500 	splhi();
501 
502 	/* turn off buffered serial console */
503 	serialoq = nil;
504 
505 	/* shutdown devices */
506 	chandevshutdown();
507 	arch->introff();
508 }
509 
510 void
prstackuse(int)511 prstackuse(int)
512 {
513 	char *top, *base;
514 	ulong *p;
515 
516 	base = up->kstack;
517 	top =  up->kstack + KSTACK - (sizeof(Sargs) + BY2WD);
518 	for (p = (ulong *)base; (char *)p < top && *p ==
519 	    (Stkpat<<24 | Stkpat<<16 | Stkpat<<8 | Stkpat); p++)
520 		;
521 	print("proc stack: used %ld bytes, %ld left (stack pattern)\n",
522 		top - (char *)p, (char *)p - base);
523 }
524 
525 /*
526  * this code is simplified from reboot().  It doesn't need to relocate
527  * the new kernel nor deal with other processors.
528  */
529 void
warp9(ulong entry)530 warp9(ulong entry)
531 {
532 //	prstackuse(0);			/* debugging */
533 	mkmultiboot();
534 	impulse();
535 
536 	/* get out of KZERO space, turn off paging and jump to entry */
537 	pagingoff(PADDR(entry));
538 }
539 
540 static int
bootfail(Boot * b)541 bootfail(Boot *b)
542 {
543 	b->state = FAILED;
544 	return FAIL;
545 }
546 
547 static int
isgzipped(uchar * p)548 isgzipped(uchar *p)
549 {
550 	return p[0] == 0x1F && p[1] == 0x8B && p[2] == 0x08;
551 }
552 
553 static int
readexec(Boot * b)554 readexec(Boot *b)
555 {
556 	Exechdr *hdr;
557 	ulong pentry, text, data, magic;
558 
559 	hdr = &b->hdr;
560 	magic = GLLONG(hdr->magic);
561 	if(magic == I_MAGIC || magic == S_MAGIC) {
562 		pentry = PADDR(GLLONG(hdr->entry));
563 		text = GLLONG(hdr->text);
564 		data = GLLONG(hdr->data);
565 		if (pentry < MB)
566 			panic("kernel entry %#p below 1 MB", pentry);
567 		if (PGROUND(pentry + text) + data > MB + Kernelmax)
568 			panic("kernel larger than %d bytes", Kernelmax);
569 		b->state = READ9TEXT;
570 		b->bp = (char*)KADDR(pentry);
571 		b->wp = b->bp;
572 		b->ep = b->wp+text;
573 
574 		if(magic == I_MAGIC){
575 			memmove(b->bp, b->hdr.uvl, sizeof(b->hdr.uvl));
576 			b->wp += sizeof(b->hdr.uvl);
577 		}
578 
579 		print("%lud", text);
580 	} else if(memcmp(b->bp, elfident, 4) == 0 &&
581 	    (uchar)b->bp[4] == ELFCLASS32){
582 		b->state = READEHDR;
583 		b->bp = (char*)&ehdr;
584 		b->wp = b->bp;
585 		b->ep = b->wp + sizeof(Ehdr);
586 		memmove(b->bp, &b->hdr, sizeof(Exechdr));
587 		b->wp += sizeof(Exechdr);
588 		print("elf...");
589 	} else if(memcmp(b->bp, elfident, 4) == 0 &&
590 	    (uchar)b->bp[4] == ELFCLASS64){
591 		b->state = READE64HDR;
592 		b->bp = (char*)&e64hdr;
593 		b->wp = b->bp;
594 		b->ep = b->wp + sizeof(E64hdr);
595 		memmove(b->bp, &b->hdr, sizeof(Exechdr));
596 		b->wp += sizeof(Exechdr);
597 		print("elf64...");
598 	} else if(isgzipped((uchar *)b->bp)) {
599 		b->state = READGZIP;
600 		/* could use Unzipbuf instead of smalloc() */
601 		b->bp = (char*)smalloc(Kernelmax);
602 		b->wp = b->bp;
603 		b->ep = b->wp + Kernelmax;
604 		memmove(b->bp, &b->hdr, sizeof(Exechdr));
605 		b->wp += sizeof(Exechdr);
606 		print("gz...");
607 	} else {
608 		print("bad kernel format (magic %#lux)\n", magic);
609 		return bootfail(b);
610 	}
611 	return MORE;
612 }
613 
614 static void
boot9(Boot * b,ulong magic,ulong entry)615 boot9(Boot *b, ulong magic, ulong entry)
616 {
617 	if(magic == I_MAGIC){
618 		print("entry: %#lux\n", entry);
619 		warp9(PADDR(entry));
620 	}
621 	else if(magic == S_MAGIC)
622 		warp64(beswav(b->hdr.uvl[0]));
623 	else
624 		print("bad magic %#lux\n", magic);
625 }
626 
627 /* only returns upon failure */
628 static void
readgzip(Boot * b)629 readgzip(Boot *b)
630 {
631 	ulong entry, text, data, bss, magic, all, pentry;
632 	uchar *sdata;
633 	Exechdr *hdr;
634 
635 	/* the whole gzipped kernel is now at b->bp */
636 	hdr = &b->hdr;
637 	if(!isgzipped((uchar *)b->bp)) {
638 		print("lost magic\n");
639 		return;
640 	}
641 	print("%ld => ", b->wp - b->bp);
642 	/* just fill hdr from gzipped b->bp, to get various sizes */
643 	if(gunzip((uchar*)hdr, sizeof *hdr, (uchar*)b->bp, b->wp - b->bp)
644 	    < sizeof *hdr) {
645 		print("error uncompressing kernel exec header\n");
646 		return;
647 	}
648 
649 	/* assume uncompressed kernel is a plan 9 boot image */
650 	magic = GLLONG(hdr->magic);
651 	entry = GLLONG(hdr->entry);
652 	text = GLLONG(hdr->text);
653 	data = GLLONG(hdr->data);
654 	bss = GLLONG(hdr->bss);
655 	print("%lud+%lud+%lud=%lud\n", text, data, bss, text+data+bss);
656 
657 	pentry = PADDR(entry);
658 	if (pentry < MB)
659 		panic("kernel entry %#p below 1 MB", pentry);
660 	if (PGROUND(pentry + text) + data > MB + Kernelmax)
661 		panic("kernel larger than %d bytes", Kernelmax);
662 
663 	/* fill entry from gzipped b->bp */
664 	all = sizeof(Exec) + text + data;
665 	if(gunzip((uchar *)KADDR(PADDR(entry)) - sizeof(Exec), all,
666 	    (uchar*)b->bp, b->wp - b->bp) < all) {
667 		print("error uncompressing kernel\n");
668 		return;
669 	}
670 
671 	/* relocate data to start at page boundary */
672 	sdata = KADDR(PADDR(entry+text));
673 	memmove((void*)PGROUND((uintptr)sdata), sdata, data);
674 
675 	boot9(b, magic, entry);
676 }
677 
678 /*
679  * if nbuf is zero, boot.
680  * else add nbuf bytes from vbuf to b->wp (if there is room)
681  * and advance the state machine, which may reset b's pointers
682  * and return to the top.
683  */
684 int
bootpass(Boot * b,void * vbuf,int nbuf)685 bootpass(Boot *b, void *vbuf, int nbuf)
686 {
687 	char *buf, *ebuf;
688 	Exechdr *hdr;
689 	ulong entry, bss;
690 	uvlong entry64;
691 
692 	if(b->state == FAILED)
693 		return FAIL;
694 
695 	if(nbuf == 0)
696 		goto Endofinput;
697 
698 	buf = vbuf;
699 	ebuf = buf+nbuf;
700 	/* possibly copy into b->wp from buf (not first time) */
701 	while(addbytes(&b->wp, b->ep, &buf, ebuf) == 0) {
702 		/* b->bp is full, so advance the state machine */
703 		switch(b->state) {
704 		case INITKERNEL:
705 			b->state = READEXEC;
706 			b->bp = (char*)&b->hdr;
707 			b->wp = b->bp;
708 			b->ep = b->bp+sizeof(Exechdr);
709 			break;
710 		case READEXEC:
711 			readexec(b);
712 			break;
713 
714 		case READ9TEXT:
715 			hdr = &b->hdr;
716 			b->state = READ9DATA;
717 			b->bp = (char*)PGROUND((uintptr)
718 				KADDR(PADDR(GLLONG(hdr->entry))) +
719 				GLLONG(hdr->text));
720 			b->wp = b->bp;
721 			b->ep = b->wp + GLLONG(hdr->data);
722 			print("+%ld", GLLONG(hdr->data));
723 			break;
724 
725 		case READ9DATA:
726 			hdr = &b->hdr;
727 			bss = GLLONG(hdr->bss);
728 			memset(b->ep, 0, bss);
729 			print("+%ld=%ld\n",
730 				bss, GLLONG(hdr->text)+GLLONG(hdr->data)+bss);
731 			b->state = TRYBOOT;
732 			return ENOUGH;
733 
734 		/*
735 		 * elf
736 		 */
737 		case READEHDR:
738 			if(!readehdr(b))
739 				print("readehdr failed\n");
740 			break;
741 		case READPHDR:
742 			readphdr(b);
743 			break;
744 		case READEPAD:
745 			readepad(b);
746 			break;
747 		case READEDATA:
748 			readedata(b);
749 			if(b->state == TRYEBOOT)
750 				return ENOUGH;
751 			break;
752 
753 		/*
754 		 * elf64
755 		 */
756 		case READE64HDR:
757 			if(!reade64hdr(b))
758 				print("reade64hdr failed\n");
759 			break;
760 		case READ64PHDR:
761 			readp64hdr(b);
762 			break;
763 		case READE64PAD:
764 			reade64pad(b);
765 			break;
766 		case READE64DATA:
767 			reade64data(b);
768 			if(b->state == TRYE64BOOT)
769 				return ENOUGH;
770 			break;
771 
772 		case TRYBOOT:
773 		case TRYEBOOT:
774 		case TRYE64BOOT:
775 		case READGZIP:
776 			return ENOUGH;
777 
778 		case READ9LOAD:
779 		case INIT9LOAD:
780 			panic("9load");
781 
782 		default:
783 			panic("bootstate");
784 		}
785 		if(b->state == FAILED)
786 			return FAIL;
787 	}
788 	return MORE;
789 
790 Endofinput:
791 	/* end of input */
792 	switch(b->state) {
793 	case INITKERNEL:
794 	case READEXEC:
795 	case READ9TEXT:
796 	case READ9DATA:
797 	case READEHDR:
798 	case READPHDR:
799 	case READEPAD:
800 	case READEDATA:
801 	case READE64HDR:
802 	case READ64PHDR:
803 	case READE64PAD:
804 	case READE64DATA:
805 		print("premature EOF\n");
806 		break;
807 
808 	case TRYBOOT:
809 		boot9(b, GLLONG(b->hdr.magic), GLLONG(b->hdr.entry));
810 		break;
811 
812 	case TRYEBOOT:
813 		entry = b->entry;
814 		if(ehdr.machine == I386){
815 			print("entry: %#lux\n", entry);
816 			warp9(PADDR(entry));
817 		}
818 		else if(ehdr.machine == AMD64)
819 			warp64(entry);
820 		else
821 			panic("elf boot: ehdr.machine %d unknown", ehdr.machine);
822 		break;
823 
824 	case TRYE64BOOT:
825 		entry64 = b->entry;
826 		if(e64hdr.machine == I386){
827 			print("entry: %#llux\n", entry64);
828 			warp9(PADDR(entry64));
829 		}
830 		else if(e64hdr.machine == AMD64)
831 			warp64(entry64);
832 		else
833 			panic("elf64 boot: e64hdr.machine %d unknown",
834 				e64hdr.machine);
835 		break;
836 
837 	case READGZIP:
838 		readgzip(b);
839 		break;
840 
841 	case INIT9LOAD:
842 	case READ9LOAD:
843 		panic("end 9load");
844 
845 	default:
846 		panic("bootdone");
847 	}
848 	return bootfail(b);
849 }
850