xref: /titanic_52/usr/src/boot/sys/boot/sparc64/boot1/boot1.c (revision 4a5d661a82b942b6538acd26209d959ce98b593a)
1 /*-
2  * Copyright (c) 1998 Robert Nordier
3  * All rights reserved.
4  * Copyright (c) 2001 Robert Drehmel
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms are freely
8  * permitted provided that the above copyright notice and this
9  * paragraph and the following disclaimer are duplicated in all
10  * such forms.
11  *
12  * This software is provided "AS IS" and without any express or
13  * implied warranties, including, without limitation, the implied
14  * warranties of merchantability and fitness for a particular
15  * purpose.
16  */
17 
18 #include <sys/cdefs.h>
19 __FBSDID("$FreeBSD$");
20 
21 #include <sys/param.h>
22 #include <sys/dirent.h>
23 
24 #include <machine/elf.h>
25 #include <machine/stdarg.h>
26 
27 #include "paths.h"
28 
29 #define	READ_BUF_SIZE	8192
30 
31 typedef int putc_func_t(char c, void *arg);
32 typedef int32_t ofwh_t;
33 
34 struct sp_data {
35 	char	*sp_buf;
36 	u_int	sp_len;
37 	u_int	sp_size;
38 };
39 
40 static const char digits[] = "0123456789abcdef";
41 
42 static char bootpath[128];
43 static char bootargs[128];
44 
45 static ofwh_t bootdev;
46 
47 static uint32_t fs_off;
48 
49 int main(int ac, char **av);
50 static void exit(int) __dead2;
51 static void usage(void);
52 
53 #ifdef ZFSBOOT
54 static void loadzfs(void);
55 static int zbread(char *buf, off_t off, size_t bytes);
56 #else
57 static void load(const char *);
58 #endif
59 
60 static void bcopy(const void *src, void *dst, size_t len);
61 static void bzero(void *b, size_t len);
62 
63 static int domount(const char *device);
64 static int dskread(void *buf, u_int64_t lba, int nblk);
65 
66 static void panic(const char *fmt, ...) __dead2;
67 static int printf(const char *fmt, ...);
68 static int putchar(char c, void *arg);
69 static int vprintf(const char *fmt, va_list ap);
70 static int vsnprintf(char *str, size_t sz, const char *fmt, va_list ap);
71 
72 static int __printf(const char *fmt, putc_func_t *putc, void *arg, va_list ap);
73 static int __puts(const char *s, putc_func_t *putc, void *arg);
74 static int __sputc(char c, void *arg);
75 static char *__uitoa(char *buf, u_int val, int base);
76 static char *__ultoa(char *buf, u_long val, int base);
77 
78 /*
79  * Open Firmware interface functions
80  */
81 typedef u_int64_t	ofwcell_t;
82 typedef u_int32_t	u_ofwh_t;
83 typedef int (*ofwfp_t)(ofwcell_t []);
84 static ofwfp_t ofw;			/* the PROM Open Firmware entry */
85 
86 void ofw_init(int, int, int, int, ofwfp_t);
87 static ofwh_t ofw_finddevice(const char *);
88 static ofwh_t ofw_open(const char *);
89 static int ofw_getprop(ofwh_t, const char *, void *, size_t);
90 static int ofw_read(ofwh_t, void *, size_t);
91 static int ofw_write(ofwh_t, const void *, size_t);
92 static int ofw_seek(ofwh_t, u_int64_t);
93 static void ofw_exit(void) __dead2;
94 
95 static ofwh_t stdinh, stdouth;
96 
97 /*
98  * This has to stay here, as the PROM seems to ignore the
99  * entry point specified in the a.out header.  (or elftoaout is broken)
100  */
101 
102 void
103 ofw_init(int d, int d1, int d2, int d3, ofwfp_t ofwaddr)
104 {
105 	ofwh_t chosenh;
106 	char *av[16];
107 	char *p;
108 	int ac;
109 
110 	ofw = ofwaddr;
111 
112 	chosenh = ofw_finddevice("/chosen");
113 	ofw_getprop(chosenh, "stdin", &stdinh, sizeof(stdinh));
114 	ofw_getprop(chosenh, "stdout", &stdouth, sizeof(stdouth));
115 	ofw_getprop(chosenh, "bootargs", bootargs, sizeof(bootargs));
116 	ofw_getprop(chosenh, "bootpath", bootpath, sizeof(bootpath));
117 
118 	bootargs[sizeof(bootargs) - 1] = '\0';
119 	bootpath[sizeof(bootpath) - 1] = '\0';
120 
121 	ac = 0;
122 	p = bootargs;
123 	for (;;) {
124 		while (*p == ' ' && *p != '\0')
125 			p++;
126 		if (*p == '\0' || ac >= 16)
127 			break;
128 		av[ac++] = p;
129 		while (*p != ' ' && *p != '\0')
130 			p++;
131 		if (*p != '\0')
132 			*p++ = '\0';
133 	}
134 
135 	exit(main(ac, av));
136 }
137 
138 static ofwh_t
139 ofw_finddevice(const char *name)
140 {
141 	ofwcell_t args[] = {
142 		(ofwcell_t)"finddevice",
143 		1,
144 		1,
145 		(ofwcell_t)name,
146 		0
147 	};
148 
149 	if ((*ofw)(args)) {
150 		printf("ofw_finddevice: name=\"%s\"\n", name);
151 		return (1);
152 	}
153 	return (args[4]);
154 }
155 
156 static int
157 ofw_getprop(ofwh_t ofwh, const char *name, void *buf, size_t len)
158 {
159 	ofwcell_t args[] = {
160 		(ofwcell_t)"getprop",
161 		4,
162 		1,
163 		(u_ofwh_t)ofwh,
164 		(ofwcell_t)name,
165 		(ofwcell_t)buf,
166 		len,
167 	0
168 	};
169 
170 	if ((*ofw)(args)) {
171 		printf("ofw_getprop: ofwh=0x%x buf=%p len=%u\n",
172 			ofwh, buf, len);
173 		return (1);
174 	}
175 	return (0);
176 }
177 
178 static ofwh_t
179 ofw_open(const char *path)
180 {
181 	ofwcell_t args[] = {
182 		(ofwcell_t)"open",
183 		1,
184 		1,
185 		(ofwcell_t)path,
186 		0
187 	};
188 
189 	if ((*ofw)(args)) {
190 		printf("ofw_open: path=\"%s\"\n", path);
191 		return (-1);
192 	}
193 	return (args[4]);
194 }
195 
196 static int
197 ofw_close(ofwh_t devh)
198 {
199 	ofwcell_t args[] = {
200 		(ofwcell_t)"close",
201 		1,
202 		0,
203 		(u_ofwh_t)devh
204 	};
205 
206 	if ((*ofw)(args)) {
207 		printf("ofw_close: devh=0x%x\n", devh);
208 		return (1);
209 	}
210 	return (0);
211 }
212 
213 static int
214 ofw_read(ofwh_t devh, void *buf, size_t len)
215 {
216 	ofwcell_t args[] = {
217 		(ofwcell_t)"read",
218 		3,
219 		1,
220 		(u_ofwh_t)devh,
221 		(ofwcell_t)buf,
222 		len,
223 		0
224 	};
225 
226 	if ((*ofw)(args)) {
227 		printf("ofw_read: devh=0x%x buf=%p len=%u\n", devh, buf, len);
228 		return (1);
229 	}
230 	return (0);
231 }
232 
233 static int
234 ofw_write(ofwh_t devh, const void *buf, size_t len)
235 {
236 	ofwcell_t args[] = {
237 		(ofwcell_t)"write",
238 		3,
239 		1,
240 		(u_ofwh_t)devh,
241 		(ofwcell_t)buf,
242 		len,
243 		0
244 	};
245 
246 	if ((*ofw)(args)) {
247 		printf("ofw_write: devh=0x%x buf=%p len=%u\n", devh, buf, len);
248 		return (1);
249 	}
250 	return (0);
251 }
252 
253 static int
254 ofw_seek(ofwh_t devh, u_int64_t off)
255 {
256 	ofwcell_t args[] = {
257 		(ofwcell_t)"seek",
258 		3,
259 		1,
260 		(u_ofwh_t)devh,
261 		off >> 32,
262 		off,
263 		0
264 	};
265 
266 	if ((*ofw)(args)) {
267 		printf("ofw_seek: devh=0x%x off=0x%lx\n", devh, off);
268 		return (1);
269 	}
270 	return (0);
271 }
272 
273 static void
274 ofw_exit(void)
275 {
276 	ofwcell_t args[3];
277 
278 	args[0] = (ofwcell_t)"exit";
279 	args[1] = 0;
280 	args[2] = 0;
281 
282 	for (;;)
283 		(*ofw)(args);
284 }
285 
286 static void
287 bcopy(const void *src, void *dst, size_t len)
288 {
289 	const char *s = src;
290 	char *d = dst;
291 
292 	while (len-- != 0)
293 		*d++ = *s++;
294 }
295 
296 static void
297 memcpy(void *dst, const void *src, size_t len)
298 {
299 
300 	bcopy(src, dst, len);
301 }
302 
303 static void
304 bzero(void *b, size_t len)
305 {
306 	char *p = b;
307 
308 	while (len-- != 0)
309 		*p++ = 0;
310 }
311 
312 static int
313 strcmp(const char *s1, const char *s2)
314 {
315 
316 	for (; *s1 == *s2 && *s1; s1++, s2++)
317 		;
318 	return ((u_char)*s1 - (u_char)*s2);
319 }
320 
321 int
322 main(int ac, char **av)
323 {
324 	const char *path;
325 	int i;
326 
327 	path = PATH_LOADER;
328 	for (i = 0; i < ac; i++) {
329 		switch (av[i][0]) {
330 		case '-':
331 			switch (av[i][1]) {
332 			default:
333 				usage();
334 			}
335 			break;
336 		default:
337 			path = av[i];
338 			break;
339 		}
340 	}
341 
342 #ifdef ZFSBOOT
343 	printf(" \n>> FreeBSD/sparc64 ZFS boot block\n   Boot path:   %s\n",
344 	    bootpath);
345 #else
346 	printf(" \n>> FreeBSD/sparc64 boot block\n   Boot path:   %s\n"
347 	    "   Boot loader: %s\n", bootpath, path);
348 #endif
349 
350 	if (domount(bootpath) == -1)
351 		panic("domount");
352 
353 #ifdef ZFSBOOT
354 	loadzfs();
355 #else
356 	load(path);
357 #endif
358 	return (1);
359 }
360 
361 static void
362 usage(void)
363 {
364 
365 	printf("usage: boot device [/path/to/loader]\n");
366 	exit(1);
367 }
368 
369 static void
370 exit(int code)
371 {
372 
373 	ofw_exit();
374 }
375 
376 #ifdef ZFSBOOT
377 
378 #define	VDEV_BOOT_OFFSET	(2 * 256 * 1024)
379 static char zbuf[READ_BUF_SIZE];
380 
381 static int
382 zbread(char *buf, off_t off, size_t bytes)
383 {
384 	size_t len;
385 	off_t poff;
386 	off_t soff;
387 	char *p;
388 	unsigned int nb;
389 	unsigned int lb;
390 
391 	p = buf;
392 	soff = VDEV_BOOT_OFFSET + off;
393 	lb = (soff + bytes + DEV_BSIZE - 1) / DEV_BSIZE;
394 	poff = soff;
395 	while (poff < soff + bytes) {
396 		nb = lb - poff / DEV_BSIZE;
397 		if (nb > READ_BUF_SIZE / DEV_BSIZE)
398 			nb = READ_BUF_SIZE / DEV_BSIZE;
399 		if (dskread(zbuf, poff / DEV_BSIZE, nb))
400 			break;
401 		if ((poff / DEV_BSIZE + nb) * DEV_BSIZE > soff + bytes)
402 			len = soff + bytes - poff;
403 		else
404 			len = (poff / DEV_BSIZE + nb) * DEV_BSIZE - poff;
405 		memcpy(p, zbuf + poff % DEV_BSIZE, len);
406 		p += len;
407 		poff += len;
408 	}
409 	return (poff - soff);
410 }
411 
412 static void
413 loadzfs(void)
414 {
415 	Elf64_Ehdr eh;
416 	Elf64_Phdr ph;
417 	caddr_t p;
418 	int i;
419 
420 	if (zbread((char *)&eh, 0, sizeof(eh)) != sizeof(eh)) {
421 		printf("Can't read elf header\n");
422 		return;
423 	}
424 	if (!IS_ELF(eh)) {
425 		printf("Not an ELF file\n");
426 		return;
427 	}
428 	for (i = 0; i < eh.e_phnum; i++) {
429 		fs_off = eh.e_phoff + i * eh.e_phentsize;
430 		if (zbread((char *)&ph, fs_off, sizeof(ph)) != sizeof(ph)) {
431 			printf("Can't read program header %d\n", i);
432 			return;
433 		}
434 		if (ph.p_type != PT_LOAD)
435 			continue;
436 		fs_off = ph.p_offset;
437 		p = (caddr_t)ph.p_vaddr;
438 		if (zbread(p, fs_off, ph.p_filesz) != ph.p_filesz) {
439 			printf("Can't read content of section %d\n", i);
440 			return;
441 		}
442 		if (ph.p_filesz != ph.p_memsz)
443 			bzero(p + ph.p_filesz, ph.p_memsz - ph.p_filesz);
444 	}
445 	ofw_close(bootdev);
446 	(*(void (*)(int, int, int, int, ofwfp_t))eh.e_entry)(0, 0, 0, 0, ofw);
447 }
448 
449 #else
450 
451 #include "ufsread.c"
452 
453 static struct dmadat __dmadat;
454 
455 static void
456 load(const char *fname)
457 {
458 	Elf64_Ehdr eh;
459 	Elf64_Phdr ph;
460 	caddr_t p;
461 	ufs_ino_t ino;
462 	int i;
463 
464 	if ((ino = lookup(fname)) == 0) {
465 		printf("File %s not found\n", fname);
466 		return;
467 	}
468 	if (fsread(ino, &eh, sizeof(eh)) != sizeof(eh)) {
469 		printf("Can't read elf header\n");
470 		return;
471 	}
472 	if (!IS_ELF(eh)) {
473 		printf("Not an ELF file\n");
474 		return;
475 	}
476 	for (i = 0; i < eh.e_phnum; i++) {
477 		fs_off = eh.e_phoff + i * eh.e_phentsize;
478 		if (fsread(ino, &ph, sizeof(ph)) != sizeof(ph)) {
479 			printf("Can't read program header %d\n", i);
480 			return;
481 		}
482 		if (ph.p_type != PT_LOAD)
483 			continue;
484 		fs_off = ph.p_offset;
485 		p = (caddr_t)ph.p_vaddr;
486 		if (fsread(ino, p, ph.p_filesz) != ph.p_filesz) {
487 			printf("Can't read content of section %d\n", i);
488 			return;
489 		}
490 		if (ph.p_filesz != ph.p_memsz)
491 			bzero(p + ph.p_filesz, ph.p_memsz - ph.p_filesz);
492 	}
493 	ofw_close(bootdev);
494 	(*(void (*)(int, int, int, int, ofwfp_t))eh.e_entry)(0, 0, 0, 0, ofw);
495 }
496 
497 #endif /* ZFSBOOT */
498 
499 static int
500 domount(const char *device)
501 {
502 
503 	if ((bootdev = ofw_open(device)) == -1) {
504 		printf("domount: can't open device\n");
505 		return (-1);
506 	}
507 #ifndef ZFSBOOT
508 	dmadat = &__dmadat;
509 	if (fsread(0, NULL, 0)) {
510 		printf("domount: can't read superblock\n");
511 		return (-1);
512 	}
513 #endif
514 	return (0);
515 }
516 
517 static int
518 dskread(void *buf, u_int64_t lba, int nblk)
519 {
520 
521 	/*
522 	 * The Open Firmware should open the correct partition for us.
523 	 * That means, if we read from offset zero on an open instance handle,
524 	 * we should read from offset zero of that partition.
525 	 */
526 	ofw_seek(bootdev, lba * DEV_BSIZE);
527 	ofw_read(bootdev, buf, nblk * DEV_BSIZE);
528 	return (0);
529 }
530 
531 static void
532 panic(const char *fmt, ...)
533 {
534 	char buf[128];
535 	va_list ap;
536 
537 	va_start(ap, fmt);
538 	vsnprintf(buf, sizeof buf, fmt, ap);
539 	printf("panic: %s\n", buf);
540 	va_end(ap);
541 
542 	exit(1);
543 }
544 
545 static int
546 printf(const char *fmt, ...)
547 {
548 	va_list ap;
549 	int ret;
550 
551 	va_start(ap, fmt);
552 	ret = vprintf(fmt, ap);
553 	va_end(ap);
554 	return (ret);
555 }
556 
557 static int
558 putchar(char c, void *arg)
559 {
560 	char buf;
561 
562 	if (c == '\n') {
563 		buf = '\r';
564 		ofw_write(stdouth, &buf, 1);
565 	}
566 	buf = c;
567 	ofw_write(stdouth, &buf, 1);
568 	return (1);
569 }
570 
571 static int
572 vprintf(const char *fmt, va_list ap)
573 {
574 	int ret;
575 
576 	ret = __printf(fmt, putchar, 0, ap);
577 	return (ret);
578 }
579 
580 static int
581 vsnprintf(char *str, size_t sz, const char *fmt, va_list ap)
582 {
583 	struct sp_data sp;
584 	int ret;
585 
586 	sp.sp_buf = str;
587 	sp.sp_len = 0;
588 	sp.sp_size = sz;
589 	ret = __printf(fmt, __sputc, &sp, ap);
590 	return (ret);
591 }
592 
593 static int
594 __printf(const char *fmt, putc_func_t *putc, void *arg, va_list ap)
595 {
596 	char buf[(sizeof(long) * 8) + 1];
597 	char *nbuf;
598 	u_long ul;
599 	u_int ui;
600 	int lflag;
601 	int sflag;
602 	char *s;
603 	int pad;
604 	int ret;
605 	int c;
606 
607 	nbuf = &buf[sizeof buf - 1];
608 	ret = 0;
609 	while ((c = *fmt++) != 0) {
610 		if (c != '%') {
611 			ret += putc(c, arg);
612 			continue;
613 		}
614 		lflag = 0;
615 		sflag = 0;
616 		pad = 0;
617 reswitch:	c = *fmt++;
618 		switch (c) {
619 		case '#':
620 			sflag = 1;
621 			goto reswitch;
622 		case '%':
623 			ret += putc('%', arg);
624 			break;
625 		case 'c':
626 			c = va_arg(ap, int);
627 			ret += putc(c, arg);
628 			break;
629 		case 'd':
630 			if (lflag == 0) {
631 				ui = (u_int)va_arg(ap, int);
632 				if (ui < (int)ui) {
633 					ui = -ui;
634 					ret += putc('-', arg);
635 				}
636 				s = __uitoa(nbuf, ui, 10);
637 			} else {
638 				ul = (u_long)va_arg(ap, long);
639 				if (ul < (long)ul) {
640 					ul = -ul;
641 					ret += putc('-', arg);
642 				}
643 				s = __ultoa(nbuf, ul, 10);
644 			}
645 			ret += __puts(s, putc, arg);
646 			break;
647 		case 'l':
648 			lflag = 1;
649 			goto reswitch;
650 		case 'o':
651 			if (lflag == 0) {
652 				ui = (u_int)va_arg(ap, u_int);
653 				s = __uitoa(nbuf, ui, 8);
654 			} else {
655 				ul = (u_long)va_arg(ap, u_long);
656 				s = __ultoa(nbuf, ul, 8);
657 			}
658 			ret += __puts(s, putc, arg);
659 			break;
660 		case 'p':
661 			ul = (u_long)va_arg(ap, void *);
662 			s = __ultoa(nbuf, ul, 16);
663 			ret += __puts("0x", putc, arg);
664 			ret += __puts(s, putc, arg);
665 			break;
666 		case 's':
667 			s = va_arg(ap, char *);
668 			ret += __puts(s, putc, arg);
669 			break;
670 		case 'u':
671 			if (lflag == 0) {
672 				ui = va_arg(ap, u_int);
673 				s = __uitoa(nbuf, ui, 10);
674 			} else {
675 				ul = va_arg(ap, u_long);
676 				s = __ultoa(nbuf, ul, 10);
677 			}
678 			ret += __puts(s, putc, arg);
679 			break;
680 		case 'x':
681 			if (lflag == 0) {
682 				ui = va_arg(ap, u_int);
683 				s = __uitoa(nbuf, ui, 16);
684 			} else {
685 				ul = va_arg(ap, u_long);
686 				s = __ultoa(nbuf, ul, 16);
687 			}
688 			if (sflag)
689 				ret += __puts("0x", putc, arg);
690 			ret += __puts(s, putc, arg);
691 			break;
692 		case '0': case '1': case '2': case '3': case '4':
693 		case '5': case '6': case '7': case '8': case '9':
694 			pad = pad * 10 + c - '0';
695 			goto reswitch;
696 		default:
697 			break;
698 		}
699 	}
700 	return (ret);
701 }
702 
703 static int
704 __sputc(char c, void *arg)
705 {
706 	struct sp_data *sp;
707 
708 	sp = arg;
709 	if (sp->sp_len < sp->sp_size)
710 		sp->sp_buf[sp->sp_len++] = c;
711 	sp->sp_buf[sp->sp_len] = '\0';
712 	return (1);
713 }
714 
715 static int
716 __puts(const char *s, putc_func_t *putc, void *arg)
717 {
718 	const char *p;
719 	int ret;
720 
721 	ret = 0;
722 	for (p = s; *p != '\0'; p++)
723 		ret += putc(*p, arg);
724 	return (ret);
725 }
726 
727 static char *
728 __uitoa(char *buf, u_int ui, int base)
729 {
730 	char *p;
731 
732 	p = buf;
733 	*p = '\0';
734 	do
735 		*--p = digits[ui % base];
736 	while ((ui /= base) != 0);
737 	return (p);
738 }
739 
740 static char *
741 __ultoa(char *buf, u_long ul, int base)
742 {
743 	char *p;
744 
745 	p = buf;
746 	*p = '\0';
747 	do
748 		*--p = digits[ul % base];
749 	while ((ul /= base) != 0);
750 	return (p);
751 }
752