boot1.c revision 133862
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 133862 2004-08-16 15:45:27Z marius $");
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(int 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 ino_t inomap;
49static char blkbuf[BSIZEMAX];
50static unsigned int fsblks;
51
52static uint32_t fs_off;
53
54int main(int ac, char **av);
55
56static void exit(int) __dead2;
57static void load(const char *);
58static int dskread(void *, u_int64_t, int);
59
60static void usage(void);
61
62static void bcopy(const void *src, void *dst, size_t len);
63static void bzero(void *b, size_t len);
64
65static int mount(const char *device);
66
67static void panic(const char *fmt, ...) __dead2;
68static int printf(const char *fmt, ...);
69static int putchar(int c, void *arg);
70static int vprintf(const char *fmt, va_list ap);
71static int vsnprintf(char *str, size_t sz, const char *fmt, va_list ap);
72
73static int __printf(const char *fmt, putc_func_t *putc, void *arg, va_list ap);
74static int __putc(int c, void *arg);
75static int __puts(const char *s, putc_func_t *putc, void *arg);
76static int __sputc(int c, void *arg);
77static char *__uitoa(char *buf, u_int val, int base);
78static char *__ultoa(char *buf, u_long val, int base);
79
80/*
81 * Open Firmware interface functions
82 */
83typedef u_int64_t	ofwcell_t;
84typedef u_int32_t	u_ofwh_t;
85typedef int (*ofwfp_t)(ofwcell_t []);
86ofwfp_t ofw;			/* the prom Open Firmware entry */
87
88void ofw_init(int, int, int, int, ofwfp_t);
89ofwh_t ofw_finddevice(const char *);
90ofwh_t ofw_open(const char *);
91int ofw_getprop(ofwh_t, const char *, void *, size_t);
92int ofw_read(ofwh_t, void *, size_t);
93int ofw_write(ofwh_t, const void *, size_t);
94int ofw_seek(ofwh_t, u_int64_t);
95void ofw_exit(void) __dead2;
96
97ofwh_t bootdevh;
98ofwh_t stdinh, stdouth;
99
100/*
101 * This has to stay here, as the PROM seems to ignore the
102 * entry point specified in the a.out header.  (or elftoaout is broken)
103 */
104
105void
106ofw_init(int d, int d1, int d2, int d3, ofwfp_t ofwaddr)
107{
108	ofwh_t chosenh;
109	char *av[16];
110	char *p;
111	int ac;
112
113	ofw = ofwaddr;
114
115	chosenh = ofw_finddevice("/chosen");
116	ofw_getprop(chosenh, "stdin", &stdinh, sizeof(stdinh));
117	ofw_getprop(chosenh, "stdout", &stdouth, sizeof(stdouth));
118	ofw_getprop(chosenh, "bootargs", bootargs, sizeof(bootargs));
119	ofw_getprop(chosenh, "bootpath", bootpath, sizeof(bootpath));
120
121	bootargs[sizeof(bootargs) - 1] = '\0';
122	bootpath[sizeof(bootpath) - 1] = '\0';
123
124	ac = 0;
125	p = bootargs;
126	for (;;) {
127		while (*p == ' ' && *p != '\0')
128			p++;
129		if (*p == '\0' || ac >= 16)
130			break;
131		av[ac++] = p;
132		while (*p != ' ' && *p != '\0')
133			p++;
134		if (*p != '\0')
135			*p++ = '\0';
136	}
137
138	exit(main(ac, av));
139}
140
141ofwh_t
142ofw_finddevice(const char *name)
143{
144	ofwcell_t args[] = {
145		(ofwcell_t)"finddevice",
146		1,
147		1,
148		(ofwcell_t)name,
149		0
150	};
151
152	if ((*ofw)(args)) {
153		printf("ofw_finddevice: name=\"%s\"\n", name);
154		return (1);
155	}
156	return (args[4]);
157}
158
159int
160ofw_getprop(ofwh_t ofwh, const char *name, void *buf, size_t len)
161{
162	ofwcell_t args[] = {
163		(ofwcell_t)"getprop",
164		4,
165		1,
166		(u_ofwh_t)ofwh,
167		(ofwcell_t)name,
168		(ofwcell_t)buf,
169		len,
170	0
171	};
172
173	if ((*ofw)(args)) {
174		printf("ofw_getprop: ofwh=0x%x buf=%p len=%u\n",
175			ofwh, buf, len);
176		return (1);
177	}
178	return (0);
179}
180
181ofwh_t
182ofw_open(const char *path)
183{
184	ofwcell_t args[] = {
185		(ofwcell_t)"open",
186		1,
187		1,
188		(ofwcell_t)path,
189		0
190	};
191
192	if ((*ofw)(args)) {
193		printf("ofw_open: path=\"%s\"\n", path);
194		return (-1);
195	}
196	return (args[4]);
197}
198
199int
200ofw_close(ofwh_t devh)
201{
202	ofwcell_t args[] = {
203		(ofwcell_t)"close",
204		1,
205		0,
206		(u_ofwh_t)devh
207	};
208
209	if ((*ofw)(args)) {
210		printf("ofw_close: devh=0x%x\n", devh);
211		return (1);
212	}
213	return (0);
214}
215
216int
217ofw_read(ofwh_t devh, void *buf, size_t len)
218{
219	ofwcell_t args[] = {
220		(ofwcell_t)"read",
221		4,
222		1,
223		(u_ofwh_t)devh,
224		(ofwcell_t)buf,
225		len,
226		0
227	};
228
229	if ((*ofw)(args)) {
230		printf("ofw_read: devh=0x%x buf=%p len=%u\n", devh, buf, len);
231		return (1);
232	}
233	return (0);
234}
235
236int
237ofw_write(ofwh_t devh, const void *buf, size_t len)
238{
239	ofwcell_t args[] = {
240		(ofwcell_t)"write",
241		3,
242		1,
243		(u_ofwh_t)devh,
244		(ofwcell_t)buf,
245		len,
246		0
247	};
248
249	if ((*ofw)(args)) {
250		printf("ofw_write: devh=0x%x buf=%p len=%u\n", devh, buf, len);
251		return (1);
252	}
253	return (0);
254}
255
256int
257ofw_seek(ofwh_t devh, u_int64_t off)
258{
259	ofwcell_t args[] = {
260		(ofwcell_t)"seek",
261		4,
262		1,
263		(u_ofwh_t)devh,
264		off >> 32,
265		off,
266		0
267	};
268
269	if ((*ofw)(args)) {
270		printf("ofw_seek: devh=0x%x off=0x%lx\n", devh, off);
271		return (1);
272	}
273	return (0);
274}
275
276void
277ofw_exit(void)
278{
279	ofwcell_t args[3];
280
281	args[0] = (ofwcell_t)"exit";
282	args[1] = 0;
283	args[2] = 0;
284
285	for (;;)
286		(*ofw)(args);
287}
288
289static void
290bcopy(const void *src, void *dst, size_t len)
291{
292	const char *s = src;
293	char *d = dst;
294
295	while (len-- != 0)
296		*d++ = *s++;
297}
298
299static void
300memcpy(void *dst, const void *src, size_t len)
301{
302	bcopy(src, dst, len);
303}
304
305static void
306bzero(void *b, size_t len)
307{
308	char *p = b;
309
310	while (len-- != 0)
311		*p++ = 0;
312}
313
314static int
315strcmp(const char *s1, const char *s2)
316{
317	for (; *s1 == *s2 && *s1; s1++, s2++)
318		;
319	return ((u_char)*s1 - (u_char)*s2);
320}
321
322#include "ufsread.c"
323
324int
325main(int ac, char **av)
326{
327	const char *path;
328	int i;
329
330	path = _PATH_LOADER;
331	for (i = 0; i < ac; i++) {
332		switch (av[i][0]) {
333		case '-':
334			switch (av[i][1]) {
335			default:
336				usage();
337			}
338			break;
339		default:
340			path = av[i];
341			break;
342		}
343	}
344
345	printf(" \n>> FreeBSD/sparc64 boot block\n"
346	"   Boot path:   %s\n"
347	"   Boot loader: %s\n", bootpath, path);
348
349	if (mount(bootpath) == -1)
350		panic("mount");
351
352	load(path);
353	return (1);
354}
355
356static void
357usage(void)
358{
359
360	printf("usage: boot device [/path/to/loader]\n");
361	exit(1);
362}
363
364static void
365exit(int code)
366{
367
368	ofw_exit();
369}
370
371static struct dmadat __dmadat;
372
373static int
374mount(const char *device)
375{
376
377	dmadat = &__dmadat;
378	if ((bootdev = ofw_open(device)) == -1) {
379		printf("mount: can't open device\n");
380		return (-1);
381	}
382	if (fsread(0, NULL, 0)) {
383		printf("mount: can't read superblock\n");
384		return (-1);
385	}
386	return (0);
387}
388
389static void
390load(const char *fname)
391{
392	Elf64_Ehdr eh;
393	Elf64_Phdr ph;
394	caddr_t p;
395	ino_t ino;
396	int i;
397
398	if ((ino = lookup(fname)) == 0) {
399		printf("File %s not found\n", fname);
400		return;
401	}
402	if (fsread(ino, &eh, sizeof(eh)) != sizeof(eh)) {
403		printf("Can't read elf header\n");
404		return;
405	}
406	if (!IS_ELF(eh)) {
407		printf("Not an ELF file\n");
408		return;
409	}
410	for (i = 0; i < eh.e_phnum; i++) {
411		fs_off = eh.e_phoff + i * eh.e_phentsize;
412		if (fsread(ino, &ph, sizeof(ph)) != sizeof(ph)) {
413			printf("Can't read program header %d\n", i);
414			return;
415		}
416		if (ph.p_type != PT_LOAD)
417			continue;
418		fs_off = ph.p_offset;
419		p = (caddr_t)ph.p_vaddr;
420		if (fsread(ino, p, ph.p_filesz) != ph.p_filesz) {
421			printf("Can't read content of section %d\n", i);
422			return;
423		}
424		if (ph.p_filesz != ph.p_memsz)
425			bzero(p + ph.p_filesz, ph.p_memsz - ph.p_filesz);
426	}
427	ofw_close(bootdev);
428	(*(void (*)(int, int, int, int, ofwfp_t))eh.e_entry)(0, 0, 0, 0, ofw);
429}
430
431static int
432dskread(void *buf, u_int64_t lba, int nblk)
433{
434	/*
435	 * The Open Firmware should open the correct partition for us.
436	 * That means, if we read from offset zero on an open instance handle,
437	 * we should read from offset zero of that partition.
438	 */
439	ofw_seek(bootdev, lba * DEV_BSIZE);
440	ofw_read(bootdev, buf, nblk * DEV_BSIZE);
441	return (0);
442}
443
444static void
445panic(const char *fmt, ...)
446{
447	char buf[128];
448	va_list ap;
449
450	va_start(ap, fmt);
451	vsnprintf(buf, sizeof buf, fmt, ap);
452	printf("panic: %s\n", buf);
453	va_end(ap);
454
455	exit(1);
456}
457
458static int
459printf(const char *fmt, ...)
460{
461	va_list ap;
462	int ret;
463
464	va_start(ap, fmt);
465	ret = vprintf(fmt, ap);
466	va_end(ap);
467	return (ret);
468}
469
470static int
471putchar(int c, void *arg)
472{
473	char buf;
474
475	if (c == '\n') {
476		buf = '\r';
477		ofw_write(stdouth, &buf, 1);
478	}
479	buf = c;
480	ofw_write(stdouth, &buf, 1);
481	return (1);
482}
483
484static int
485vprintf(const char *fmt, va_list ap)
486{
487	int ret;
488
489	ret = __printf(fmt, putchar, 0, ap);
490	return (ret);
491}
492
493static int
494vsnprintf(char *str, size_t sz, const char *fmt, va_list ap)
495{
496	struct sp_data sp;
497	int ret;
498
499	sp.sp_buf = str;
500	sp.sp_len = 0;
501	sp.sp_size = sz;
502	ret = __printf(fmt, __sputc, &sp, ap);
503	return (ret);
504}
505
506static int
507__printf(const char *fmt, putc_func_t *putc, void *arg, va_list ap)
508{
509	char buf[(sizeof(long) * 8) + 1];
510	char *nbuf;
511	u_long ul;
512	u_int ui;
513	int lflag;
514	int sflag;
515	char *s;
516	int pad;
517	int ret;
518	int c;
519
520	nbuf = &buf[sizeof buf - 1];
521	ret = 0;
522	while ((c = *fmt++) != 0) {
523		if (c != '%') {
524			ret += putc(c, arg);
525			continue;
526		}
527		lflag = 0;
528		sflag = 0;
529		pad = 0;
530reswitch:	c = *fmt++;
531		switch (c) {
532		case '#':
533			sflag = 1;
534			goto reswitch;
535		case '%':
536			ret += putc('%', arg);
537			break;
538		case 'c':
539			c = va_arg(ap, int);
540			ret += putc(c, arg);
541			break;
542		case 'd':
543			if (lflag == 0) {
544				ui = (u_int)va_arg(ap, int);
545				if (ui < (int)ui) {
546					ui = -ui;
547					ret += putc('-', arg);
548				}
549				s = __uitoa(nbuf, ui, 10);
550			} else {
551				ul = (u_long)va_arg(ap, long);
552				if (ul < (long)ul) {
553					ul = -ul;
554					ret += putc('-', arg);
555				}
556				s = __ultoa(nbuf, ul, 10);
557			}
558			ret += __puts(s, putc, arg);
559			break;
560		case 'l':
561			lflag = 1;
562			goto reswitch;
563		case 'o':
564			if (lflag == 0) {
565				ui = (u_int)va_arg(ap, u_int);
566				s = __uitoa(nbuf, ui, 8);
567			} else {
568				ul = (u_long)va_arg(ap, u_long);
569				s = __ultoa(nbuf, ul, 8);
570			}
571			ret += __puts(s, putc, arg);
572			break;
573		case 'p':
574			ul = (u_long)va_arg(ap, void *);
575			s = __ultoa(nbuf, ul, 16);
576			ret += __puts("0x", putc, arg);
577			ret += __puts(s, putc, arg);
578			break;
579		case 's':
580			s = va_arg(ap, char *);
581			ret += __puts(s, putc, arg);
582			break;
583		case 'u':
584			if (lflag == 0) {
585				ui = va_arg(ap, u_int);
586				s = __uitoa(nbuf, ui, 10);
587			} else {
588				ul = va_arg(ap, u_long);
589				s = __ultoa(nbuf, ul, 10);
590			}
591			ret += __puts(s, putc, arg);
592			break;
593		case 'x':
594			if (lflag == 0) {
595				ui = va_arg(ap, u_int);
596				s = __uitoa(nbuf, ui, 16);
597			} else {
598				ul = va_arg(ap, u_long);
599				s = __ultoa(nbuf, ul, 16);
600			}
601			if (sflag)
602				ret += __puts("0x", putc, arg);
603			ret += __puts(s, putc, arg);
604			break;
605		case '0': case '1': case '2': case '3': case '4':
606		case '5': case '6': case '7': case '8': case '9':
607			pad = pad * 10 + c - '0';
608			goto reswitch;
609		default:
610			break;
611		}
612	}
613	return (ret);
614}
615
616static int
617__sputc(int c, void *arg)
618{
619	struct sp_data *sp;
620
621	sp = arg;
622	if (sp->sp_len < sp->sp_size)
623		sp->sp_buf[sp->sp_len++] = c;
624	sp->sp_buf[sp->sp_len] = '\0';
625	return (1);
626}
627
628static int
629__puts(const char *s, putc_func_t *putc, void *arg)
630{
631	const char *p;
632	int ret;
633
634	ret = 0;
635	for (p = s; *p != '\0'; p++)
636		ret += putc(*p, arg);
637	return (ret);
638}
639
640static char *
641__uitoa(char *buf, u_int ui, int base)
642{
643	char *p;
644
645	p = buf;
646	*p = '\0';
647	do
648		*--p = digits[ui % base];
649	while ((ui /= base) != 0);
650	return (p);
651}
652
653static char *
654__ultoa(char *buf, u_long ul, int base)
655{
656	char *p;
657
658	p = buf;
659	*p = '\0';
660	do
661		*--p = digits[ul % base];
662	while ((ul /= base) != 0);
663	return (p);
664}
665