boot1.c revision 234898
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: head/sys/boot/sparc64/boot1/boot1.c 234898 2012-05-01 17:16:01Z marius $");
20
21#include <sys/param.h>
22#include <sys/dirent.h>
23
24#include <machine/elf.h>
25#include <machine/stdarg.h>
26
27#define	_PATH_LOADER	"/boot/loader"
28#define	_PATH_KERNEL	"/boot/kernel/kernel"
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 mount(const char *device);
64static int dskread(void *buf, u_int64_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 u_int64_t	ofwcell_t;
82typedef u_int32_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, u_int64_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, u_int64_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 (mount(bootpath) == -1)
351		panic("mount");
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 = (soff + bytes + DEV_BSIZE - 1) / 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	ino_t ino;
419	int i;
420
421	if (zbread((char *)&eh, 0, sizeof(eh)) != sizeof(eh)) {
422		printf("Can't read elf header\n");
423		return;
424	}
425	if (!IS_ELF(eh)) {
426		printf("Not an ELF file\n");
427		return;
428	}
429	for (i = 0; i < eh.e_phnum; i++) {
430		fs_off = eh.e_phoff + i * eh.e_phentsize;
431		if (zbread((char *)&ph, fs_off, sizeof(ph)) != sizeof(ph)) {
432			printf("Can't read program header %d\n", i);
433			return;
434		}
435		if (ph.p_type != PT_LOAD)
436			continue;
437		fs_off = ph.p_offset;
438		p = (caddr_t)ph.p_vaddr;
439		if (zbread(p, fs_off, ph.p_filesz) != ph.p_filesz) {
440			printf("Can't read content of section %d\n", i);
441			return;
442		}
443		if (ph.p_filesz != ph.p_memsz)
444			bzero(p + ph.p_filesz, ph.p_memsz - ph.p_filesz);
445	}
446	ofw_close(bootdev);
447	(*(void (*)(int, int, int, int, ofwfp_t))eh.e_entry)(0, 0, 0, 0, ofw);
448}
449
450#else
451
452#include "ufsread.c"
453
454static struct dmadat __dmadat;
455
456static void
457load(const char *fname)
458{
459	Elf64_Ehdr eh;
460	Elf64_Phdr ph;
461	caddr_t p;
462	ino_t ino;
463	int i;
464
465	if ((ino = lookup(fname)) == 0) {
466		printf("File %s not found\n", fname);
467		return;
468	}
469	if (fsread(ino, &eh, sizeof(eh)) != sizeof(eh)) {
470		printf("Can't read elf header\n");
471		return;
472	}
473	if (!IS_ELF(eh)) {
474		printf("Not an ELF file\n");
475		return;
476	}
477	for (i = 0; i < eh.e_phnum; i++) {
478		fs_off = eh.e_phoff + i * eh.e_phentsize;
479		if (fsread(ino, &ph, sizeof(ph)) != sizeof(ph)) {
480			printf("Can't read program header %d\n", i);
481			return;
482		}
483		if (ph.p_type != PT_LOAD)
484			continue;
485		fs_off = ph.p_offset;
486		p = (caddr_t)ph.p_vaddr;
487		if (fsread(ino, p, ph.p_filesz) != ph.p_filesz) {
488			printf("Can't read content of section %d\n", i);
489			return;
490		}
491		if (ph.p_filesz != ph.p_memsz)
492			bzero(p + ph.p_filesz, ph.p_memsz - ph.p_filesz);
493	}
494	ofw_close(bootdev);
495	(*(void (*)(int, int, int, int, ofwfp_t))eh.e_entry)(0, 0, 0, 0, ofw);
496}
497
498#endif /* ZFSBOOT */
499
500static int
501mount(const char *device)
502{
503
504	if ((bootdev = ofw_open(device)) == -1) {
505		printf("mount: can't open device\n");
506		return (-1);
507	}
508#ifndef ZFSBOOT
509	dmadat = &__dmadat;
510	if (fsread(0, NULL, 0)) {
511		printf("mount: can't read superblock\n");
512		return (-1);
513	}
514#endif
515	return (0);
516}
517
518static int
519dskread(void *buf, u_int64_t lba, int nblk)
520{
521
522	/*
523	 * The Open Firmware should open the correct partition for us.
524	 * That means, if we read from offset zero on an open instance handle,
525	 * we should read from offset zero of that partition.
526	 */
527	ofw_seek(bootdev, lba * DEV_BSIZE);
528	ofw_read(bootdev, buf, nblk * DEV_BSIZE);
529	return (0);
530}
531
532static void
533panic(const char *fmt, ...)
534{
535	char buf[128];
536	va_list ap;
537
538	va_start(ap, fmt);
539	vsnprintf(buf, sizeof buf, fmt, ap);
540	printf("panic: %s\n", buf);
541	va_end(ap);
542
543	exit(1);
544}
545
546static int
547printf(const char *fmt, ...)
548{
549	va_list ap;
550	int ret;
551
552	va_start(ap, fmt);
553	ret = vprintf(fmt, ap);
554	va_end(ap);
555	return (ret);
556}
557
558static int
559putchar(char c, void *arg)
560{
561	char buf;
562
563	if (c == '\n') {
564		buf = '\r';
565		ofw_write(stdouth, &buf, 1);
566	}
567	buf = c;
568	ofw_write(stdouth, &buf, 1);
569	return (1);
570}
571
572static int
573vprintf(const char *fmt, va_list ap)
574{
575	int ret;
576
577	ret = __printf(fmt, putchar, 0, ap);
578	return (ret);
579}
580
581static int
582vsnprintf(char *str, size_t sz, const char *fmt, va_list ap)
583{
584	struct sp_data sp;
585	int ret;
586
587	sp.sp_buf = str;
588	sp.sp_len = 0;
589	sp.sp_size = sz;
590	ret = __printf(fmt, __sputc, &sp, ap);
591	return (ret);
592}
593
594static int
595__printf(const char *fmt, putc_func_t *putc, void *arg, va_list ap)
596{
597	char buf[(sizeof(long) * 8) + 1];
598	char *nbuf;
599	u_long ul;
600	u_int ui;
601	int lflag;
602	int sflag;
603	char *s;
604	int pad;
605	int ret;
606	int c;
607
608	nbuf = &buf[sizeof buf - 1];
609	ret = 0;
610	while ((c = *fmt++) != 0) {
611		if (c != '%') {
612			ret += putc(c, arg);
613			continue;
614		}
615		lflag = 0;
616		sflag = 0;
617		pad = 0;
618reswitch:	c = *fmt++;
619		switch (c) {
620		case '#':
621			sflag = 1;
622			goto reswitch;
623		case '%':
624			ret += putc('%', arg);
625			break;
626		case 'c':
627			c = va_arg(ap, int);
628			ret += putc(c, arg);
629			break;
630		case 'd':
631			if (lflag == 0) {
632				ui = (u_int)va_arg(ap, int);
633				if (ui < (int)ui) {
634					ui = -ui;
635					ret += putc('-', arg);
636				}
637				s = __uitoa(nbuf, ui, 10);
638			} else {
639				ul = (u_long)va_arg(ap, long);
640				if (ul < (long)ul) {
641					ul = -ul;
642					ret += putc('-', arg);
643				}
644				s = __ultoa(nbuf, ul, 10);
645			}
646			ret += __puts(s, putc, arg);
647			break;
648		case 'l':
649			lflag = 1;
650			goto reswitch;
651		case 'o':
652			if (lflag == 0) {
653				ui = (u_int)va_arg(ap, u_int);
654				s = __uitoa(nbuf, ui, 8);
655			} else {
656				ul = (u_long)va_arg(ap, u_long);
657				s = __ultoa(nbuf, ul, 8);
658			}
659			ret += __puts(s, putc, arg);
660			break;
661		case 'p':
662			ul = (u_long)va_arg(ap, void *);
663			s = __ultoa(nbuf, ul, 16);
664			ret += __puts("0x", putc, arg);
665			ret += __puts(s, putc, arg);
666			break;
667		case 's':
668			s = va_arg(ap, char *);
669			ret += __puts(s, putc, arg);
670			break;
671		case 'u':
672			if (lflag == 0) {
673				ui = va_arg(ap, u_int);
674				s = __uitoa(nbuf, ui, 10);
675			} else {
676				ul = va_arg(ap, u_long);
677				s = __ultoa(nbuf, ul, 10);
678			}
679			ret += __puts(s, putc, arg);
680			break;
681		case 'x':
682			if (lflag == 0) {
683				ui = va_arg(ap, u_int);
684				s = __uitoa(nbuf, ui, 16);
685			} else {
686				ul = va_arg(ap, u_long);
687				s = __ultoa(nbuf, ul, 16);
688			}
689			if (sflag)
690				ret += __puts("0x", putc, arg);
691			ret += __puts(s, putc, arg);
692			break;
693		case '0': case '1': case '2': case '3': case '4':
694		case '5': case '6': case '7': case '8': case '9':
695			pad = pad * 10 + c - '0';
696			goto reswitch;
697		default:
698			break;
699		}
700	}
701	return (ret);
702}
703
704static int
705__sputc(char c, void *arg)
706{
707	struct sp_data *sp;
708
709	sp = arg;
710	if (sp->sp_len < sp->sp_size)
711		sp->sp_buf[sp->sp_len++] = c;
712	sp->sp_buf[sp->sp_len] = '\0';
713	return (1);
714}
715
716static int
717__puts(const char *s, putc_func_t *putc, void *arg)
718{
719	const char *p;
720	int ret;
721
722	ret = 0;
723	for (p = s; *p != '\0'; p++)
724		ret += putc(*p, arg);
725	return (ret);
726}
727
728static char *
729__uitoa(char *buf, u_int ui, int base)
730{
731	char *p;
732
733	p = buf;
734	*p = '\0';
735	do
736		*--p = digits[ui % base];
737	while ((ui /= base) != 0);
738	return (p);
739}
740
741static char *
742__ultoa(char *buf, u_long ul, int base)
743{
744	char *p;
745
746	p = buf;
747	*p = '\0';
748	do
749		*--p = digits[ul % base];
750	while ((ul /= base) != 0);
751	return (p);
752}
753