boot1.c revision 95351
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 95351 2002-04-24 05:54:10Z jake $");
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
3395337Sjake#define _PATH_LOADER	"/boot/loader"
3495337Sjake#define _PATH_KERNEL	"/boot/kernel/kernel"
3590699Srobert
3690699Srobert#define BSIZEMAX	8192
3790699Srobert
3895351Sjaketypedef int putc_func_t(int c, void *arg);
3995351Sjaketypedef int32_t ofwh_t;
4095351Sjake
4195351Sjakestruct sp_data {
4295351Sjake	char	*sp_buf;
4395351Sjake	u_int	sp_len;
4495351Sjake	u_int	sp_size;
4590699Srobert};
4690699Srobert
4795346Sjakestatic const char digits[] = "0123456789abcdef";
4890699Srobert
4995346Sjakestatic char bootpath[128];
5095346Sjakestatic char bootargs[128];
5195346Sjake
5295351Sjakestatic ofwh_t bootdev;
5395346Sjake
5495351Sjakestatic struct fs fs;
5595351Sjakestatic ino_t inomap;
5695351Sjakestatic char blkbuf[BSIZEMAX];
5795351Sjakestatic unsigned int fsblks;
5895351Sjake
5990699Srobertstatic uint32_t fs_off;
6090699Srobert
6195346Sjakeint main(int ac, char **av);
6295346Sjake
6395351Sjakestatic void exit(int) __dead2;
6490699Srobertstatic void load(const char *);
6590699Srobertstatic ino_t lookup(const char *);
6690699Srobertstatic ssize_t fsread(ino_t, void *, size_t);
6790699Srobertstatic int dskread(void *, u_int64_t, int);
6890699Srobert
6995351Sjakestatic void usage(void);
7095351Sjake
7195340Sjakestatic void bcopy(const void *src, void *dst, size_t len);
7295340Sjakestatic void bzero(void *b, size_t len);
7390699Srobert
7495351Sjakestatic int mount(const char *device);
7595351Sjake
7695351Sjakestatic void panic(const char *fmt, ...) __dead2;
7795346Sjakestatic int printf(const char *fmt, ...);
7895351Sjakestatic int putchar(int c, void *arg);
7995346Sjakestatic int vprintf(const char *fmt, va_list ap);
8095351Sjakestatic int vsnprintf(char *str, size_t sz, const char *fmt, va_list ap);
8195346Sjake
8295346Sjakestatic int __printf(const char *fmt, putc_func_t *putc, void *arg, va_list ap);
8395346Sjakestatic int __putc(int c, void *arg);
8495346Sjakestatic int __puts(const char *s, putc_func_t *putc, void *arg);
8595351Sjakestatic int __sputc(int c, void *arg);
8695346Sjakestatic char *__uitoa(char *buf, u_int val, int base);
8795346Sjakestatic char *__ultoa(char *buf, u_long val, int base);
8895346Sjake
8990699Srobert/*
9090699Srobert * Open Firmware interface functions
9190699Srobert */
9290699Sroberttypedef u_int64_t	ofwcell_t;
9390699Sroberttypedef u_int32_t	u_ofwh_t;
9490699Sroberttypedef int (*ofwfp_t)(ofwcell_t []);
9590699Srobertofwfp_t ofw;			/* the prom Open Firmware entry */
9690699Srobert
9790699Srobertvoid ofw_init(int, int, int, int, ofwfp_t);
9890699Srobertofwh_t ofw_finddevice(const char *);
9990699Srobertofwh_t ofw_open(const char *);
10090699Srobertint ofw_getprop(ofwh_t, const char *, void *, size_t);
10190699Srobertint ofw_read(ofwh_t, void *, size_t);
10290699Srobertint ofw_write(ofwh_t, const void *, size_t);
10390699Srobertint ofw_seek(ofwh_t, u_int64_t);
10495351Sjakevoid ofw_exit(void) __dead2;
10590699Srobert
10690699Srobertofwh_t bootdevh;
10790699Srobertofwh_t stdinh, stdouth;
10890699Srobert
10990699Srobert/*
11090699Srobert * This has to stay here, as the PROM seems to ignore the
11190699Srobert * entry point specified in the a.out header.  (or elftoaout is broken)
11290699Srobert */
11390699Srobert
11490699Srobertvoid
11590699Srobertofw_init(int d, int d1, int d2, int d3, ofwfp_t ofwaddr)
11690699Srobert{
11790699Srobert	ofwh_t chosenh;
11895346Sjake	char *av[16];
11995346Sjake	char *p;
12095346Sjake	int ac;
12190699Srobert
12290699Srobert	ofw = ofwaddr;
12390699Srobert
12490699Srobert	chosenh = ofw_finddevice("/chosen");
12590699Srobert	ofw_getprop(chosenh, "stdin", &stdinh, sizeof(stdinh));
12690699Srobert	ofw_getprop(chosenh, "stdout", &stdouth, sizeof(stdouth));
12795346Sjake	ofw_getprop(chosenh, "bootargs", bootargs, sizeof(bootargs));
12890699Srobert	ofw_getprop(chosenh, "bootpath", bootpath, sizeof(bootpath));
12990699Srobert
13095346Sjake	bootargs[sizeof(bootargs) - 1] = '\0';
13195346Sjake	bootpath[sizeof(bootpath) - 1] = '\0';
13295346Sjake
13395346Sjake	ac = 0;
13495346Sjake	p = bootargs;
13595346Sjake	for (;;) {
13695346Sjake		while (*p == ' ' && *p != '\0')
13795346Sjake			p++;
13895346Sjake		if (*p == '\0' || ac >= 16)
13995346Sjake			break;
14095346Sjake		av[ac++] = p;
14195346Sjake		while (*p != ' ' && *p != '\0')
14295346Sjake			p++;
14395346Sjake		if (*p != '\0')
14495346Sjake			*p++ = '\0';
14595346Sjake	}
14695346Sjake
14795346Sjake	exit(main(ac, av));
14890699Srobert}
14990699Srobert
15090699Srobertofwh_t
15190699Srobertofw_finddevice(const char *name)
15290699Srobert{
15391295Srobert	ofwcell_t args[] = {
15491295Srobert		(ofwcell_t)"finddevice",
15591295Srobert		1,
15691295Srobert		1,
15791295Srobert		(ofwcell_t)name,
15891295Srobert		0
15991295Srobert	};
16091295Srobert
16191295Srobert	if ((*ofw)(args)) {
16291295Srobert		printf("ofw_finddevice: name=\"%s\"\n", name);
16391295Srobert		return (1);
16491295Srobert	}
16591295Srobert	return (args[4]);
16690699Srobert}
16790699Srobert
16890699Srobertint
16990699Srobertofw_getprop(ofwh_t ofwh, const char *name, void *buf, size_t len)
17090699Srobert{
17191295Srobert	ofwcell_t args[] = {
17291295Srobert		(ofwcell_t)"getprop",
17391295Srobert		4,
17491295Srobert		1,
17591295Srobert		(u_ofwh_t)ofwh,
17691295Srobert		(ofwcell_t)name,
17791295Srobert		(ofwcell_t)buf,
17891295Srobert		len,
17990699Srobert	0
18091295Srobert	};
18191295Srobert
18291295Srobert	if ((*ofw)(args)) {
18391295Srobert		printf("ofw_getprop: ofwh=0x%x buf=%p len=%u\n",
18491295Srobert			ofwh, buf, len);
18591295Srobert		return (1);
18691295Srobert	}
18791295Srobert	return (0);
18890699Srobert}
18990699Srobert
19090699Srobertofwh_t
19190699Srobertofw_open(const char *path)
19290699Srobert{
19391295Srobert	ofwcell_t args[] = {
19491295Srobert		(ofwcell_t)"open",
19591295Srobert		1,
19691295Srobert		1,
19791295Srobert		(ofwcell_t)path,
19891295Srobert		0
19991295Srobert	};
20091295Srobert
20191295Srobert	if ((*ofw)(args)) {
20291295Srobert		printf("ofw_open: path=\"%s\"\n", path);
20391295Srobert		return (-1);
20491295Srobert	}
20591295Srobert	return (args[4]);
20690699Srobert}
20790699Srobert
20890699Srobertint
20990699Srobertofw_close(ofwh_t devh)
21090699Srobert{
21191295Srobert	ofwcell_t args[] = {
21291295Srobert		(ofwcell_t)"close",
21391295Srobert		1,
21491295Srobert		0,
21591295Srobert		(u_ofwh_t)devh
21691295Srobert	};
21791295Srobert
21891295Srobert	if ((*ofw)(args)) {
21991295Srobert		printf("ofw_close: devh=0x%x\n", devh);
22091295Srobert		return (1);
22191295Srobert	}
22291295Srobert	return (0);
22390699Srobert}
22490699Srobert
22590699Srobertint
22690699Srobertofw_read(ofwh_t devh, void *buf, size_t len)
22790699Srobert{
22891295Srobert	ofwcell_t args[] = {
22991295Srobert		(ofwcell_t)"read",
23091295Srobert		4,
23191295Srobert		1,
23291295Srobert		(u_ofwh_t)devh,
23391295Srobert		(ofwcell_t)buf,
23491295Srobert		len,
23591295Srobert		0
23691295Srobert	};
23791295Srobert
23891295Srobert	if ((*ofw)(args)) {
23991295Srobert		printf("ofw_read: devh=0x%x buf=%p len=%u\n", devh, buf, len);
24091295Srobert		return (1);
24191295Srobert	}
24291295Srobert	return (0);
24390699Srobert}
24490699Srobert
24590699Srobertint
24690699Srobertofw_write(ofwh_t devh, const void *buf, size_t len)
24790699Srobert{
24891295Srobert	ofwcell_t args[] = {
24991295Srobert		(ofwcell_t)"write",
25091295Srobert		3,
25191295Srobert		1,
25291295Srobert		(u_ofwh_t)devh,
25391295Srobert		(ofwcell_t)buf,
25491295Srobert		len,
25591295Srobert		0
25691295Srobert	};
25791295Srobert
25891295Srobert	if ((*ofw)(args)) {
25991295Srobert		printf("ofw_write: devh=0x%x buf=%p len=%u\n", devh, buf, len);
26091295Srobert		return (1);
26191295Srobert	}
26291295Srobert	return (0);
26390699Srobert}
26490699Srobert
26590699Srobertint
26690699Srobertofw_seek(ofwh_t devh, u_int64_t off)
26790699Srobert{
26891295Srobert	ofwcell_t args[] = {
26991295Srobert		(ofwcell_t)"seek",
27091295Srobert		4,
27191295Srobert		1,
27291295Srobert		(u_ofwh_t)devh,
27391295Srobert		off >> 32,
27491678Srobert		off,
27591295Srobert		0
27691295Srobert	};
27791295Srobert
27891295Srobert	if ((*ofw)(args)) {
27991295Srobert		printf("ofw_seek: devh=0x%x off=0x%lx\n", devh, off);
28091295Srobert		return (1);
28191295Srobert	}
28291295Srobert	return (0);
28390699Srobert}
28490699Srobert
28595342Sjakevoid
28695342Sjakeofw_exit(void)
28795342Sjake{
28895342Sjake	ofwcell_t args[3];
28995342Sjake
29095342Sjake	args[0] = (ofwcell_t)"exit";
29195342Sjake	args[1] = 0;
29295342Sjake	args[2] = 0;
29395342Sjake
29495351Sjake	for (;;)
29595351Sjake		(*ofw)(args);
29695342Sjake}
29795342Sjake
29895340Sjakestatic void
29995340Sjakebcopy(const void *dst, void *src, size_t len)
30095340Sjake{
30195340Sjake	const char *d = dst;
30295340Sjake	char *s = src;
30395340Sjake
30495340Sjake	while (len-- != 0)
30595340Sjake		*s++ = *d++;
30695340Sjake}
30795340Sjake
30895340Sjakestatic void
30995340Sjakebzero(void *b, size_t len)
31095340Sjake{
31195340Sjake	char *p = b;
31295340Sjake
31395340Sjake	while (len-- != 0)
31495340Sjake		*p++ = 0;
31595340Sjake}
31695340Sjake
31790699Srobertstatic int
31890699Srobertstrcmp(const char *s1, const char *s2)
31990699Srobert{
32091295Srobert	for (; *s1 == *s2 && *s1; s1++, s2++)
32191295Srobert		;
32291295Srobert	return ((u_char)*s1 - (u_char)*s2);
32390699Srobert}
32490699Srobert
32590699Srobertstatic int
32690699Srobertfsfind(const char *name, ino_t * ino)
32790699Srobert{
32891295Srobert	char buf[DEV_BSIZE];
32991295Srobert	struct dirent *d;
33091295Srobert	char *s;
33191295Srobert	ssize_t n;
33290699Srobert
33391295Srobert	fs_off = 0;
33491295Srobert	while ((n = fsread(*ino, buf, DEV_BSIZE)) > 0) {
33591295Srobert		for (s = buf; s < buf + DEV_BSIZE;) {
33691295Srobert			d = (void *)s;
33795337Sjake			if (!strcmp(name, d->d_name)) {
33891295Srobert				*ino = d->d_fileno;
33991295Srobert				return (d->d_type);
34091295Srobert			}
34191295Srobert			s += d->d_reclen;
34291295Srobert		}
34390699Srobert	}
34491295Srobert	return (0);
34590699Srobert}
34690699Srobert
34795346Sjakeint
34895346Sjakemain(int ac, char **av)
34990699Srobert{
35095346Sjake	const char *path;
35195346Sjake	int i;
35291295Srobert
35395346Sjake	path = _PATH_LOADER;
35495346Sjake	for (i = 0; i < ac; i++) {
35595346Sjake		switch (av[i][0]) {
35695346Sjake		case '-':
35795346Sjake			switch (av[i][1]) {
35895346Sjake			default:
35995351Sjake				usage();
36095346Sjake			}
36195346Sjake			break;
36295346Sjake		default:
36395346Sjake			path = av[i];
36495346Sjake			break;
36595346Sjake		}
36695346Sjake	}
36790699Srobert
36891295Srobert	printf(" \n>> FreeBSD/sparc64 boot block\n"
36990699Srobert	"   Boot path:   %s\n"
37095346Sjake	"   Boot loader: %s\n", bootpath, path);
37195351Sjake
37295351Sjake	if (mount(bootpath) == -1)
37395351Sjake		panic("mount");
37495351Sjake
37595346Sjake	load(path);
37691295Srobert	return (1);
37790699Srobert}
37890699Srobert
37990699Srobertstatic void
38095351Sjakeusage(void)
38195351Sjake{
38295351Sjake
38395351Sjake	printf("usage: boot device [/path/to/loader]\n");
38495351Sjake	exit(1);
38595351Sjake}
38695351Sjake
38795351Sjakestatic void
38895342Sjakeexit(int code)
38995342Sjake{
39095342Sjake
39195342Sjake	ofw_exit();
39295342Sjake}
39395342Sjake
39495351Sjakestatic int
39595351Sjakemount(const char *device)
39695351Sjake{
39795351Sjake
39895351Sjake	if ((bootdev = ofw_open(device)) == -1) {
39995351Sjake		printf("mount: can't open device\n");
40095351Sjake		return (-1);
40195351Sjake	}
40295351Sjake	if (dskread(blkbuf, SBOFF / DEV_BSIZE, SBSIZE / DEV_BSIZE)) {
40395351Sjake		printf("mount: can't read superblock\n");
40495351Sjake		return (-1);
40595351Sjake	}
40695351Sjake	inomap = 0;
40795351Sjake	bcopy(blkbuf, &fs, sizeof(fs));
40895351Sjake	if (fs.fs_magic != FS_MAGIC) {
40995351Sjake		printf("mount: not ufs\n");
41095351Sjake		return (-1);
41195351Sjake	}
41295351Sjake	fsblks = fs.fs_bsize >> DEV_BSHIFT;
41395351Sjake	return (0);
41495351Sjake}
41595351Sjake
41695342Sjakestatic void
41790699Srobertload(const char *fname)
41890699Srobert{
41991295Srobert	Elf64_Ehdr eh;
42095339Sjake	Elf64_Phdr ph;
42191295Srobert	caddr_t p;
42291295Srobert	ino_t ino;
42395339Sjake	int i;
42490699Srobert
42591295Srobert	if ((ino = lookup(fname)) == 0) {
42695337Sjake		printf("File %s not found\n", fname);
42790699Srobert		return;
42890699Srobert	}
42995339Sjake	if (fsread(ino, &eh, sizeof(eh)) != sizeof(eh)) {
43095339Sjake		printf("Can't read elf header\n");
43191295Srobert		return;
43295339Sjake	}
43391295Srobert	if (!IS_ELF(eh)) {
43491295Srobert		printf("Not an ELF file\n");
43591295Srobert		return;
43691295Srobert	}
43795339Sjake	for (i = 0; i < eh.e_phnum; i++) {
43895339Sjake		fs_off = eh.e_phoff + i * eh.e_phentsize;
43995339Sjake		if (fsread(ino, &ph, sizeof(ph)) != sizeof(ph)) {
44095339Sjake			printf("Can't read program header %d\n", i);
44191295Srobert			return;
44291295Srobert		}
44395339Sjake		if (ph.p_type != PT_LOAD)
44495339Sjake			continue;
44595339Sjake		fs_off = ph.p_offset;
44695339Sjake		p = (caddr_t)ph.p_vaddr;
44795339Sjake		if (fsread(ino, p, ph.p_filesz) != ph.p_filesz) {
44895339Sjake			printf("Can't read content of section %d\n", i);
44991295Srobert			return;
45091295Srobert		}
45195339Sjake		if (ph.p_filesz != ph.p_memsz)
45295340Sjake			bzero(p + ph.p_filesz, ph.p_memsz - ph.p_filesz);
45391295Srobert	}
45495351Sjake	ofw_close(bootdev);
45595339Sjake	(*(void (*)(int, int, int, int, ofwfp_t))eh.e_entry)(0, 0, 0, 0, ofw);
45690699Srobert}
45790699Srobert
45890699Srobertstatic ino_t
45990699Srobertlookup(const char *path)
46090699Srobert{
46191295Srobert	char name[MAXNAMLEN + 1];
46291295Srobert	const char *s;
46391295Srobert	ino_t ino;
46491295Srobert	ssize_t n;
46591295Srobert	int dt;
46690699Srobert
46791295Srobert	ino = ROOTINO;
46891295Srobert	dt = DT_DIR;
46991678Srobert	name[0] = '/';
47091678Srobert	name[1] = '\0';
47191295Srobert	for (;;) {
47291295Srobert		if (*path == '/')
47391295Srobert			path++;
47491295Srobert		if (!*path)
47591295Srobert			break;
47691295Srobert		for (s = path; *s && *s != '/'; s++)
47791295Srobert			;
47891295Srobert		if ((n = s - path) > MAXNAMLEN)
47991295Srobert			return (0);
48095340Sjake		bcopy(path, name, n);
48191295Srobert		name[n] = 0;
48291678Srobert		if (dt != DT_DIR) {
48391678Srobert			printf("%s: not a directory.\n", name);
48491678Srobert			return (0);
48591678Srobert		}
48691295Srobert		if ((dt = fsfind(name, &ino)) <= 0)
48791295Srobert			break;
48891295Srobert		path = s;
48991295Srobert	}
49091295Srobert	return (dt == DT_REG ? ino : 0);
49190699Srobert}
49290699Srobert
49390699Srobertstatic ssize_t
49490699Srobertfsread(ino_t inode, void *buf, size_t nbyte)
49590699Srobert{
49691295Srobert	static struct dinode din;
49795337Sjake	static ufs_daddr_t indbuf[BSIZEMAX / sizeof(ufs_daddr_t)];
49891295Srobert	static ufs_daddr_t blkmap, indmap;
49991295Srobert	char *s;
50091295Srobert	ufs_daddr_t lbn, addr;
50191295Srobert	size_t n, nb, off;
50290699Srobert
50391295Srobert	if (!inode)
50491295Srobert		return (0);
50591295Srobert	if (inomap != inode) {
50691295Srobert		if (dskread(blkbuf, fsbtodb(&fs, ino_to_fsba(&fs, inode)),
50790699Srobert		    fsblks))
50891295Srobert			return (-1);
50995340Sjake		bcopy(blkbuf + ((inode % INOPB(&fs)) * sizeof(din)), &din,
51095340Sjake		    sizeof(din));
51191295Srobert		inomap = inode;
51291295Srobert		fs_off = 0;
51391295Srobert		blkmap = indmap = 0;
51490699Srobert	}
51591295Srobert	s = buf;
51691295Srobert	if (nbyte > (n = din.di_size - fs_off))
51791295Srobert		nbyte = n;
51891295Srobert	nb = nbyte;
51991295Srobert	while (nb) {
52091295Srobert		lbn = lblkno(&fs, fs_off);
52191295Srobert		if (lbn < NDADDR)
52291295Srobert			addr = din.di_db[lbn];
52391295Srobert		else {
52491295Srobert			if (indmap != din.di_ib[0]) {
52591295Srobert				if (dskread(indbuf, fsbtodb(&fs, din.di_ib[0]),
52691295Srobert				    fsblks))
52791295Srobert					return (-1);
52891295Srobert				indmap = din.di_ib[0];
52991295Srobert			}
53091295Srobert			addr = indbuf[(lbn - NDADDR) % NINDIR(&fs)];
53191295Srobert		}
53291295Srobert		n = dblksize(&fs, &din, lbn);
53391295Srobert		if (blkmap != addr) {
53491295Srobert			if (dskread(blkbuf, fsbtodb(&fs, addr),
53591295Srobert			    n >> DEV_BSHIFT)) {
53691295Srobert				return (-1);
53791295Srobert			}
53891295Srobert			blkmap = addr;
53991295Srobert		}
54091295Srobert		off = blkoff(&fs, fs_off);
54191295Srobert		n -= off;
54291295Srobert		if (n > nb)
54391295Srobert			n = nb;
54495340Sjake		bcopy(blkbuf + off, s, n);
54591295Srobert		s += n;
54691295Srobert		fs_off += n;
54791295Srobert		nb -= n;
54890699Srobert	}
54991295Srobert	return (nbyte);
55090699Srobert}
55190699Srobert
55290699Srobertstatic int
55390699Srobertdskread(void *buf, u_int64_t lba, int nblk)
55490699Srobert{
55591295Srobert	/*
55691295Srobert	 * The OpenFirmware should open the correct partition for us.
55791295Srobert	 * That means, if we read from offset zero on an open instance handle,
55891295Srobert	 * we should read from offset zero of that partition.
55991295Srobert	 */
56095351Sjake	ofw_seek(bootdev, lba * DEV_BSIZE);
56195351Sjake	ofw_read(bootdev, buf, nblk * DEV_BSIZE);
56291295Srobert	return (0);
56390699Srobert}
56490699Srobert
56595351Sjakestatic void
56695351Sjakepanic(const char *fmt, ...)
56790699Srobert{
56895351Sjake	char buf[128];
56991295Srobert	va_list ap;
57095346Sjake
57195346Sjake	va_start(ap, fmt);
57295351Sjake	vsnprintf(buf, sizeof buf, fmt, ap);
57395351Sjake	printf("panic: %s\n", buf);
57495346Sjake	va_end(ap);
57595351Sjake
57695351Sjake	exit(1);
57795346Sjake}
57895346Sjake
57995346Sjakestatic int
58095351Sjakeprintf(const char *fmt, ...)
58195346Sjake{
58295351Sjake	va_list ap;
58395346Sjake	int ret;
58495346Sjake
58595351Sjake	va_start(ap, fmt);
58695351Sjake	ret = vprintf(fmt, ap);
58795351Sjake	va_end(ap);
58895346Sjake	return (ret);
58995346Sjake}
59095346Sjake
59195346Sjakestatic int
59295346Sjakeputchar(int c, void *arg)
59395346Sjake{
59495346Sjake	char buf;
59595346Sjake
59695346Sjake	if (c == '\n') {
59795346Sjake		buf = '\r';
59895346Sjake		ofw_write(stdouth, &buf, 1);
59995346Sjake	}
60095346Sjake	buf = c;
60195346Sjake	ofw_write(stdouth, &buf, 1);
60295346Sjake	return (1);
60395346Sjake}
60495346Sjake
60595346Sjakestatic int
60695351Sjakevprintf(const char *fmt, va_list ap)
60795351Sjake{
60895351Sjake	int ret;
60995351Sjake
61095351Sjake	ret = __printf(fmt, putchar, 0, ap);
61195351Sjake	return (ret);
61295351Sjake}
61395351Sjake
61495351Sjakestatic int
61595351Sjakevsnprintf(char *str, size_t sz, const char *fmt, va_list ap)
61695351Sjake{
61795351Sjake	struct sp_data sp;
61895351Sjake	int ret;
61995351Sjake
62095351Sjake	sp.sp_buf = str;
62195351Sjake	sp.sp_len = 0;
62295351Sjake	sp.sp_size = sz;
62395351Sjake	ret = __printf(fmt, __sputc, &sp, ap);
62495351Sjake	return (ret);
62595351Sjake}
62695351Sjake
62795351Sjakestatic int
62895346Sjake__printf(const char *fmt, putc_func_t *putc, void *arg, va_list ap)
62995346Sjake{
63095346Sjake	char buf[(sizeof(long) * 8) + 1];
63195346Sjake	char *nbuf;
63295346Sjake	u_long ul;
63395346Sjake	u_int ui;
63495346Sjake	int lflag;
63595346Sjake	int sflag;
63691295Srobert	char *s;
63795346Sjake	int pad;
63895346Sjake	int ret;
63995346Sjake	int c;
64090699Srobert
64195346Sjake	nbuf = &buf[sizeof buf - 1];
64295346Sjake	ret = 0;
64395346Sjake	while ((c = *fmt++) != 0) {
64495346Sjake		if (c != '%') {
64595346Sjake			ret += putc(c, arg);
64695346Sjake			continue;
64795346Sjake		}
64895346Sjake		lflag = 0;
64995346Sjake		sflag = 0;
65095346Sjake		pad = 0;
65195346Sjakereswitch:	c = *fmt++;
65295346Sjake		switch (c) {
65395346Sjake		case '#':
65495346Sjake			sflag = 1;
65595346Sjake			goto reswitch;
65695346Sjake		case '%':
65795346Sjake			ret += putc('%', arg);
65895346Sjake			break;
65995346Sjake		case 'c':
66095346Sjake			c = va_arg(ap, int);
66195346Sjake			ret += putc(c, arg);
66295346Sjake			break;
66395346Sjake		case 'd':
66495346Sjake			if (lflag == 0) {
66595346Sjake				ui = (u_int)va_arg(ap, int);
66695346Sjake				if (ui < (int)ui) {
66795346Sjake					ui = -ui;
66895346Sjake					ret += putc('-', arg);
66991295Srobert				}
67095346Sjake				s = __uitoa(nbuf, ui, 10);
67195346Sjake			} else {
67295346Sjake				ul = (u_long)va_arg(ap, long);
67395346Sjake				if (ul < (long)ul) {
67495346Sjake					ul = -ul;
67595346Sjake					ret += putc('-', arg);
67695346Sjake				}
67795346Sjake				s = __ultoa(nbuf, ul, 10);
67891295Srobert			}
67995346Sjake			ret += __puts(s, putc, arg);
68095346Sjake			break;
68195346Sjake		case 'l':
68295346Sjake			lflag = 1;
68395346Sjake			goto reswitch;
68495346Sjake		case 'o':
68595346Sjake			if (lflag == 0) {
68695346Sjake				ui = (u_int)va_arg(ap, u_int);
68795346Sjake				s = __uitoa(nbuf, ui, 8);
68895346Sjake			} else {
68995346Sjake				ul = (u_long)va_arg(ap, u_long);
69095346Sjake				s = __ultoa(nbuf, ul, 8);
69195346Sjake			}
69295346Sjake			ret += __puts(s, putc, arg);
69395346Sjake			break;
69495346Sjake		case 'p':
69595346Sjake			ul = (u_long)va_arg(ap, void *);
69695346Sjake			s = __ultoa(nbuf, ul, 16);
69795346Sjake			ret += __puts("0x", putc, arg);
69895346Sjake			ret += __puts(s, putc, arg);
69995346Sjake			break;
70095346Sjake		case 's':
70195346Sjake			s = va_arg(ap, char *);
70295346Sjake			ret += __puts(s, putc, arg);
70395346Sjake			break;
70495346Sjake		case 'u':
70595346Sjake			if (lflag == 0) {
70695346Sjake				ui = va_arg(ap, u_int);
70795346Sjake				s = __uitoa(nbuf, ui, 10);
70895346Sjake			} else {
70995346Sjake				ul = va_arg(ap, u_long);
71095346Sjake				s = __ultoa(nbuf, ul, 10);
71195346Sjake			}
71295346Sjake			ret += __puts(s, putc, arg);
71395346Sjake			break;
71495346Sjake		case 'x':
71595346Sjake			if (lflag == 0) {
71695346Sjake				ui = va_arg(ap, u_int);
71795346Sjake				s = __uitoa(nbuf, ui, 16);
71895346Sjake			} else {
71995346Sjake				ul = va_arg(ap, u_long);
72095346Sjake				s = __ultoa(nbuf, ul, 16);
72195346Sjake			}
72295346Sjake			if (sflag)
72395346Sjake				ret += __puts("0x", putc, arg);
72495346Sjake			ret += __puts(s, putc, arg);
72595346Sjake			break;
72695346Sjake		case '0': case '1': case '2': case '3': case '4':
72795346Sjake		case '5': case '6': case '7': case '8': case '9':
72895346Sjake			pad = pad * 10 + c - '0';
72995346Sjake			goto reswitch;
73095346Sjake		default:
73195346Sjake			break;
73290699Srobert		}
73390699Srobert	}
73495346Sjake	return (ret);
73590699Srobert}
73690699Srobert
73790699Srobertstatic int
73895351Sjake__sputc(int c, void *arg)
73995351Sjake{
74095351Sjake	struct sp_data *sp;
74195351Sjake
74295351Sjake	sp = arg;
74395351Sjake	if (sp->sp_len < sp->sp_size)
74495351Sjake		sp->sp_buf[sp->sp_len++] = c;
74595351Sjake	sp->sp_buf[sp->sp_len] = '\0';
74695351Sjake	return (1);
74795351Sjake}
74895351Sjake
74995351Sjakestatic int
75095346Sjake__puts(const char *s, putc_func_t *putc, void *arg)
75190699Srobert{
75295346Sjake	const char *p;
75395346Sjake	int ret;
75495346Sjake
75595346Sjake	ret = 0;
75695346Sjake	for (p = s; *p != '\0'; p++)
75795346Sjake		ret += putc(*p, arg);
75895346Sjake	return (ret);
75990699Srobert}
76095346Sjake
76195346Sjakestatic char *
76295346Sjake__uitoa(char *buf, u_int ui, int base)
76395346Sjake{
76495346Sjake	char *p;
76595346Sjake
76695346Sjake	p = buf;
76795346Sjake	*p = '\0';
76895346Sjake	do
76995346Sjake		*--p = digits[ui % base];
77095346Sjake	while ((ui /= base) != 0);
77195346Sjake	return (p);
77295346Sjake}
77395346Sjake
77495346Sjakestatic char *
77595346Sjake__ultoa(char *buf, u_long ul, int base)
77695346Sjake{
77795346Sjake	char *p;
77895346Sjake
77995346Sjake	p = buf;
78095346Sjake	*p = '\0';
78195346Sjake	do
78295346Sjake		*--p = digits[ul % base];
78395346Sjake	while ((ul /= base) != 0);
78495346Sjake	return (p);
78595346Sjake}
786