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: stable/11/stand/powerpc/boot1.chrp/boot1.c 332154 2018-04-06 21:37:25Z kevans $");
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
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 *, uint64_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
79/*
80 * Open Firmware interface functions
81 */
82typedef uint32_t	ofwcell_t;
83typedef uint32_t	u_ofwh_t;
84typedef int (*ofwfp_t)(void *);
85ofwfp_t ofw;			/* the prom Open Firmware entry */
86ofwh_t chosenh;
87
88void ofw_init(void *, int, int (*)(void *), char *, int);
89static ofwh_t ofw_finddevice(const char *);
90static ofwh_t ofw_open(const char *);
91static int ofw_close(ofwh_t);
92static int ofw_getprop(ofwh_t, const char *, void *, size_t);
93static int ofw_setprop(ofwh_t, const char *, void *, size_t);
94static int ofw_read(ofwh_t, void *, size_t);
95static int ofw_write(ofwh_t, const void *, size_t);
96static int ofw_claim(void *virt, size_t len, u_int align);
97static int ofw_seek(ofwh_t, uint64_t);
98static void ofw_exit(void) __dead2;
99
100ofwh_t bootdevh;
101ofwh_t stdinh, stdouth;
102
103__asm("                         \n\
104        .data                   \n\
105	.align 4		\n\
106stack:                          \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
119void
120ofw_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
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, 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
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		/* 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
456out:
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
463static void
464usage(void)
465{
466
467	printf("usage: boot device [/path/to/loader]\n");
468	exit(1);
469}
470
471static void
472exit(int code)
473{
474
475	ofw_exit();
476}
477
478static struct dmadat __dmadat;
479
480static int
481domount(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
497static void
498load(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
543static int
544dskread(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
556static void
557panic(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
570static int
571printf(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
582static int
583putchar(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
596static int
597vprintf(const char *fmt, va_list ap)
598{
599	int ret;
600
601	ret = __printf(fmt, putchar, 0, ap);
602	return (ret);
603}
604
605static int
606vsnprintf(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
618static 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;
642reswitch:	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
728static 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
740static 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
752static 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
765static 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