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/sparc64/boot1/boot1.c 332154 2018-04-06 21:37:25Z kevans $");
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
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 uint32_t fs_off;
48
49int main(int ac, char **av);
50static void exit(int) __dead2;
51static void usage(void);
52
53#ifdef ZFSBOOT
54static void loadzfs(void);
55static int zbread(char *buf, off_t off, size_t bytes);
56#else
57static void load(const char *);
58#endif
59
60static void bcopy(const void *src, void *dst, size_t len);
61static void bzero(void *b, size_t len);
62
63static int domount(const char *device);
64static int dskread(void *buf, uint64_t lba, int nblk);
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 __puts(const char *s, putc_func_t *putc, void *arg);
74static int __sputc(char c, void *arg);
75static char *__uitoa(char *buf, u_int val, int base);
76static char *__ultoa(char *buf, u_long val, int base);
77
78/*
79 * Open Firmware interface functions
80 */
81typedef uint64_t	ofwcell_t;
82typedef uint32_t	u_ofwh_t;
83typedef int (*ofwfp_t)(ofwcell_t []);
84static ofwfp_t ofw;			/* the PROM Open Firmware entry */
85
86void ofw_init(int, int, int, int, ofwfp_t);
87static ofwh_t ofw_finddevice(const char *);
88static ofwh_t ofw_open(const char *);
89static int ofw_getprop(ofwh_t, const char *, void *, size_t);
90static int ofw_read(ofwh_t, void *, size_t);
91static int ofw_write(ofwh_t, const void *, size_t);
92static int ofw_seek(ofwh_t, uint64_t);
93static void ofw_exit(void) __dead2;
94
95static 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
102void
103ofw_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
138static ofwh_t
139ofw_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
156static int
157ofw_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
178static ofwh_t
179ofw_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
196static int
197ofw_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
213static int
214ofw_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
233static int
234ofw_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
253static int
254ofw_seek(ofwh_t devh, uint64_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
273static void
274ofw_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
286static void
287bcopy(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
296static void
297memcpy(void *dst, const void *src, size_t len)
298{
299
300	bcopy(src, dst, len);
301}
302
303static void
304bzero(void *b, size_t len)
305{
306	char *p = b;
307
308	while (len-- != 0)
309		*p++ = 0;
310}
311
312static int
313strcmp(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
321int
322main(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
361static void
362usage(void)
363{
364
365	printf("usage: boot device [/path/to/loader]\n");
366	exit(1);
367}
368
369static void
370exit(int code)
371{
372
373	ofw_exit();
374}
375
376#ifdef ZFSBOOT
377
378#define	VDEV_BOOT_OFFSET	(2 * 256 * 1024)
379static char zbuf[READ_BUF_SIZE];
380
381static int
382zbread(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 = howmany(soff + bytes, 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
412static void
413loadzfs(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
453static struct dmadat __dmadat;
454
455static void
456load(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
499static int
500domount(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
517static int
518dskread(void *buf, uint64_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
531static void
532panic(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
545static int
546printf(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
557static int
558putchar(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
571static int
572vprintf(const char *fmt, va_list ap)
573{
574	int ret;
575
576	ret = __printf(fmt, putchar, 0, ap);
577	return (ret);
578}
579
580static int
581vsnprintf(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
593static 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;
617reswitch:	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
703static 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
715static 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
727static 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
740static 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