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