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