boot1.c revision 95339
1131377Stjr/*
2312335Sdelphij * Copyright (c) 1998 Robert Nordier
3131377Stjr * All rights reserved.
417651Speter * Copyright (c) 2001 Robert Drehmel
517651Speter * All rights reserved.
617651Speter *
717651Speter * Redistribution and use in source and binary forms are freely
8131377Stjr * permitted provided that the above copyright notice and this
917651Speter * paragraph and the following disclaimer are duplicated in all
1017651Speter * such forms.
11311285Sdelphij *
12311285Sdelphij * This software is provided "AS IS" and without any express or
13131377Stjr * implied warranties, including, without limitation, the implied
1417651Speter * warranties of merchantability and fitness for a particular
15131377Stjr * purpose.
16131377Stjr *
17131377Stjr */
18131377Stjr
19131377Stjr#include <sys/cdefs.h>
20131377Stjr__FBSDID("$FreeBSD: head/sys/boot/sparc64/boot1/boot1.c 95339 2002-04-24 02:10:35Z jake $");
21131377Stjr
2217651Speter#include <sys/param.h>
23131377Stjr#include <sys/reboot.h>
2417651Speter#include <sys/diskslice.h>
25131377Stjr#include <sys/disklabel.h>
26131377Stjr#include <sys/dirent.h>
27131377Stjr#include <machine/elf.h>
28131377Stjr#include <machine/stdarg.h>
29131377Stjr
3017651Speter#include <ufs/ffs/fs.h>
31131377Stjr#include <ufs/ufs/dinode.h>
3217651Speter
33131377Stjr#define _PATH_LOADER	"/boot/loader"
34131377Stjr#define _PATH_KERNEL	"/boot/kernel/kernel"
35131377Stjr
3617651Speter#define BSIZEMAX	8192
37131377Stjr
3817651Speter/*
39131377Stjr * This structure will be refined along with the addition of a bootpath
40131377Stjr * parsing routine when it is necessary to cope with bootpaths that are
41131377Stjr * not in the exact <devpath>@<controller>,<disk>:<partition> format and
42131377Stjr * for which we need to evaluate the disklabel ourselves.
43131377Stjr */
4417651Speterstruct disk {
45131377Stjr	int meta;
46131377Stjr};
47131377Stjrstruct disk dsk;
48131377Stjr
49131377Stjrextern uint32_t _end;
50206905Sdelphij
51131377Stjrstatic char bname[1024];	/* name of the binary to load */
52131377Stjrstatic uint32_t fs_off;
53131377Stjr
54131377Stjrint main(void);
55250224Sdelphijvoid exit(int);
56250224Sdelphijstatic void load(const char *);
57131377Stjrstatic ino_t lookup(const char *);
58131377Stjrstatic ssize_t fsread(ino_t, void *, size_t);
59131377Stjrstatic int dskread(void *, u_int64_t, int);
60157043Sdesstatic int printf(const char *, ...);
61157043Sdesstatic int putchar(int);
62157043Sdes
63131377Stjrstatic void *memcpy(void *, const void *, size_t);
64131377Stjrstatic void *memset(void *, int, size_t);
65205194Sdelphij
66131377Stjr/*
67131377Stjr * Open Firmware interface functions
68131377Stjr */
69131377Stjrtypedef u_int64_t	ofwcell_t;
70131377Stjrtypedef int32_t		ofwh_t;
71131377Stjrtypedef u_int32_t	u_ofwh_t;
72131377Stjrtypedef int (*ofwfp_t)(ofwcell_t []);
73205194Sdelphijofwfp_t ofw;			/* the prom Open Firmware entry */
74131377Stjr
75131377Stjrvoid ofw_init(int, int, int, int, ofwfp_t);
76131377Stjrofwh_t ofw_finddevice(const char *);
77131377Stjrofwh_t ofw_open(const char *);
78131377Stjrint ofw_getprop(ofwh_t, const char *, void *, size_t);
79131377Stjrint ofw_read(ofwh_t, void *, size_t);
80131377Stjrint ofw_write(ofwh_t, const void *, size_t);
81131377Stjrint ofw_seek(ofwh_t, u_int64_t);
82311285Sdelphij
83131377Stjrofwh_t bootdevh;
84311285Sdelphijofwh_t stdinh, stdouth;
85131377Stjrchar bootpath[64];
86131377Stjr
87157043Sdes/*
88157043Sdes * This has to stay here, as the PROM seems to ignore the
89157043Sdes * entry point specified in the a.out header.  (or elftoaout is broken)
90131377Stjr */
91131377Stjr
92205194Sdelphijvoid
93131377Stjrofw_init(int d, int d1, int d2, int d3, ofwfp_t ofwaddr)
94131377Stjr{
95131377Stjr	ofwh_t chosenh;
96131377Stjr
97131377Stjr	ofw = ofwaddr;
98131377Stjr
99131377Stjr	chosenh = ofw_finddevice("/chosen");
100131377Stjr	ofw_getprop(chosenh, "stdin", &stdinh, sizeof(stdinh));
101131377Stjr	ofw_getprop(chosenh, "stdout", &stdouth, sizeof(stdouth));
102131377Stjr	ofw_getprop(chosenh, "bootpath", bootpath, sizeof(bootpath));
103131377Stjr
104131377Stjr	if ((bootdevh = ofw_open(bootpath)) == -1) {
105311285Sdelphij		printf("Could not open boot device.\n");
106131377Stjr	}
107311285Sdelphij
108131377Stjr	main();
109131377Stjr	d = d1 = d2 = d3;	/* make GCC happy */
110205194Sdelphij}
111131377Stjr
112205194Sdelphijofwh_t
113131377Stjrofw_finddevice(const char *name)
114131377Stjr{
115205194Sdelphij	ofwcell_t args[] = {
116131377Stjr		(ofwcell_t)"finddevice",
117205194Sdelphij		1,
118131377Stjr		1,
119205194Sdelphij		(ofwcell_t)name,
120311285Sdelphij		0
121131377Stjr	};
122131377Stjr
123205194Sdelphij	if ((*ofw)(args)) {
124131377Stjr		printf("ofw_finddevice: name=\"%s\"\n", name);
125131377Stjr		return (1);
126131377Stjr	}
127311285Sdelphij	return (args[4]);
128131377Stjr}
129131377Stjr
130131377Stjrint
131131377Stjrofw_getprop(ofwh_t ofwh, const char *name, void *buf, size_t len)
132131377Stjr{
13317651Speter	ofwcell_t args[] = {
134131377Stjr		(ofwcell_t)"getprop",
135131377Stjr		4,
136311285Sdelphij		1,
137131377Stjr		(u_ofwh_t)ofwh,
138311285Sdelphij		(ofwcell_t)name,
139131377Stjr		(ofwcell_t)buf,
14092111Sgreen		len,
141205194Sdelphij	0
142131377Stjr	};
143205194Sdelphij
144131377Stjr	if ((*ofw)(args)) {
145131377Stjr		printf("ofw_getprop: ofwh=0x%x buf=%p len=%u\n",
146205194Sdelphij			ofwh, buf, len);
147131377Stjr		return (1);
148205194Sdelphij	}
149131377Stjr	return (0);
150131377Stjr}
151311285Sdelphij
152131377Stjrofwh_t
153131377Stjrofw_open(const char *path)
154311285Sdelphij{
155131377Stjr	ofwcell_t args[] = {
156131377Stjr		(ofwcell_t)"open",
157131377Stjr		1,
158131377Stjr		1,
159157043Sdes		(ofwcell_t)path,
160157043Sdes		0
161157043Sdes	};
162157043Sdes
163157043Sdes	if ((*ofw)(args)) {
164157043Sdes		printf("ofw_open: path=\"%s\"\n", path);
165157043Sdes		return (-1);
166131377Stjr	}
167131377Stjr	return (args[4]);
168131377Stjr}
169131377Stjr
170131377Stjrint
171131377Stjrofw_close(ofwh_t devh)
172131377Stjr{
173205194Sdelphij	ofwcell_t args[] = {
174205194Sdelphij		(ofwcell_t)"close",
175205194Sdelphij		1,
176205194Sdelphij		0,
177205194Sdelphij		(u_ofwh_t)devh
178205194Sdelphij	};
179205194Sdelphij
180205194Sdelphij	if ((*ofw)(args)) {
181205194Sdelphij		printf("ofw_close: devh=0x%x\n", devh);
182311285Sdelphij		return (1);
183205194Sdelphij	}
184205194Sdelphij	return (0);
185205194Sdelphij}
186205194Sdelphij
187205194Sdelphijint
188311285Sdelphijofw_read(ofwh_t devh, void *buf, size_t len)
189205194Sdelphij{
190205194Sdelphij	ofwcell_t args[] = {
191205194Sdelphij		(ofwcell_t)"read",
192205194Sdelphij		4,
193311285Sdelphij		1,
194205194Sdelphij		(u_ofwh_t)devh,
195205194Sdelphij		(ofwcell_t)buf,
196205194Sdelphij		len,
197205194Sdelphij		0
198131377Stjr	};
199311285Sdelphij
200205194Sdelphij	if ((*ofw)(args)) {
201131377Stjr		printf("ofw_read: devh=0x%x buf=%p len=%u\n", devh, buf, len);
202131377Stjr		return (1);
203131377Stjr	}
204131377Stjr	return (0);
205311285Sdelphij}
206131377Stjr
207131377Stjrint
208131377Stjrofw_write(ofwh_t devh, const void *buf, size_t len)
209131377Stjr{
210205194Sdelphij	ofwcell_t args[] = {
211205194Sdelphij		(ofwcell_t)"write",
212205194Sdelphij		3,
213131377Stjr		1,
214131377Stjr		(u_ofwh_t)devh,
215131377Stjr		(ofwcell_t)buf,
216311285Sdelphij		len,
217131377Stjr		0
218311285Sdelphij	};
219205194Sdelphij
220205194Sdelphij	if ((*ofw)(args)) {
221131377Stjr		printf("ofw_write: devh=0x%x buf=%p len=%u\n", devh, buf, len);
222131377Stjr		return (1);
223311285Sdelphij	}
224131377Stjr	return (0);
225131377Stjr}
226131377Stjr
227131377Stjrint
228131377Stjrofw_seek(ofwh_t devh, u_int64_t off)
229131377Stjr{
230205194Sdelphij	ofwcell_t args[] = {
231131377Stjr		(ofwcell_t)"seek",
232131377Stjr		4,
233131377Stjr		1,
234311285Sdelphij		(u_ofwh_t)devh,
235131377Stjr		off >> 32,
236131377Stjr		off,
237131377Stjr		0
238131377Stjr	};
239131377Stjr
240311285Sdelphij	if ((*ofw)(args)) {
241311285Sdelphij		printf("ofw_seek: devh=0x%x off=0x%lx\n", devh, off);
242311285Sdelphij		return (1);
243131377Stjr	}
244131377Stjr	return (0);
245131377Stjr}
246311285Sdelphij
247131377Stjrstatic int
248311285Sdelphijstrcmp(const char *s1, const char *s2)
249131377Stjr{
250131377Stjr	for (; *s1 == *s2 && *s1; s1++, s2++)
251131377Stjr		;
252131377Stjr	return ((u_char)*s1 - (u_char)*s2);
253131377Stjr}
254311285Sdelphij
255311285Sdelphijstatic void *
256311285Sdelphijmemset(void *dst, int val, size_t len)
257131377Stjr{
258131377Stjr	void *ret;
259131377Stjr
260311285Sdelphij	ret = dst;
261131377Stjr	while (len) {
262311285Sdelphij		*((char *)dst)++ = val;
263131377Stjr		len--;
264131377Stjr	}
265131377Stjr	return (ret);
266131377Stjr}
267205194Sdelphij
268131377Stjrstatic int
269131377Stjrfsfind(const char *name, ino_t * ino)
270131377Stjr{
271131377Stjr	char buf[DEV_BSIZE];
272131377Stjr	struct dirent *d;
273131377Stjr	char *s;
274131377Stjr	ssize_t n;
275131377Stjr
276131377Stjr	fs_off = 0;
277205194Sdelphij	while ((n = fsread(*ino, buf, DEV_BSIZE)) > 0) {
278131377Stjr		for (s = buf; s < buf + DEV_BSIZE;) {
279131377Stjr			d = (void *)s;
280131377Stjr			if (!strcmp(name, d->d_name)) {
281131377Stjr				*ino = d->d_fileno;
282131377Stjr				return (d->d_type);
28317651Speter			}
28417651Speter			s += d->d_reclen;
285131377Stjr		}
286131377Stjr	}
287131377Stjr	return (0);
288131377Stjr}
289131377Stjr
290131377Stjrstatic void
29117651Speterputc(int c)
292131377Stjr{
293131377Stjr	char d;
294131377Stjr
295131377Stjr	d = c;
296131377Stjr	ofw_write(stdouth, &d, 1);
297131377Stjr}
298131377Stjr
299311285Sdelphijint
300311285Sdelphijmain(void)
301131377Stjr{
302131377Stjr	if (bname[0] == '\0')
303131377Stjr		memcpy(bname, _PATH_LOADER, sizeof(_PATH_LOADER));
304131377Stjr
305131377Stjr	printf(" \n>> FreeBSD/sparc64 boot block\n"
306131377Stjr	"   Boot path:   %s\n"
30717651Speter	"   Boot loader: %s\n", bootpath, _PATH_LOADER);
308131377Stjr	load(bname);
309131377Stjr	return (1);
310131377Stjr}
311131377Stjr
312131377Stjrstatic void
313205194Sdelphijload(const char *fname)
314131377Stjr{
315131377Stjr	Elf64_Ehdr eh;
316131377Stjr	Elf64_Phdr ph;
317131377Stjr	caddr_t p;
318131377Stjr	ino_t ino;
319131377Stjr	int i;
320131377Stjr
321131377Stjr	if ((ino = lookup(fname)) == 0) {
322131377Stjr		printf("File %s not found\n", fname);
323131377Stjr		return;
324	}
325	if (fsread(ino, &eh, sizeof(eh)) != sizeof(eh)) {
326		printf("Can't read elf header\n");
327		return;
328	}
329	if (!IS_ELF(eh)) {
330		printf("Not an ELF file\n");
331		return;
332	}
333	for (i = 0; i < eh.e_phnum; i++) {
334		fs_off = eh.e_phoff + i * eh.e_phentsize;
335		if (fsread(ino, &ph, sizeof(ph)) != sizeof(ph)) {
336			printf("Can't read program header %d\n", i);
337			return;
338		}
339		if (ph.p_type != PT_LOAD)
340			continue;
341		fs_off = ph.p_offset;
342		p = (caddr_t)ph.p_vaddr;
343		if (fsread(ino, p, ph.p_filesz) != ph.p_filesz) {
344			printf("Can't read content of section %d\n", i);
345			return;
346		}
347		if (ph.p_filesz != ph.p_memsz)
348			memset(p + ph.p_filesz, 0, ph.p_memsz - ph.p_filesz);
349	}
350	ofw_close(bootdevh);
351	(*(void (*)(int, int, int, int, ofwfp_t))eh.e_entry)(0, 0, 0, 0, ofw);
352}
353
354static ino_t
355lookup(const char *path)
356{
357	char name[MAXNAMLEN + 1];
358	const char *s;
359	ino_t ino;
360	ssize_t n;
361	int dt;
362
363	ino = ROOTINO;
364	dt = DT_DIR;
365	name[0] = '/';
366	name[1] = '\0';
367	for (;;) {
368		if (*path == '/')
369			path++;
370		if (!*path)
371			break;
372		for (s = path; *s && *s != '/'; s++)
373			;
374		if ((n = s - path) > MAXNAMLEN)
375			return (0);
376		memcpy(name, path, n);
377		name[n] = 0;
378		if (dt != DT_DIR) {
379			printf("%s: not a directory.\n", name);
380			return (0);
381		}
382		if ((dt = fsfind(name, &ino)) <= 0)
383			break;
384		path = s;
385	}
386	return (dt == DT_REG ? ino : 0);
387}
388
389static ssize_t
390fsread(ino_t inode, void *buf, size_t nbyte)
391{
392	static struct fs fs;
393	static struct dinode din;
394	static char blkbuf[BSIZEMAX];
395	static ufs_daddr_t indbuf[BSIZEMAX / sizeof(ufs_daddr_t)];
396	static ino_t inomap;
397	static ufs_daddr_t blkmap, indmap;
398	static unsigned int fsblks;
399	char *s;
400	ufs_daddr_t lbn, addr;
401	size_t n, nb, off;
402
403	if (!dsk.meta) {
404		inomap = 0;
405		if (dskread(blkbuf, SBOFF / DEV_BSIZE, SBSIZE / DEV_BSIZE))
406			return (-1);
407		memcpy(&fs, blkbuf, sizeof(fs));
408		if (fs.fs_magic != FS_MAGIC) {
409			printf("Not ufs\n");
410			return (-1);
411		}
412		fsblks = fs.fs_bsize >> DEV_BSHIFT;
413		dsk.meta++;
414	}
415	if (!inode)
416		return (0);
417	if (inomap != inode) {
418		if (dskread(blkbuf, fsbtodb(&fs, ino_to_fsba(&fs, inode)),
419		    fsblks))
420			return (-1);
421		din = ((struct dinode *)blkbuf)[inode % INOPB(&fs)];
422		inomap = inode;
423		fs_off = 0;
424		blkmap = indmap = 0;
425	}
426	s = buf;
427	if (nbyte > (n = din.di_size - fs_off))
428		nbyte = n;
429	nb = nbyte;
430	while (nb) {
431		lbn = lblkno(&fs, fs_off);
432		if (lbn < NDADDR)
433			addr = din.di_db[lbn];
434		else {
435			if (indmap != din.di_ib[0]) {
436				if (dskread(indbuf, fsbtodb(&fs, din.di_ib[0]),
437				    fsblks))
438					return (-1);
439				indmap = din.di_ib[0];
440			}
441			addr = indbuf[(lbn - NDADDR) % NINDIR(&fs)];
442		}
443		n = dblksize(&fs, &din, lbn);
444		if (blkmap != addr) {
445			if (dskread(blkbuf, fsbtodb(&fs, addr),
446			    n >> DEV_BSHIFT)) {
447				return (-1);
448			}
449			blkmap = addr;
450		}
451		off = blkoff(&fs, fs_off);
452		n -= off;
453		if (n > nb)
454			n = nb;
455		memcpy(s, blkbuf + off, n);
456		s += n;
457		fs_off += n;
458		nb -= n;
459	}
460	return (nbyte);
461}
462
463static int
464dskread(void *buf, u_int64_t lba, int nblk)
465{
466	/*
467	 * The OpenFirmware should open the correct partition for us.
468	 * That means, if we read from offset zero on an open instance handle,
469	 * we should read from offset zero of that partition.
470	 */
471	ofw_seek(bootdevh, lba * DEV_BSIZE);
472	ofw_read(bootdevh, buf, nblk * DEV_BSIZE);
473	return (0);
474}
475
476static int
477printf(const char *fmt,...)
478{
479	static const char digits[16] = "0123456789abcdef";
480	va_list ap;
481	char buf[10];
482	char *s;
483	unsigned long int r, u;
484	int c, longp;
485
486	va_start(ap, fmt);
487	longp = 0;
488	while ((c = *fmt++)) {
489		if (c == '%' || longp) {
490			if (c == '%')
491				c = *fmt++;
492			switch (c) {
493			case 'c':
494				if (longp)
495					break;
496				putchar(va_arg(ap, int));
497				continue;
498			case 's':
499				if (longp)
500					break;
501				for (s = va_arg(ap, char *); *s; s++)
502					putchar(*s);
503				continue;
504			case 'p':
505				if (longp)
506					break;
507				if (c == 'p') {
508					putchar('0');
509					putchar('x');
510				}
511			case 'u':
512			case 'x':
513				r = c == 'u' ? 10U : 16U;
514				u = (c == 'p' || longp) ?
515				    va_arg(ap, unsigned long) :
516				    va_arg(ap, unsigned int);
517				s = buf;
518				do
519					*s++ = digits[u % r];
520				while (u /= r);
521				while (--s >= buf)
522					putchar(*s);
523				longp = 0;
524				continue;
525			case 'l':
526				if (longp)
527					break;
528				longp = 1;
529				continue;
530			}
531			longp = 0;
532		}
533		putchar(c);
534	}
535	va_end(ap);
536	return (0);
537}
538
539static int
540putchar(int c)
541{
542	if (c == '\n')
543		putc('\r');
544	putc(c);
545	return (c);
546}
547
548static void *
549memcpy(void *dst, const void *src, size_t size)
550{
551	const char *s;
552	char *d;
553
554	for (d = dst, s = src; size; size--)
555		*d++ = *s++;
556	return (dst);
557}
558