boot1.c revision 91678
190699Srobert/*
290699Srobert * Copyright (c) 1998 Robert Nordier
390699Srobert * All rights reserved.
490699Srobert * Copyright (c) 2001 Robert Drehmel
590699Srobert * All rights reserved.
690699Srobert *
790699Srobert * Redistribution and use in source and binary forms are freely
890699Srobert * permitted provided that the above copyright notice and this
990699Srobert * paragraph and the following disclaimer are duplicated in all
1090699Srobert * such forms.
1190699Srobert *
1290699Srobert * This software is provided "AS IS" and without any express or
1390699Srobert * implied warranties, including, without limitation, the implied
1490699Srobert * warranties of merchantability and fitness for a particular
1590699Srobert * purpose.
1690699Srobert *
1790699Srobert */
1891295Srobert
1991295Srobert#include <sys/cdefs.h>
2091295Srobert__FBSDID("$FreeBSD: head/sys/boot/sparc64/boot1/boot1.c 91678 2002-03-05 11:22:43Z robert $");
2191295Srobert
2290699Srobert#include <sys/param.h>
2390699Srobert#include <sys/reboot.h>
2490699Srobert#include <sys/diskslice.h>
2590699Srobert#include <sys/disklabel.h>
2690699Srobert#include <sys/dirent.h>
2790699Srobert#include <machine/elf.h>
2890699Srobert#include <machine/stdarg.h>
2990699Srobert
3090699Srobert#include <ufs/ffs/fs.h>
3190699Srobert#include <ufs/ufs/dinode.h>
3290699Srobert
3390699Srobert#include <a.out.h>
3490699Srobert
3590699Srobert#define RBX_ASKNAME	0x0	/* -a */
3690699Srobert#define RBX_SINGLE	0x1	/* -s */
3790699Srobert#define RBX_DFLTROOT	0x5	/* -r */
3890699Srobert#define RBX_KDB 	0x6	/* -d */
3990699Srobert#define RBX_CONFIG	0xa	/* -c */
4090699Srobert#define RBX_VERBOSE	0xb	/* -v */
4190699Srobert#define RBX_CDROM	0xd	/* -C */
4290699Srobert#define RBX_GDB 	0xf	/* -g */
4390699Srobert
4490699Srobert#define RBX_MASK	0x2000ffff
4590699Srobert
4690699Srobert#define PATH_CONFIG	"/boot.config"
4790699Srobert#define PATH_LOADER	"/boot/loader"
4890699Srobert#define PATH_KERNEL	"/kernel"
4990699Srobert
5090699Srobert#define ARGS		0x900
5190699Srobert#define NOPT		11
5290699Srobert#define BSIZEMAX	8192
5390699Srobert#define NDEV		5
5490699Srobert
5590699Srobert#define TYPE_AD		0
5690699Srobert#define TYPE_WD		1
5790699Srobert#define TYPE_WFD 	2
5890699Srobert#define TYPE_FD		3
5990699Srobert#define TYPE_DA		4
6090699Srobert
6190699Srobert/*
6290699Srobert * This structure will be refined along with the addition of a bootpath
6390699Srobert * parsing routine when it is necessary to cope with bootpaths that are
6490699Srobert * not in the exact <devpath>@<controller>,<disk>:<partition> format and
6590699Srobert * for which we need to evaluate the disklabel ourselves.
6690699Srobert */
6790699Srobertstruct disk {
6890699Srobert	int meta;
6990699Srobert};
7090699Srobertstruct disk dsk;
7190699Srobert
7290699Srobertextern uint32_t _end;
7390699Srobert
7490699Srobertstatic const char optstr[NOPT] = "aCcgrsv";
7590699Srobertstatic const unsigned char flags[NOPT] = {
7691295Srobert	RBX_ASKNAME,
7791295Srobert	RBX_CDROM,
7891295Srobert	RBX_CONFIG,
7991295Srobert	RBX_GDB,
8091295Srobert	RBX_DFLTROOT,
8191295Srobert	RBX_SINGLE,
8291295Srobert	RBX_VERBOSE
8390699Srobert};
8490699Srobert
8590699Srobertstatic char cmd[512];		/* command to parse */
8690699Srobertstatic char bname[1024];	/* name of the binary to load */
8790699Srobertstatic uint32_t opts;
8890699Srobertstatic int ls;
8990699Srobertstatic uint32_t fs_off;
9090699Srobert
9190699Srobertint main(void);
9290699Srobertvoid exit(int);
9390699Srobertstatic void load(const char *);
9490699Srobertstatic int parse(char *);
9590699Srobertstatic ino_t lookup(const char *);
9690699Srobertstatic int xfsread(ino_t, void *, size_t);
9790699Srobertstatic ssize_t fsread(ino_t, void *, size_t);
9890699Srobertstatic int dskread(void *, u_int64_t, int);
9990699Srobertstatic int printf(const char *, ...);
10090699Srobertstatic int putchar(int);
10190699Srobertstatic int keyhit(unsigned int);
10290699Srobertstatic int getc(void);
10390699Srobert
10490699Srobertstatic void *memcpy(void *, const void *, size_t);
10590699Srobertstatic void *memset(void *, int, size_t);
10690699Srobertstatic void *malloc(size_t);
10790699Srobert
10890699Srobert/*
10990699Srobert * Open Firmware interface functions
11090699Srobert */
11190699Sroberttypedef u_int64_t	ofwcell_t;
11290699Sroberttypedef int32_t		ofwh_t;
11390699Sroberttypedef u_int32_t	u_ofwh_t;
11490699Sroberttypedef int (*ofwfp_t)(ofwcell_t []);
11590699Srobertofwfp_t ofw;			/* the prom Open Firmware entry */
11690699Srobert
11790699Srobertvoid ofw_init(int, int, int, int, ofwfp_t);
11890699Srobertofwh_t ofw_finddevice(const char *);
11990699Srobertofwh_t ofw_open(const char *);
12090699Srobertint ofw_getprop(ofwh_t, const char *, void *, size_t);
12190699Srobertint ofw_read(ofwh_t, void *, size_t);
12290699Srobertint ofw_write(ofwh_t, const void *, size_t);
12390699Srobertint ofw_seek(ofwh_t, u_int64_t);
12490699Srobert
12590699Srobertofwh_t bootdevh;
12690699Srobertofwh_t stdinh, stdouth;
12790699Srobertchar bootpath[64];
12890699Srobert
12990699Srobert/*
13090699Srobert * This has to stay here, as the PROM seems to ignore the
13190699Srobert * entry point specified in the a.out header.  (or elftoaout is broken)
13290699Srobert */
13390699Srobert
13490699Srobertvoid
13590699Srobertofw_init(int d, int d1, int d2, int d3, ofwfp_t ofwaddr)
13690699Srobert{
13790699Srobert	ofwh_t chosenh;
13890699Srobert
13990699Srobert	ofw = ofwaddr;
14090699Srobert
14190699Srobert	chosenh = ofw_finddevice("/chosen");
14290699Srobert	ofw_getprop(chosenh, "stdin", &stdinh, sizeof(stdinh));
14390699Srobert	ofw_getprop(chosenh, "stdout", &stdouth, sizeof(stdouth));
14490699Srobert	ofw_getprop(chosenh, "bootpath", bootpath, sizeof(bootpath));
14590699Srobert
14690699Srobert	if ((bootdevh = ofw_open(bootpath)) == -1) {
14790699Srobert		printf("Could not open boot device.\n");
14890699Srobert	}
14990699Srobert
15090699Srobert	main();
15190699Srobert	d = d1 = d2 = d3;	/* make GCC happy */
15290699Srobert}
15390699Srobert
15490699Srobertofwh_t
15590699Srobertofw_finddevice(const char *name)
15690699Srobert{
15791295Srobert	ofwcell_t args[] = {
15891295Srobert		(ofwcell_t)"finddevice",
15991295Srobert		1,
16091295Srobert		1,
16191295Srobert		(ofwcell_t)name,
16291295Srobert		0
16391295Srobert	};
16491295Srobert
16591295Srobert	if ((*ofw)(args)) {
16691295Srobert		printf("ofw_finddevice: name=\"%s\"\n", name);
16791295Srobert		return (1);
16891295Srobert	}
16991295Srobert	return (args[4]);
17090699Srobert}
17190699Srobert
17290699Srobertint
17390699Srobertofw_getprop(ofwh_t ofwh, const char *name, void *buf, size_t len)
17490699Srobert{
17591295Srobert	ofwcell_t args[] = {
17691295Srobert		(ofwcell_t)"getprop",
17791295Srobert		4,
17891295Srobert		1,
17991295Srobert		(u_ofwh_t)ofwh,
18091295Srobert		(ofwcell_t)name,
18191295Srobert		(ofwcell_t)buf,
18291295Srobert		len,
18390699Srobert	0
18491295Srobert	};
18591295Srobert
18691295Srobert	if ((*ofw)(args)) {
18791295Srobert		printf("ofw_getprop: ofwh=0x%x buf=%p len=%u\n",
18891295Srobert			ofwh, buf, len);
18991295Srobert		return (1);
19091295Srobert	}
19191295Srobert	return (0);
19290699Srobert}
19390699Srobert
19490699Srobertofwh_t
19590699Srobertofw_open(const char *path)
19690699Srobert{
19791295Srobert	ofwcell_t args[] = {
19891295Srobert		(ofwcell_t)"open",
19991295Srobert		1,
20091295Srobert		1,
20191295Srobert		(ofwcell_t)path,
20291295Srobert		0
20391295Srobert	};
20491295Srobert
20591295Srobert	if ((*ofw)(args)) {
20691295Srobert		printf("ofw_open: path=\"%s\"\n", path);
20791295Srobert		return (-1);
20891295Srobert	}
20991295Srobert	return (args[4]);
21090699Srobert}
21190699Srobert
21290699Srobertint
21390699Srobertofw_close(ofwh_t devh)
21490699Srobert{
21591295Srobert	ofwcell_t args[] = {
21691295Srobert		(ofwcell_t)"close",
21791295Srobert		1,
21891295Srobert		0,
21991295Srobert		(u_ofwh_t)devh
22091295Srobert	};
22191295Srobert
22291295Srobert	if ((*ofw)(args)) {
22391295Srobert		printf("ofw_close: devh=0x%x\n", devh);
22491295Srobert		return (1);
22591295Srobert	}
22691295Srobert	return (0);
22790699Srobert}
22890699Srobert
22990699Srobertint
23090699Srobertofw_read(ofwh_t devh, void *buf, size_t len)
23190699Srobert{
23291295Srobert	ofwcell_t args[] = {
23391295Srobert		(ofwcell_t)"read",
23491295Srobert		4,
23591295Srobert		1,
23691295Srobert		(u_ofwh_t)devh,
23791295Srobert		(ofwcell_t)buf,
23891295Srobert		len,
23991295Srobert		0
24091295Srobert	};
24191295Srobert
24291295Srobert	if ((*ofw)(args)) {
24391295Srobert		printf("ofw_read: devh=0x%x buf=%p len=%u\n", devh, buf, len);
24491295Srobert		return (1);
24591295Srobert	}
24691295Srobert	return (0);
24790699Srobert}
24890699Srobert
24990699Srobertint
25090699Srobertofw_write(ofwh_t devh, const void *buf, size_t len)
25190699Srobert{
25291295Srobert	ofwcell_t args[] = {
25391295Srobert		(ofwcell_t)"write",
25491295Srobert		3,
25591295Srobert		1,
25691295Srobert		(u_ofwh_t)devh,
25791295Srobert		(ofwcell_t)buf,
25891295Srobert		len,
25991295Srobert		0
26091295Srobert	};
26191295Srobert
26291295Srobert	if ((*ofw)(args)) {
26391295Srobert		printf("ofw_write: devh=0x%x buf=%p len=%u\n", devh, buf, len);
26491295Srobert		return (1);
26591295Srobert	}
26691295Srobert	return (0);
26790699Srobert}
26890699Srobert
26990699Srobertint
27090699Srobertofw_seek(ofwh_t devh, u_int64_t off)
27190699Srobert{
27291295Srobert	ofwcell_t args[] = {
27391295Srobert		(ofwcell_t)"seek",
27491295Srobert		4,
27591295Srobert		1,
27691295Srobert		(u_ofwh_t)devh,
27791295Srobert		off >> 32,
27891678Srobert		off,
27991295Srobert		0
28091295Srobert	};
28191295Srobert
28291295Srobert	if ((*ofw)(args)) {
28391295Srobert		printf("ofw_seek: devh=0x%x off=0x%lx\n", devh, off);
28491295Srobert		return (1);
28591295Srobert	}
28691295Srobert	return (0);
28790699Srobert}
28890699Srobert
28990699Srobertstatic void
29090699Srobertreadfile(const char *fname, void *buf, size_t size)
29190699Srobert{
29291295Srobert	ino_t ino;
29390699Srobert
29491295Srobert	if ((ino = lookup(fname)))
29591295Srobert		fsread(ino, buf, size);
29690699Srobert}
29790699Srobert
29890699Srobertstatic int
29990699Srobertstrcmp(const char *s1, const char *s2)
30090699Srobert{
30191295Srobert	for (; *s1 == *s2 && *s1; s1++, s2++)
30291295Srobert		;
30391295Srobert	return ((u_char)*s1 - (u_char)*s2);
30490699Srobert}
30590699Srobert
30690699Srobertstatic void *
30790699Srobertmemset(void *dst, int val, size_t len)
30890699Srobert{
30991295Srobert	void *ret;
31091295Srobert
31191295Srobert	ret = dst;
31290699Srobert	while (len) {
31390699Srobert		*((char *)dst)++ = val;
31490699Srobert		len--;
31590699Srobert	}
31691295Srobert	return (ret);
31790699Srobert}
31890699Srobert
31990699Srobertstatic int
32090699Srobertfsfind(const char *name, ino_t * ino)
32190699Srobert{
32291295Srobert	char buf[DEV_BSIZE];
32391295Srobert	struct dirent *d;
32491295Srobert	char *s;
32591295Srobert	ssize_t n;
32690699Srobert
32791295Srobert	fs_off = 0;
32891295Srobert	while ((n = fsread(*ino, buf, DEV_BSIZE)) > 0) {
32991295Srobert		for (s = buf; s < buf + DEV_BSIZE;) {
33091295Srobert			d = (void *)s;
33191295Srobert			if (ls)
33291295Srobert				printf("%s ", d->d_name);
33391295Srobert			else if (!strcmp(name, d->d_name)) {
33491295Srobert				*ino = d->d_fileno;
33591295Srobert				return (d->d_type);
33691295Srobert			}
33791295Srobert			s += d->d_reclen;
33891295Srobert		}
33990699Srobert	}
34091295Srobert	if (n != -1 && ls)
34191295Srobert		putchar('\n');
34291295Srobert	return (0);
34390699Srobert}
34490699Srobert
34590699Srobertstatic int
34690699Srobertgetchar(void)
34790699Srobert{
34891295Srobert	int c;
34990699Srobert
35091295Srobert	c = getc();
35191295Srobert	if (c == '\r')
35291295Srobert		c = '\n';
35391295Srobert	return (c);
35490699Srobert}
35590699Srobert
35690699Srobertstatic void
35790699Srobertgetstr(char *str, int size)
35890699Srobert{
35991295Srobert	char *s;
36091295Srobert	int c;
36190699Srobert
36291295Srobert	s = str;
36391295Srobert	do {
36491295Srobert		switch (c = getchar()) {
36591295Srobert		case 0:
36691295Srobert			break;
36791295Srobert		case '\b':
36891295Srobert		case '\177':
36991295Srobert			if (s > str) {
37091295Srobert				s--;
37191295Srobert				putchar('\b');
37291295Srobert				putchar(' ');
37391295Srobert			} else
37491295Srobert				c = 0;
37591295Srobert			break;
37691295Srobert		case '\n':
37791295Srobert			*s = 0;
37891295Srobert			break;
37991295Srobert		default:
38091295Srobert			if (s - str < size - 1)
38191295Srobert				*s++ = c;
38291295Srobert		}
38391295Srobert		if (c)
38491295Srobert			putchar(c);
38591295Srobert	} while (c != '\n');
38690699Srobert}
38790699Srobert
38890699Srobertstatic void
38990699Srobertputc(int c)
39090699Srobert{
39191295Srobert	char d;
39291295Srobert
39391295Srobert	d = c;
39490699Srobert	ofw_write(stdouth, &d, 1);
39590699Srobert}
39690699Srobert
39790699Srobertint main(void)
39890699Srobert{
39991295Srobert	readfile(PATH_CONFIG, cmd, sizeof(cmd));
40091295Srobert	if (cmd[0] != '\0') {
40191295Srobert		printf("%s: %s", PATH_CONFIG, cmd);
40291295Srobert		if (parse(cmd))
40391295Srobert			cmd[0] = '\0';
40491295Srobert	}
40591295Srobert	if (bname[0] == '\0')
40691295Srobert		memcpy(bname, PATH_LOADER, sizeof(PATH_LOADER));
40790699Srobert
40891295Srobert	printf(" \n>> FreeBSD/sparc64 boot block\n"
40990699Srobert	"   Boot path:   %s\n"
41090699Srobert	"   Boot loader: %s\n", bootpath, PATH_LOADER);
41191295Srobert	load(bname);
41291295Srobert	return (1);
41390699Srobert}
41490699Srobert
41590699Srobertstatic void
41690699Srobertload(const char *fname)
41790699Srobert{
41891295Srobert	Elf64_Ehdr eh;
41991295Srobert	Elf64_Phdr ep[2];
42091295Srobert	Elf64_Shdr es[2];
42191295Srobert	caddr_t p;
42291295Srobert	ino_t ino;
42391295Srobert	vm_offset_t entry;
42491295Srobert	int i, j;
42590699Srobert
42691295Srobert	if ((ino = lookup(fname)) == 0) {
42791295Srobert		if (!ls)
42891295Srobert			printf("File %s not found\n", fname);
42990699Srobert		return;
43090699Srobert	}
43191295Srobert	if (xfsread(ino, &eh, sizeof(eh)))
43291295Srobert		return;
43391295Srobert	if (!IS_ELF(eh)) {
43491295Srobert		printf("Not an ELF file\n");
43591295Srobert		return;
43691295Srobert	}
43791295Srobert	fs_off = eh.e_phoff;
43891295Srobert	for (j = i = 0; i < eh.e_phnum && j < 2; i++) {
43991295Srobert		if (xfsread(ino, ep + j, sizeof(ep[0])))
44091295Srobert			return;
44191295Srobert		if (ep[j].p_type == PT_LOAD)
44291295Srobert			j++;
44391295Srobert	}
44491295Srobert	for (i = 0; i < j; i++) {
44591295Srobert		p = (caddr_t)ep[i].p_vaddr;
44691295Srobert		fs_off = ep[i].p_offset;
44791295Srobert		if (xfsread(ino, p, ep[i].p_filesz))
44891295Srobert			return;
44991295Srobert		/*
45091295Srobert		 * Assume the second program header table entry
45191295Srobert		 * to contain data and bss.  Clear out the .bss section.
45291295Srobert		 */
45391295Srobert		if (i == 1) {
45491295Srobert			memset(p + ep[i].p_filesz, 0,
45591295Srobert			    ep[i].p_memsz - ep[i].p_filesz);
45691295Srobert		}
45791295Srobert	}
45891295Srobert	p += roundup2(ep[1].p_memsz, PAGE_SIZE);
45991295Srobert	if (eh.e_shnum == eh.e_shstrndx + 3) {
46091295Srobert		fs_off = eh.e_shoff + sizeof(es[0]) * (eh.e_shstrndx + 1);
46191295Srobert		if (xfsread(ino, &es, sizeof(es)))
46291295Srobert			return;
46391295Srobert		for (i = 0; i < 2; i++) {
46491295Srobert			memcpy(p, &es[i].sh_size, sizeof(es[i].sh_size));
46591295Srobert			p += sizeof(es[i].sh_size);
46691295Srobert			fs_off = es[i].sh_offset;
46791295Srobert			if (xfsread(ino, p, es[i].sh_size))
46891295Srobert				return;
46991295Srobert			p += es[i].sh_size;
47091295Srobert		}
47191295Srobert	}
47291295Srobert	entry = eh.e_entry;
47391295Srobert	ofw_close(bootdevh);
47491295Srobert	(*(void (*)(int, int, int, int, ofwfp_t))entry)(0, 0, 0, 0, ofw);
47590699Srobert}
47690699Srobert
47790699Srobertstatic int
47890699Srobertparse(char *arg)
47990699Srobert{
48091295Srobert	char *p;
48191295Srobert	int c, i;
48290699Srobert
48391295Srobert	while ((c = *arg++)) {
48491295Srobert		if (c == ' ' || c == '\t' || c == '\n')
48591295Srobert			continue;
48691295Srobert		for (p = arg; *p && *p != '\n' && *p != ' ' && *p != '\t'; p++)
48791295Srobert			;
48891295Srobert		if (*p)
48991295Srobert			*p++ = 0;
49091295Srobert		if (c == '-') {
49191295Srobert			while ((c = *arg++)) {
49291295Srobert				for (i = 0; c != optstr[i]; i++)
49391295Srobert					if (i == NOPT - 1)
49491295Srobert						return (-1);
49591295Srobert				opts ^= 1 << flags[i];
49691295Srobert			}
49791295Srobert		}
49891295Srobert		arg = p;
49990699Srobert	}
50091295Srobert	return (0);
50190699Srobert}
50290699Srobert
50390699Srobertstatic ino_t
50490699Srobertlookup(const char *path)
50590699Srobert{
50691295Srobert	char name[MAXNAMLEN + 1];
50791295Srobert	const char *s;
50891295Srobert	ino_t ino;
50991295Srobert	ssize_t n;
51091295Srobert	int dt;
51190699Srobert
51291295Srobert	ino = ROOTINO;
51391295Srobert	dt = DT_DIR;
51491678Srobert	name[0] = '/';
51591678Srobert	name[1] = '\0';
51691295Srobert	for (;;) {
51791295Srobert		if (*path == '/')
51891295Srobert			path++;
51991295Srobert		if (!*path)
52091295Srobert			break;
52191295Srobert		for (s = path; *s && *s != '/'; s++)
52291295Srobert			;
52391295Srobert		if ((n = s - path) > MAXNAMLEN)
52491295Srobert			return (0);
52591295Srobert		ls = *path == '?' && n == 1 && !*s;
52691295Srobert		memcpy(name, path, n);
52791295Srobert		name[n] = 0;
52891678Srobert		if (dt != DT_DIR) {
52991678Srobert			printf("%s: not a directory.\n", name);
53091678Srobert			return (0);
53191678Srobert		}
53291295Srobert		if ((dt = fsfind(name, &ino)) <= 0)
53391295Srobert			break;
53491295Srobert		path = s;
53591295Srobert	}
53691295Srobert	return (dt == DT_REG ? ino : 0);
53790699Srobert}
53890699Srobert
53990699Srobertstatic int
54090699Srobertxfsread(ino_t inode, void *buf, size_t nbyte)
54190699Srobert{
54291295Srobert	if (fsread(inode, buf, nbyte) != (ssize_t)nbyte) {
54391295Srobert		printf("Invalid %s\n", "format");
54491295Srobert		return (-1);
54591295Srobert	}
54691295Srobert	return (0);
54790699Srobert}
54890699Srobert
54990699Srobertstatic ssize_t
55090699Srobertfsread(ino_t inode, void *buf, size_t nbyte)
55190699Srobert{
55291295Srobert	static struct fs fs;
55391295Srobert	static struct dinode din;
55491295Srobert	static char *blkbuf;
55591295Srobert	static ufs_daddr_t *indbuf;
55691295Srobert	static ino_t inomap;
55791295Srobert	static ufs_daddr_t blkmap, indmap;
55891295Srobert	static unsigned int fsblks;
55991295Srobert	char *s;
56091295Srobert	ufs_daddr_t lbn, addr;
56191295Srobert	size_t n, nb, off;
56290699Srobert
56391295Srobert	if (!dsk.meta) {
56491295Srobert		if (!blkbuf)
56591295Srobert			blkbuf = malloc(BSIZEMAX);
56691295Srobert		inomap = 0;
56791295Srobert		if (dskread(blkbuf, SBOFF / DEV_BSIZE, SBSIZE / DEV_BSIZE))
56891295Srobert			return (-1);
56991295Srobert		memcpy(&fs, blkbuf, sizeof(fs));
57091295Srobert		if (fs.fs_magic != FS_MAGIC) {
57191295Srobert			printf("Not ufs\n");
57291295Srobert				return (-1);
57391295Srobert		}
57491295Srobert		fsblks = fs.fs_bsize >> DEV_BSHIFT;
57591295Srobert		dsk.meta++;
57690699Srobert	}
57791295Srobert	if (!inode)
57891295Srobert		return (0);
57991295Srobert	if (inomap != inode) {
58091295Srobert		if (dskread(blkbuf, fsbtodb(&fs, ino_to_fsba(&fs, inode)),
58190699Srobert		    fsblks))
58291295Srobert			return (-1);
58391295Srobert		din = ((struct dinode *)blkbuf)[inode % INOPB(&fs)];
58491295Srobert		inomap = inode;
58591295Srobert		fs_off = 0;
58691295Srobert		blkmap = indmap = 0;
58790699Srobert	}
58891295Srobert	s = buf;
58991295Srobert	if (nbyte > (n = din.di_size - fs_off))
59091295Srobert		nbyte = n;
59191295Srobert	nb = nbyte;
59291295Srobert	while (nb) {
59391295Srobert		lbn = lblkno(&fs, fs_off);
59491295Srobert		if (lbn < NDADDR)
59591295Srobert			addr = din.di_db[lbn];
59691295Srobert		else {
59791295Srobert			if (indmap != din.di_ib[0]) {
59891295Srobert				if (!indbuf)
59991295Srobert					indbuf = malloc(BSIZEMAX);
60091295Srobert				if (dskread(indbuf, fsbtodb(&fs, din.di_ib[0]),
60191295Srobert				    fsblks))
60291295Srobert					return (-1);
60391295Srobert				indmap = din.di_ib[0];
60491295Srobert			}
60591295Srobert			addr = indbuf[(lbn - NDADDR) % NINDIR(&fs)];
60691295Srobert		}
60791295Srobert		n = dblksize(&fs, &din, lbn);
60891295Srobert		if (blkmap != addr) {
60991295Srobert			if (dskread(blkbuf, fsbtodb(&fs, addr),
61091295Srobert			    n >> DEV_BSHIFT)) {
61191295Srobert				return (-1);
61291295Srobert			}
61391295Srobert			blkmap = addr;
61491295Srobert		}
61591295Srobert		off = blkoff(&fs, fs_off);
61691295Srobert		n -= off;
61791295Srobert		if (n > nb)
61891295Srobert			n = nb;
61991295Srobert		memcpy(s, blkbuf + off, n);
62091295Srobert		s += n;
62191295Srobert		fs_off += n;
62291295Srobert		nb -= n;
62390699Srobert	}
62491295Srobert	return (nbyte);
62590699Srobert}
62690699Srobert
62790699Srobertstatic int
62890699Srobertdskread(void *buf, u_int64_t lba, int nblk)
62990699Srobert{
63091295Srobert	/*
63191295Srobert	 * The OpenFirmware should open the correct partition for us.
63291295Srobert	 * That means, if we read from offset zero on an open instance handle,
63391295Srobert	 * we should read from offset zero of that partition.
63491295Srobert	 */
63591295Srobert	ofw_seek(bootdevh, lba * DEV_BSIZE);
63691295Srobert	ofw_read(bootdevh, buf, nblk * DEV_BSIZE);
63791295Srobert	return (0);
63890699Srobert}
63990699Srobert
64090699Srobertstatic int
64190699Srobertprintf(const char *fmt,...)
64290699Srobert{
64391295Srobert	static const char digits[16] = "0123456789abcdef";
64491295Srobert	va_list ap;
64591295Srobert	char buf[10];
64691295Srobert	char *s;
64791295Srobert	unsigned long int r, u;
64891678Srobert	int c, longp;
64990699Srobert
65091295Srobert	va_start(ap, fmt);
65191678Srobert	longp = 0;
65291295Srobert	while ((c = *fmt++)) {
65391678Srobert		if (c == '%' || longp) {
65491678Srobert			if (c == '%')
65591678Srobert				c = *fmt++;
65691295Srobert			switch (c) {
65791295Srobert			case 'c':
65891678Srobert				if (longp)
65991678Srobert					break;
66091295Srobert				putchar(va_arg(ap, int));
66191295Srobert				continue;
66291295Srobert			case 's':
66391678Srobert				if (longp)
66491678Srobert					break;
66591295Srobert				for (s = va_arg(ap, char *); *s; s++)
66691295Srobert					putchar(*s);
66791295Srobert				continue;
66891295Srobert			case 'p':
66991678Srobert				if (longp)
67091678Srobert					break;
67191295Srobert				if (c == 'p') {
67291295Srobert					putchar('0');
67391295Srobert					putchar('x');
67491295Srobert				}
67591295Srobert			case 'u':
67691295Srobert			case 'x':
67791295Srobert				r = c == 'u' ? 10U : 16U;
67891678Srobert				u = (c == 'p' || longp) ?
67991678Srobert				    va_arg(ap, unsigned long) :
68091295Srobert				    va_arg(ap, unsigned int);
68191295Srobert				s = buf;
68291295Srobert				do
68391295Srobert					*s++ = digits[u % r];
68491295Srobert				while (u /= r);
68591295Srobert				while (--s >= buf)
68691295Srobert					putchar(*s);
68791678Srobert				longp = 0;
68891295Srobert				continue;
68991678Srobert			case 'l':
69091678Srobert				if (longp)
69191678Srobert					break;
69291678Srobert				longp = 1;
69391678Srobert				continue;
69491295Srobert			}
69591678Srobert			longp = 0;
69690699Srobert		}
69791295Srobert		putchar(c);
69890699Srobert	}
69991295Srobert	va_end(ap);
70091295Srobert	return (0);
70190699Srobert}
70290699Srobert
70390699Srobertstatic int
70490699Srobertputchar(int c)
70590699Srobert{
70691295Srobert	if (c == '\n')
70791295Srobert		putc('\r');
70891295Srobert	putc(c);
70991295Srobert	return (c);
71090699Srobert}
71190699Srobert
71290699Srobertstatic void *
71390699Srobertmemcpy(void *dst, const void *src, size_t size)
71490699Srobert{
71591295Srobert	const char *s;
71691295Srobert	char *d;
71790699Srobert
71891295Srobert	for (d = dst, s = src; size; size--)
71991295Srobert		*d++ = *s++;
72091295Srobert	return (dst);
72190699Srobert}
72290699Srobert
72390699Srobertstatic void *
72490699Srobertmalloc(size_t size)
72590699Srobert{
72691295Srobert	static vm_offset_t next = 0x10000;
72791295Srobert	void *p;
72890699Srobert
72991295Srobert	if (size & 0xf)
73091295Srobert		size = (size + 0xf) & ~0xf;
73191295Srobert	p = (void *)next;
73291295Srobert	next += size;
73391295Srobert	return (p);
73490699Srobert}
73590699Srobert
73690699Srobertstatic int
73790699Srobertkeyhit(unsigned int ticks)
73890699Srobert{
73990699Srobert	/* XXX */
74091295Srobert	return (0);
74190699Srobert	ticks = ticks;		/* make GCC happy */
74290699Srobert}
74390699Srobert
74490699Srobertstatic int
74590699Srobertgetc(void)
74690699Srobert{
74790699Srobert	char c;
74890699Srobert	ofw_read(stdinh, &c, 1);
74991295Srobert	return (c);
75090699Srobert}
751