boot1.c revision 91295
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
19#include <sys/cdefs.h>
20__FBSDID("$FreeBSD: head/sys/boot/sparc64/boot1/boot1.c 91295 2002-02-26 10:05:20Z robert $");
21
22#include <sys/param.h>
23#include <sys/reboot.h>
24#include <sys/diskslice.h>
25#include <sys/disklabel.h>
26#include <sys/dirent.h>
27#include <machine/elf.h>
28#include <machine/stdarg.h>
29
30#include <ufs/ffs/fs.h>
31#include <ufs/ufs/dinode.h>
32
33#include <a.out.h>
34
35#define RBX_ASKNAME	0x0	/* -a */
36#define RBX_SINGLE	0x1	/* -s */
37#define RBX_DFLTROOT	0x5	/* -r */
38#define RBX_KDB 	0x6	/* -d */
39#define RBX_CONFIG	0xa	/* -c */
40#define RBX_VERBOSE	0xb	/* -v */
41#define RBX_CDROM	0xd	/* -C */
42#define RBX_GDB 	0xf	/* -g */
43
44#define RBX_MASK	0x2000ffff
45
46#define PATH_CONFIG	"/boot.config"
47#define PATH_LOADER	"/boot/loader"
48#define PATH_KERNEL	"/kernel"
49
50#define ARGS		0x900
51#define NOPT		11
52#define BSIZEMAX	8192
53#define NDEV		5
54
55#define TYPE_AD		0
56#define TYPE_WD		1
57#define TYPE_WFD 	2
58#define TYPE_FD		3
59#define TYPE_DA		4
60
61/*
62 * This structure will be refined along with the addition of a bootpath
63 * parsing routine when it is necessary to cope with bootpaths that are
64 * not in the exact <devpath>@<controller>,<disk>:<partition> format and
65 * for which we need to evaluate the disklabel ourselves.
66 */
67struct disk {
68	int meta;
69};
70struct disk dsk;
71
72extern uint32_t _end;
73
74static const char optstr[NOPT] = "aCcgrsv";
75static const unsigned char flags[NOPT] = {
76	RBX_ASKNAME,
77	RBX_CDROM,
78	RBX_CONFIG,
79	RBX_GDB,
80	RBX_DFLTROOT,
81	RBX_SINGLE,
82	RBX_VERBOSE
83};
84
85static char cmd[512];		/* command to parse */
86static char bname[1024];	/* name of the binary to load */
87static uint32_t opts;
88static int ls;
89static uint32_t fs_off;
90
91int main(void);
92void exit(int);
93static void load(const char *);
94static int parse(char *);
95static ino_t lookup(const char *);
96static int xfsread(ino_t, void *, size_t);
97static ssize_t fsread(ino_t, void *, size_t);
98static int dskread(void *, u_int64_t, int);
99static int printf(const char *, ...);
100static int putchar(int);
101static int keyhit(unsigned int);
102static int getc(void);
103
104static void *memcpy(void *, const void *, size_t);
105static void *memset(void *, int, size_t);
106static void *malloc(size_t);
107
108/*
109 * Open Firmware interface functions
110 */
111typedef u_int64_t	ofwcell_t;
112typedef int32_t		ofwh_t;
113typedef u_int32_t	u_ofwh_t;
114typedef int (*ofwfp_t)(ofwcell_t []);
115ofwfp_t ofw;			/* the prom Open Firmware entry */
116
117void ofw_init(int, int, int, int, ofwfp_t);
118ofwh_t ofw_finddevice(const char *);
119ofwh_t ofw_open(const char *);
120int ofw_getprop(ofwh_t, const char *, void *, size_t);
121int ofw_read(ofwh_t, void *, size_t);
122int ofw_write(ofwh_t, const void *, size_t);
123int ofw_seek(ofwh_t, u_int64_t);
124
125ofwh_t bootdevh;
126ofwh_t stdinh, stdouth;
127char bootpath[64];
128
129/*
130 * This has to stay here, as the PROM seems to ignore the
131 * entry point specified in the a.out header.  (or elftoaout is broken)
132 */
133
134void
135ofw_init(int d, int d1, int d2, int d3, ofwfp_t ofwaddr)
136{
137	ofwh_t chosenh;
138
139	ofw = ofwaddr;
140
141	chosenh = ofw_finddevice("/chosen");
142	ofw_getprop(chosenh, "stdin", &stdinh, sizeof(stdinh));
143	ofw_getprop(chosenh, "stdout", &stdouth, sizeof(stdouth));
144	ofw_getprop(chosenh, "bootpath", bootpath, sizeof(bootpath));
145
146	if ((bootdevh = ofw_open(bootpath)) == -1) {
147		printf("Could not open boot device.\n");
148	}
149
150	main();
151	d = d1 = d2 = d3;	/* make GCC happy */
152}
153
154ofwh_t
155ofw_finddevice(const char *name)
156{
157	ofwcell_t args[] = {
158		(ofwcell_t)"finddevice",
159		1,
160		1,
161		(ofwcell_t)name,
162		0
163	};
164
165	if ((*ofw)(args)) {
166		printf("ofw_finddevice: name=\"%s\"\n", name);
167		return (1);
168	}
169	return (args[4]);
170}
171
172int
173ofw_getprop(ofwh_t ofwh, const char *name, void *buf, size_t len)
174{
175	ofwcell_t args[] = {
176		(ofwcell_t)"getprop",
177		4,
178		1,
179		(u_ofwh_t)ofwh,
180		(ofwcell_t)name,
181		(ofwcell_t)buf,
182		len,
183	0
184	};
185
186	if ((*ofw)(args)) {
187		printf("ofw_getprop: ofwh=0x%x buf=%p len=%u\n",
188			ofwh, buf, len);
189		return (1);
190	}
191	return (0);
192}
193
194ofwh_t
195ofw_open(const char *path)
196{
197	ofwcell_t args[] = {
198		(ofwcell_t)"open",
199		1,
200		1,
201		(ofwcell_t)path,
202		0
203	};
204
205	if ((*ofw)(args)) {
206		printf("ofw_open: path=\"%s\"\n", path);
207		return (-1);
208	}
209	return (args[4]);
210}
211
212int
213ofw_close(ofwh_t devh)
214{
215	ofwcell_t args[] = {
216		(ofwcell_t)"close",
217		1,
218		0,
219		(u_ofwh_t)devh
220	};
221
222	if ((*ofw)(args)) {
223		printf("ofw_close: devh=0x%x\n", devh);
224		return (1);
225	}
226	return (0);
227}
228
229int
230ofw_read(ofwh_t devh, void *buf, size_t len)
231{
232	ofwcell_t args[] = {
233		(ofwcell_t)"read",
234		4,
235		1,
236		(u_ofwh_t)devh,
237		(ofwcell_t)buf,
238		len,
239		0
240	};
241
242	if ((*ofw)(args)) {
243		printf("ofw_read: devh=0x%x buf=%p len=%u\n", devh, buf, len);
244		return (1);
245	}
246	return (0);
247}
248
249int
250ofw_write(ofwh_t devh, const void *buf, size_t len)
251{
252	ofwcell_t args[] = {
253		(ofwcell_t)"write",
254		3,
255		1,
256		(u_ofwh_t)devh,
257		(ofwcell_t)buf,
258		len,
259		0
260	};
261
262	if ((*ofw)(args)) {
263		printf("ofw_write: devh=0x%x buf=%p len=%u\n", devh, buf, len);
264		return (1);
265	}
266	return (0);
267}
268
269int
270ofw_seek(ofwh_t devh, u_int64_t off)
271{
272	ofwcell_t args[] = {
273		(ofwcell_t)"seek",
274		4,
275		1,
276		(u_ofwh_t)devh,
277		off >> 32,
278		off & ((1UL << 32) - 1),
279		0
280	};
281
282	if ((*ofw)(args)) {
283		printf("ofw_seek: devh=0x%x off=0x%lx\n", devh, off);
284		return (1);
285	}
286	return (0);
287}
288
289static void
290readfile(const char *fname, void *buf, size_t size)
291{
292	ino_t ino;
293
294	if ((ino = lookup(fname)))
295		fsread(ino, buf, size);
296}
297
298static int
299strcmp(const char *s1, const char *s2)
300{
301	for (; *s1 == *s2 && *s1; s1++, s2++)
302		;
303	return ((u_char)*s1 - (u_char)*s2);
304}
305
306static void *
307memset(void *dst, int val, size_t len)
308{
309	void *ret;
310
311	ret = dst;
312	while (len) {
313		*((char *)dst)++ = val;
314		len--;
315	}
316	return (ret);
317}
318
319static int
320fsfind(const char *name, ino_t * ino)
321{
322	char buf[DEV_BSIZE];
323	struct dirent *d;
324	char *s;
325	ssize_t n;
326
327	fs_off = 0;
328	while ((n = fsread(*ino, buf, DEV_BSIZE)) > 0) {
329		for (s = buf; s < buf + DEV_BSIZE;) {
330			d = (void *)s;
331			if (ls)
332				printf("%s ", d->d_name);
333			else if (!strcmp(name, d->d_name)) {
334				*ino = d->d_fileno;
335				return (d->d_type);
336			}
337			s += d->d_reclen;
338		}
339	}
340	if (n != -1 && ls)
341		putchar('\n');
342	return (0);
343}
344
345static int
346getchar(void)
347{
348	int c;
349
350	c = getc();
351	if (c == '\r')
352		c = '\n';
353	return (c);
354}
355
356static void
357getstr(char *str, int size)
358{
359	char *s;
360	int c;
361
362	s = str;
363	do {
364		switch (c = getchar()) {
365		case 0:
366			break;
367		case '\b':
368		case '\177':
369			if (s > str) {
370				s--;
371				putchar('\b');
372				putchar(' ');
373			} else
374				c = 0;
375			break;
376		case '\n':
377			*s = 0;
378			break;
379		default:
380			if (s - str < size - 1)
381				*s++ = c;
382		}
383		if (c)
384			putchar(c);
385	} while (c != '\n');
386}
387
388static void
389putc(int c)
390{
391	char d;
392
393	d = c;
394	ofw_write(stdouth, &d, 1);
395}
396
397int main(void)
398{
399	readfile(PATH_CONFIG, cmd, sizeof(cmd));
400	if (cmd[0] != '\0') {
401		printf("%s: %s", PATH_CONFIG, cmd);
402		if (parse(cmd))
403			cmd[0] = '\0';
404	}
405	if (bname[0] == '\0')
406		memcpy(bname, PATH_LOADER, sizeof(PATH_LOADER));
407
408	printf(" \n>> FreeBSD/sparc64 boot block\n"
409	"   Boot path:   %s\n"
410	"   Boot loader: %s\n", bootpath, PATH_LOADER);
411	load(bname);
412	return (1);
413}
414
415static void
416load(const char *fname)
417{
418	Elf64_Ehdr eh;
419	Elf64_Phdr ep[2];
420	Elf64_Shdr es[2];
421	caddr_t p;
422	ino_t ino;
423	vm_offset_t entry;
424	int i, j;
425
426	if ((ino = lookup(fname)) == 0) {
427		if (!ls)
428			printf("File %s not found\n", fname);
429		return;
430	}
431	if (xfsread(ino, &eh, sizeof(eh)))
432		return;
433	if (!IS_ELF(eh)) {
434		printf("Not an ELF file\n");
435		return;
436	}
437	fs_off = eh.e_phoff;
438	for (j = i = 0; i < eh.e_phnum && j < 2; i++) {
439		if (xfsread(ino, ep + j, sizeof(ep[0])))
440			return;
441		if (ep[j].p_type == PT_LOAD)
442			j++;
443	}
444	for (i = 0; i < j; i++) {
445		p = (caddr_t)ep[i].p_vaddr;
446		fs_off = ep[i].p_offset;
447		if (xfsread(ino, p, ep[i].p_filesz))
448			return;
449		/*
450		 * Assume the second program header table entry
451		 * to contain data and bss.  Clear out the .bss section.
452		 */
453		if (i == 1) {
454			memset(p + ep[i].p_filesz, 0,
455			    ep[i].p_memsz - ep[i].p_filesz);
456		}
457	}
458	p += roundup2(ep[1].p_memsz, PAGE_SIZE);
459	if (eh.e_shnum == eh.e_shstrndx + 3) {
460		fs_off = eh.e_shoff + sizeof(es[0]) * (eh.e_shstrndx + 1);
461		if (xfsread(ino, &es, sizeof(es)))
462			return;
463		for (i = 0; i < 2; i++) {
464			memcpy(p, &es[i].sh_size, sizeof(es[i].sh_size));
465			p += sizeof(es[i].sh_size);
466			fs_off = es[i].sh_offset;
467			if (xfsread(ino, p, es[i].sh_size))
468				return;
469			p += es[i].sh_size;
470		}
471	}
472	entry = eh.e_entry;
473	ofw_close(bootdevh);
474	(*(void (*)(int, int, int, int, ofwfp_t))entry)(0, 0, 0, 0, ofw);
475}
476
477static int
478parse(char *arg)
479{
480	char *p;
481	int c, i;
482
483	while ((c = *arg++)) {
484		if (c == ' ' || c == '\t' || c == '\n')
485			continue;
486		for (p = arg; *p && *p != '\n' && *p != ' ' && *p != '\t'; p++)
487			;
488		if (*p)
489			*p++ = 0;
490		if (c == '-') {
491			while ((c = *arg++)) {
492				for (i = 0; c != optstr[i]; i++)
493					if (i == NOPT - 1)
494						return (-1);
495				opts ^= 1 << flags[i];
496			}
497		}
498		arg = p;
499	}
500	return (0);
501}
502
503static ino_t
504lookup(const char *path)
505{
506	char name[MAXNAMLEN + 1];
507	const char *s;
508	ino_t ino;
509	ssize_t n;
510	int dt;
511
512	ino = ROOTINO;
513	dt = DT_DIR;
514	for (;;) {
515		if (*path == '/')
516			path++;
517		if (!*path)
518			break;
519		for (s = path; *s && *s != '/'; s++)
520			;
521		if ((n = s - path) > MAXNAMLEN)
522			return (0);
523		ls = *path == '?' && n == 1 && !*s;
524		memcpy(name, path, n);
525		name[n] = 0;
526		if ((dt = fsfind(name, &ino)) <= 0)
527			break;
528		path = s;
529	}
530	return (dt == DT_REG ? ino : 0);
531}
532
533static int
534xfsread(ino_t inode, void *buf, size_t nbyte)
535{
536	if (fsread(inode, buf, nbyte) != (ssize_t)nbyte) {
537		printf("Invalid %s\n", "format");
538		return (-1);
539	}
540	return (0);
541}
542
543static ssize_t
544fsread(ino_t inode, void *buf, size_t nbyte)
545{
546	static struct fs fs;
547	static struct dinode din;
548	static char *blkbuf;
549	static ufs_daddr_t *indbuf;
550	static ino_t inomap;
551	static ufs_daddr_t blkmap, indmap;
552	static unsigned int fsblks;
553	char *s;
554	ufs_daddr_t lbn, addr;
555	size_t n, nb, off;
556
557	if (!dsk.meta) {
558		if (!blkbuf)
559			blkbuf = malloc(BSIZEMAX);
560		inomap = 0;
561		if (dskread(blkbuf, SBOFF / DEV_BSIZE, SBSIZE / DEV_BSIZE))
562			return (-1);
563		memcpy(&fs, blkbuf, sizeof(fs));
564		if (fs.fs_magic != FS_MAGIC) {
565			printf("Not ufs\n");
566				return (-1);
567		}
568		fsblks = fs.fs_bsize >> DEV_BSHIFT;
569		dsk.meta++;
570	}
571	if (!inode)
572		return (0);
573	if (inomap != inode) {
574		if (dskread(blkbuf, fsbtodb(&fs, ino_to_fsba(&fs, inode)),
575		    fsblks))
576			return (-1);
577		din = ((struct dinode *)blkbuf)[inode % INOPB(&fs)];
578		inomap = inode;
579		fs_off = 0;
580		blkmap = indmap = 0;
581	}
582	s = buf;
583	if (nbyte > (n = din.di_size - fs_off))
584		nbyte = n;
585	nb = nbyte;
586	while (nb) {
587		lbn = lblkno(&fs, fs_off);
588		if (lbn < NDADDR)
589			addr = din.di_db[lbn];
590		else {
591			if (indmap != din.di_ib[0]) {
592				if (!indbuf)
593					indbuf = malloc(BSIZEMAX);
594				if (dskread(indbuf, fsbtodb(&fs, din.di_ib[0]),
595				    fsblks))
596					return (-1);
597				indmap = din.di_ib[0];
598			}
599			addr = indbuf[(lbn - NDADDR) % NINDIR(&fs)];
600		}
601		n = dblksize(&fs, &din, lbn);
602		if (blkmap != addr) {
603			if (dskread(blkbuf, fsbtodb(&fs, addr),
604			    n >> DEV_BSHIFT)) {
605				return (-1);
606			}
607			blkmap = addr;
608		}
609		off = blkoff(&fs, fs_off);
610		n -= off;
611		if (n > nb)
612			n = nb;
613		memcpy(s, blkbuf + off, n);
614		s += n;
615		fs_off += n;
616		nb -= n;
617	}
618	return (nbyte);
619}
620
621static int
622dskread(void *buf, u_int64_t lba, int nblk)
623{
624	/*
625	 * The OpenFirmware should open the correct partition for us.
626	 * That means, if we read from offset zero on an open instance handle,
627	 * we should read from offset zero of that partition.
628	 */
629	ofw_seek(bootdevh, lba * DEV_BSIZE);
630	ofw_read(bootdevh, buf, nblk * DEV_BSIZE);
631	return (0);
632}
633
634static int
635printf(const char *fmt,...)
636{
637	static const char digits[16] = "0123456789abcdef";
638	va_list ap;
639	char buf[10];
640	char *s;
641	unsigned long int r, u;
642	int c;
643
644	va_start(ap, fmt);
645	while ((c = *fmt++)) {
646		if (c == '%') {
647			c = *fmt++;
648			switch (c) {
649			case 'c':
650				putchar(va_arg(ap, int));
651				continue;
652			case 's':
653				for (s = va_arg(ap, char *); *s; s++)
654					putchar(*s);
655				continue;
656			case 'p':
657				if (c == 'p') {
658					putchar('0');
659					putchar('x');
660				}
661			case 'u':
662			case 'x':
663				r = c == 'u' ? 10U : 16U;
664				u = c == 'p' ? va_arg(ap, unsigned long) :
665				    va_arg(ap, unsigned int);
666				s = buf;
667				do
668					*s++ = digits[u % r];
669				while (u /= r);
670				while (--s >= buf)
671					putchar(*s);
672				continue;
673			}
674		}
675		putchar(c);
676	}
677	va_end(ap);
678	return (0);
679}
680
681static int
682putchar(int c)
683{
684	if (c == '\n')
685		putc('\r');
686	putc(c);
687	return (c);
688}
689
690static void *
691memcpy(void *dst, const void *src, size_t size)
692{
693	const char *s;
694	char *d;
695
696	for (d = dst, s = src; size; size--)
697		*d++ = *s++;
698	return (dst);
699}
700
701static void *
702malloc(size_t size)
703{
704	static vm_offset_t next = 0x10000;
705	void *p;
706
707	if (size & 0xf)
708		size = (size + 0xf) & ~0xf;
709	p = (void *)next;
710	next += size;
711	return (p);
712}
713
714static int
715keyhit(unsigned int ticks)
716{
717	/* XXX */
718	return (0);
719	ticks = ticks;		/* make GCC happy */
720}
721
722static int
723getc(void)
724{
725	char c;
726	ofw_read(stdinh, &c, 1);
727	return (c);
728}
729