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: releng/10.2/sys/boot/powerpc/boot1.chrp/boot1.c 243254 2012-11-19 01:15:32Z trasz $");
20
21#include <sys/param.h>
22#include <sys/dirent.h>
23#include <machine/elf.h>
24#include <machine/stdarg.h>
25
26#define _PATH_LOADER	"/boot/loader"
27#define _PATH_KERNEL	"/boot/kernel/kernel"
28
29#define BSIZEMAX	16384
30
31typedef int putc_func_t(char c, void *arg);
32typedef int32_t ofwh_t;
33
34struct sp_data {
35	char	*sp_buf;
36	u_int	sp_len;
37	u_int	sp_size;
38};
39
40static const char digits[] = "0123456789abcdef";
41
42static char bootpath[128];
43static char bootargs[128];
44
45static ofwh_t bootdev;
46
47static struct fs fs;
48static char blkbuf[BSIZEMAX];
49static unsigned int fsblks;
50
51static uint32_t fs_off;
52
53int main(int ac, char **av);
54
55static void exit(int) __dead2;
56static void load(const char *);
57static int dskread(void *, u_int64_t, int);
58
59static void usage(void);
60
61static void bcopy(const void *src, void *dst, size_t len);
62static void bzero(void *b, size_t len);
63
64static int domount(const char *device, int quiet);
65
66static void panic(const char *fmt, ...) __dead2;
67static int printf(const char *fmt, ...);
68static int putchar(char c, void *arg);
69static int vprintf(const char *fmt, va_list ap);
70static int vsnprintf(char *str, size_t sz, const char *fmt, va_list ap);
71
72static int __printf(const char *fmt, putc_func_t *putc, void *arg, va_list ap);
73static int __putc(char c, void *arg);
74static int __puts(const char *s, putc_func_t *putc, void *arg);
75static int __sputc(char c, void *arg);
76static char *__uitoa(char *buf, u_int val, int base);
77static char *__ultoa(char *buf, u_long val, int base);
78
79void __syncicache(void *, int);
80
81/*
82 * Open Firmware interface functions
83 */
84typedef u_int32_t	ofwcell_t;
85typedef u_int32_t	u_ofwh_t;
86typedef int (*ofwfp_t)(void *);
87ofwfp_t ofw;			/* the prom Open Firmware entry */
88ofwh_t chosenh;
89
90void ofw_init(void *, int, int (*)(void *), char *, int);
91static ofwh_t ofw_finddevice(const char *);
92static ofwh_t ofw_open(const char *);
93static int ofw_close(ofwh_t);
94static int ofw_getprop(ofwh_t, const char *, void *, size_t);
95static int ofw_setprop(ofwh_t, const char *, void *, size_t);
96static int ofw_read(ofwh_t, void *, size_t);
97static int ofw_write(ofwh_t, const void *, size_t);
98static int ofw_claim(void *virt, size_t len, u_int align);
99static int ofw_seek(ofwh_t, u_int64_t);
100static void ofw_exit(void) __dead2;
101
102ofwh_t bootdevh;
103ofwh_t stdinh, stdouth;
104
105__asm("                         \n\
106        .data                   \n\
107	.align 4		\n\
108stack:                          \n\
109        .space  16384           \n\
110                                \n\
111        .text                   \n\
112        .globl  _start          \n\
113_start:                         \n\
114        lis     %r1,stack@ha    \n\
115        addi    %r1,%r1,stack@l \n\
116        addi    %r1,%r1,8192    \n\
117                                \n\
118        b       ofw_init        \n\
119");
120
121void
122ofw_init(void *vpd, int res, int (*openfirm)(void *), char *arg, int argl)
123{
124	char *av[16];
125	char *p;
126	int ac;
127
128	ofw = openfirm;
129
130	chosenh = ofw_finddevice("/chosen");
131	ofw_getprop(chosenh, "stdin", &stdinh, sizeof(stdinh));
132	ofw_getprop(chosenh, "stdout", &stdouth, sizeof(stdouth));
133	ofw_getprop(chosenh, "bootargs", bootargs, sizeof(bootargs));
134	ofw_getprop(chosenh, "bootpath", bootpath, sizeof(bootpath));
135
136	bootargs[sizeof(bootargs) - 1] = '\0';
137	bootpath[sizeof(bootpath) - 1] = '\0';
138
139	p = bootpath;
140	while (*p != '\0') {
141		if (*p == ':') {
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
165static ofwh_t
166ofw_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
183static int
184ofw_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
205static int
206ofw_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
227static ofwh_t
228ofw_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
245static int
246ofw_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
262static int
263ofw_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
284static int
285ofw_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
304static int
305ofw_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
324static int
325ofw_seek(ofwh_t devh, u_int64_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
344static void
345ofw_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
357static void
358bcopy(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
367static void
368memcpy(void *dst, const void *src, size_t len)
369{
370	bcopy(src, dst, len);
371}
372
373static void
374bzero(void *b, size_t len)
375{
376	char *p = b;
377
378	while (len-- != 0)
379		*p++ = 0;
380}
381
382static int
383strcmp(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
392int
393main(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		for (i = 0; i < 16; i++) {
425			if (i < 10) {
426				bootpath_full[len] = i + '0';
427				bootpath_full[len+1] = '\0';
428			} else {
429				bootpath_full[len] = '1';
430				bootpath_full[len+1] = i - 10 + '0';
431				bootpath_full[len+2] = '\0';
432			}
433
434			if (domount(bootpath_full,1) >= 0)
435				break;
436
437			if (bootdev > 0)
438				ofw_close(bootdev);
439		}
440
441		if (i >= 16)
442			panic("domount");
443	} else {
444		if (domount(bootpath_full,0) == -1)
445			panic("domount");
446	}
447
448	printf("   Boot volume:   %s\n",bootpath_full);
449	ofw_setprop(chosenh, "bootargs", bootpath_full, len+2);
450	load(path);
451	return (1);
452}
453
454static void
455usage(void)
456{
457
458	printf("usage: boot device [/path/to/loader]\n");
459	exit(1);
460}
461
462static void
463exit(int code)
464{
465
466	ofw_exit();
467}
468
469static struct dmadat __dmadat;
470
471static int
472domount(const char *device, int quiet)
473{
474
475	dmadat = &__dmadat;
476	if ((bootdev = ofw_open(device)) == -1) {
477		printf("domount: can't open device\n");
478		return (-1);
479	}
480	if (fsread(0, NULL, 0)) {
481		if (!quiet)
482			printf("domount: can't read superblock\n");
483		return (-1);
484	}
485	return (0);
486}
487
488static void
489load(const char *fname)
490{
491	Elf32_Ehdr eh;
492	Elf32_Phdr ph;
493	caddr_t p;
494	ufs_ino_t ino;
495	int i;
496
497	if ((ino = lookup(fname)) == 0) {
498		printf("File %s not found\n", fname);
499		return;
500	}
501	if (fsread(ino, &eh, sizeof(eh)) != sizeof(eh)) {
502		printf("Can't read elf header\n");
503		return;
504	}
505	if (!IS_ELF(eh)) {
506		printf("Not an ELF file\n");
507		return;
508	}
509	for (i = 0; i < eh.e_phnum; i++) {
510		fs_off = eh.e_phoff + i * eh.e_phentsize;
511		if (fsread(ino, &ph, sizeof(ph)) != sizeof(ph)) {
512			printf("Can't read program header %d\n", i);
513			return;
514		}
515		if (ph.p_type != PT_LOAD)
516			continue;
517		fs_off = ph.p_offset;
518		p = (caddr_t)ph.p_vaddr;
519		ofw_claim(p,(ph.p_filesz > ph.p_memsz) ?
520		    ph.p_filesz : ph.p_memsz,0);
521		if (fsread(ino, p, ph.p_filesz) != ph.p_filesz) {
522			printf("Can't read content of section %d\n", i);
523			return;
524		}
525		if (ph.p_filesz != ph.p_memsz)
526			bzero(p + ph.p_filesz, ph.p_memsz - ph.p_filesz);
527		__syncicache(p, ph.p_memsz);
528	}
529	ofw_close(bootdev);
530	(*(void (*)(void *, int, ofwfp_t, char *, int))eh.e_entry)(NULL, 0,
531	    ofw,NULL,0);
532}
533
534static int
535dskread(void *buf, u_int64_t lba, int nblk)
536{
537	/*
538	 * The Open Firmware should open the correct partition for us.
539	 * That means, if we read from offset zero on an open instance handle,
540	 * we should read from offset zero of that partition.
541	 */
542	ofw_seek(bootdev, lba * DEV_BSIZE);
543	ofw_read(bootdev, buf, nblk * DEV_BSIZE);
544	return (0);
545}
546
547static void
548panic(const char *fmt, ...)
549{
550	char buf[128];
551	va_list ap;
552
553	va_start(ap, fmt);
554	vsnprintf(buf, sizeof buf, fmt, ap);
555	printf("panic: %s\n", buf);
556	va_end(ap);
557
558	exit(1);
559}
560
561static int
562printf(const char *fmt, ...)
563{
564	va_list ap;
565	int ret;
566
567	/* Don't annoy the user as we probe for partitions */
568	if (strcmp(fmt,"Not ufs\n") == 0)
569		return 0;
570
571	va_start(ap, fmt);
572	ret = vprintf(fmt, ap);
573	va_end(ap);
574	return (ret);
575}
576
577static int
578putchar(char c, void *arg)
579{
580	char buf;
581
582	if (c == '\n') {
583		buf = '\r';
584		ofw_write(stdouth, &buf, 1);
585	}
586	buf = c;
587	ofw_write(stdouth, &buf, 1);
588	return (1);
589}
590
591static int
592vprintf(const char *fmt, va_list ap)
593{
594	int ret;
595
596	ret = __printf(fmt, putchar, 0, ap);
597	return (ret);
598}
599
600static int
601vsnprintf(char *str, size_t sz, const char *fmt, va_list ap)
602{
603	struct sp_data sp;
604	int ret;
605
606	sp.sp_buf = str;
607	sp.sp_len = 0;
608	sp.sp_size = sz;
609	ret = __printf(fmt, __sputc, &sp, ap);
610	return (ret);
611}
612
613static int
614__printf(const char *fmt, putc_func_t *putc, void *arg, va_list ap)
615{
616	char buf[(sizeof(long) * 8) + 1];
617	char *nbuf;
618	u_long ul;
619	u_int ui;
620	int lflag;
621	int sflag;
622	char *s;
623	int pad;
624	int ret;
625	int c;
626
627	nbuf = &buf[sizeof buf - 1];
628	ret = 0;
629	while ((c = *fmt++) != 0) {
630		if (c != '%') {
631			ret += putc(c, arg);
632			continue;
633		}
634		lflag = 0;
635		sflag = 0;
636		pad = 0;
637reswitch:	c = *fmt++;
638		switch (c) {
639		case '#':
640			sflag = 1;
641			goto reswitch;
642		case '%':
643			ret += putc('%', arg);
644			break;
645		case 'c':
646			c = va_arg(ap, int);
647			ret += putc(c, arg);
648			break;
649		case 'd':
650			if (lflag == 0) {
651				ui = (u_int)va_arg(ap, int);
652				if (ui < (int)ui) {
653					ui = -ui;
654					ret += putc('-', arg);
655				}
656				s = __uitoa(nbuf, ui, 10);
657			} else {
658				ul = (u_long)va_arg(ap, long);
659				if (ul < (long)ul) {
660					ul = -ul;
661					ret += putc('-', arg);
662				}
663				s = __ultoa(nbuf, ul, 10);
664			}
665			ret += __puts(s, putc, arg);
666			break;
667		case 'l':
668			lflag = 1;
669			goto reswitch;
670		case 'o':
671			if (lflag == 0) {
672				ui = (u_int)va_arg(ap, u_int);
673				s = __uitoa(nbuf, ui, 8);
674			} else {
675				ul = (u_long)va_arg(ap, u_long);
676				s = __ultoa(nbuf, ul, 8);
677			}
678			ret += __puts(s, putc, arg);
679			break;
680		case 'p':
681			ul = (u_long)va_arg(ap, void *);
682			s = __ultoa(nbuf, ul, 16);
683			ret += __puts("0x", putc, arg);
684			ret += __puts(s, putc, arg);
685			break;
686		case 's':
687			s = va_arg(ap, char *);
688			ret += __puts(s, putc, arg);
689			break;
690		case 'u':
691			if (lflag == 0) {
692				ui = va_arg(ap, u_int);
693				s = __uitoa(nbuf, ui, 10);
694			} else {
695				ul = va_arg(ap, u_long);
696				s = __ultoa(nbuf, ul, 10);
697			}
698			ret += __puts(s, putc, arg);
699			break;
700		case 'x':
701			if (lflag == 0) {
702				ui = va_arg(ap, u_int);
703				s = __uitoa(nbuf, ui, 16);
704			} else {
705				ul = va_arg(ap, u_long);
706				s = __ultoa(nbuf, ul, 16);
707			}
708			if (sflag)
709				ret += __puts("0x", putc, arg);
710			ret += __puts(s, putc, arg);
711			break;
712		case '0': case '1': case '2': case '3': case '4':
713		case '5': case '6': case '7': case '8': case '9':
714			pad = pad * 10 + c - '0';
715			goto reswitch;
716		default:
717			break;
718		}
719	}
720	return (ret);
721}
722
723static int
724__sputc(char c, void *arg)
725{
726	struct sp_data *sp;
727
728	sp = arg;
729	if (sp->sp_len < sp->sp_size)
730		sp->sp_buf[sp->sp_len++] = c;
731	sp->sp_buf[sp->sp_len] = '\0';
732	return (1);
733}
734
735static int
736__puts(const char *s, putc_func_t *putc, void *arg)
737{
738	const char *p;
739	int ret;
740
741	ret = 0;
742	for (p = s; *p != '\0'; p++)
743		ret += putc(*p, arg);
744	return (ret);
745}
746
747static char *
748__uitoa(char *buf, u_int ui, int base)
749{
750	char *p;
751
752	p = buf;
753	*p = '\0';
754	do
755		*--p = digits[ui % base];
756	while ((ui /= base) != 0);
757	return (p);
758}
759
760static char *
761__ultoa(char *buf, u_long ul, int base)
762{
763	char *p;
764
765	p = buf;
766	*p = '\0';
767	do
768		*--p = digits[ul % base];
769	while ((ul /= base) != 0);
770	return (p);
771}
772