xref: /freebsd/stand/powerpc/boot1.chrp/boot1.c (revision 7c43148a)
1ca987d46SWarner Losh /*-
2ca987d46SWarner Losh  * Copyright (c) 1998 Robert Nordier
3ca987d46SWarner Losh  * All rights reserved.
4ca987d46SWarner Losh  * Copyright (c) 2001 Robert Drehmel
5ca987d46SWarner Losh  * All rights reserved.
6ca987d46SWarner Losh  *
7ca987d46SWarner Losh  * Redistribution and use in source and binary forms are freely
8ca987d46SWarner Losh  * permitted provided that the above copyright notice and this
9ca987d46SWarner Losh  * paragraph and the following disclaimer are duplicated in all
10ca987d46SWarner Losh  * such forms.
11ca987d46SWarner Losh  *
12ca987d46SWarner Losh  * This software is provided "AS IS" and without any express or
13ca987d46SWarner Losh  * implied warranties, including, without limitation, the implied
14ca987d46SWarner Losh  * warranties of merchantability and fitness for a particular
15ca987d46SWarner Losh  * purpose.
16ca987d46SWarner Losh  */
17ca987d46SWarner Losh 
18ca987d46SWarner Losh #include <sys/param.h>
19ca987d46SWarner Losh #include <sys/dirent.h>
20f8328864SLeandro Lupori #include <sys/endian.h>
21ca987d46SWarner Losh #include <machine/elf.h>
22ca987d46SWarner Losh #include <machine/stdarg.h>
23a76b2d3dSWarner Losh #include <machine/md_var.h>
24ff7449d6SLeandro Lupori #include <ufs/ffs/fs.h>
25ca987d46SWarner Losh 
26ca987d46SWarner Losh #include "paths.h"
27ca987d46SWarner Losh 
28ca987d46SWarner Losh #define BSIZEMAX	16384
29ca987d46SWarner Losh 
30ca987d46SWarner Losh typedef int putc_func_t(char c, void *arg);
31ca987d46SWarner Losh typedef int32_t ofwh_t;
32ca987d46SWarner Losh 
33ca987d46SWarner Losh struct sp_data {
34ca987d46SWarner Losh 	char	*sp_buf;
35ca987d46SWarner Losh 	u_int	sp_len;
36ca987d46SWarner Losh 	u_int	sp_size;
37ca987d46SWarner Losh };
38ca987d46SWarner Losh 
39ca987d46SWarner Losh static const char digits[] = "0123456789abcdef";
40ca987d46SWarner Losh 
41ca987d46SWarner Losh static char bootpath[128];
42ca987d46SWarner Losh static char bootargs[128];
43ca987d46SWarner Losh 
44ca987d46SWarner Losh static ofwh_t bootdev;
45ca987d46SWarner Losh 
46ca987d46SWarner Losh static struct fs fs;
47ca987d46SWarner Losh static char blkbuf[BSIZEMAX];
48ca987d46SWarner Losh static unsigned int fsblks;
49ca987d46SWarner Losh 
50ca987d46SWarner Losh static uint32_t fs_off;
51ca987d46SWarner Losh 
52ca987d46SWarner Losh int main(int ac, char **av);
53ca987d46SWarner Losh 
54ca987d46SWarner Losh static void exit(int) __dead2;
55ca987d46SWarner Losh static void load(const char *);
5656e53cb8SWarner Losh static int dskread(void *, uint64_t, int);
57ca987d46SWarner Losh 
585762de72SAlfonso Gregory static void usage(void) __dead2;
59ca987d46SWarner Losh 
60ca987d46SWarner Losh static void bcopy(const void *src, void *dst, size_t len);
61ca987d46SWarner Losh static void bzero(void *b, size_t len);
62ca987d46SWarner Losh 
63ca987d46SWarner Losh static int domount(const char *device, int quiet);
64ca987d46SWarner Losh 
65ca987d46SWarner Losh static void panic(const char *fmt, ...) __dead2;
66ca987d46SWarner Losh static int printf(const char *fmt, ...);
67ca987d46SWarner Losh static int putchar(char c, void *arg);
68ca987d46SWarner Losh static int vprintf(const char *fmt, va_list ap);
69ca987d46SWarner Losh static int vsnprintf(char *str, size_t sz, const char *fmt, va_list ap);
70ca987d46SWarner Losh 
71ca987d46SWarner Losh static int __printf(const char *fmt, putc_func_t *putc, void *arg, va_list ap);
72ca987d46SWarner Losh static int __putc(char c, void *arg);
73ca987d46SWarner Losh static int __puts(const char *s, putc_func_t *putc, void *arg);
74ca987d46SWarner Losh static int __sputc(char c, void *arg);
75ca987d46SWarner Losh static char *__uitoa(char *buf, u_int val, int base);
76ca987d46SWarner Losh static char *__ultoa(char *buf, u_long val, int base);
77ca987d46SWarner Losh 
78ca987d46SWarner Losh /*
79ca987d46SWarner Losh  * Open Firmware interface functions
80ca987d46SWarner Losh  */
8156e53cb8SWarner Losh typedef uint32_t	ofwcell_t;
8256e53cb8SWarner Losh typedef uint32_t	u_ofwh_t;
83f8328864SLeandro Lupori typedef int (*ofwfp_t)(ofwcell_t *);
84ca987d46SWarner Losh ofwfp_t ofw;			/* the prom Open Firmware entry */
85ca987d46SWarner Losh ofwh_t chosenh;
86ca987d46SWarner Losh 
87f8328864SLeandro Lupori void ofw_init(void *, int, ofwfp_t, char *, int);
88ca987d46SWarner Losh static ofwh_t ofw_finddevice(const char *);
89ca987d46SWarner Losh static ofwh_t ofw_open(const char *);
90ca987d46SWarner Losh static int ofw_close(ofwh_t);
91ca987d46SWarner Losh static int ofw_getprop(ofwh_t, const char *, void *, size_t);
92ca987d46SWarner Losh static int ofw_setprop(ofwh_t, const char *, void *, size_t);
93ca987d46SWarner Losh static int ofw_read(ofwh_t, void *, size_t);
94ca987d46SWarner Losh static int ofw_write(ofwh_t, const void *, size_t);
95ca987d46SWarner Losh static int ofw_claim(void *virt, size_t len, u_int align);
9656e53cb8SWarner Losh static int ofw_seek(ofwh_t, uint64_t);
97ca987d46SWarner Losh static void ofw_exit(void) __dead2;
98ca987d46SWarner Losh 
99ca987d46SWarner Losh ofwh_t bootdevh;
100ca987d46SWarner Losh ofwh_t stdinh, stdouth;
101ca987d46SWarner Losh 
102f8328864SLeandro Lupori /*
103f8328864SLeandro Lupori  * Note about the entry point:
104f8328864SLeandro Lupori  *
105f8328864SLeandro Lupori  * For some odd reason, the first page of the load appears to have trouble
106f8328864SLeandro Lupori  * when entering in LE. The first five instructions decode weirdly.
107f8328864SLeandro Lupori  * I suspect it is some cache weirdness between the ELF headers and .text.
108f8328864SLeandro Lupori  *
109f8328864SLeandro Lupori  * Ensure we have a gap between the start of .text and the entry as a
110f8328864SLeandro Lupori  * workaround.
111f8328864SLeandro Lupori  */
112ca987d46SWarner Losh __asm("                         \n\
113ca987d46SWarner Losh         .data                   \n\
114ca987d46SWarner Losh 	.align 4		\n\
115ca987d46SWarner Losh stack:                          \n\
116ca987d46SWarner Losh         .space  16384           \n\
117ca987d46SWarner Losh                                 \n\
118ca987d46SWarner Losh         .text                   \n\
119f8328864SLeandro Lupori         /* SLOF cache hack */   \n\
120f8328864SLeandro Lupori         .space 4096             \n\
121ca987d46SWarner Losh         .globl  _start          \n\
122ca987d46SWarner Losh _start:                         \n\
123ca987d46SWarner Losh         lis     %r1,stack@ha    \n\
124ca987d46SWarner Losh         addi    %r1,%r1,stack@l \n\
125ca987d46SWarner Losh         addi    %r1,%r1,8192    \n\
126ca987d46SWarner Losh                                 \n\
127ca987d46SWarner Losh         b       ofw_init        \n\
128ca987d46SWarner Losh ");
129ca987d46SWarner Losh 
130f8328864SLeandro Lupori ofwfp_t realofw;
131f8328864SLeandro Lupori 
132f8328864SLeandro Lupori #if BYTE_ORDER == LITTLE_ENDIAN
133f8328864SLeandro Lupori /*
134f8328864SLeandro Lupori  * Minimal endianness-swap trampoline for LE.
135f8328864SLeandro Lupori  */
136f8328864SLeandro Lupori __attribute__((naked)) int
ofwtramp(void * buf,ofwfp_t cb)137f8328864SLeandro Lupori ofwtramp(void *buf, ofwfp_t cb)
138f8328864SLeandro Lupori {
139f8328864SLeandro Lupori __asm("									\n\
140f8328864SLeandro Lupori 	mflr	%r0							\n\
141f8328864SLeandro Lupori 	stw	%r0, 4(%r1)						\n\
142f8328864SLeandro Lupori 	stwu	%r1, -16(%r1)						\n\
143f8328864SLeandro Lupori 	stw	%r30, 8(%r1)						\n\
144f8328864SLeandro Lupori 	/* Save current MSR for restoration post-call. */		\n\
145f8328864SLeandro Lupori 	mfmsr	%r30							\n\
146f8328864SLeandro Lupori 	mr	%r5, %r30						\n\
147f8328864SLeandro Lupori 	/* Remove LE bit from MSR. */					\n\
148f8328864SLeandro Lupori 	clrrwi	%r5, %r5, 1						\n\
149f8328864SLeandro Lupori 	mtsrr0	%r4							\n\
150f8328864SLeandro Lupori 	mtsrr1	%r5							\n\
151f8328864SLeandro Lupori 	bcl	20, 31, .+4	/* LOAD_LR_NIA */			\n\
152f8328864SLeandro Lupori 1:									\n\
153f8328864SLeandro Lupori 	mflr	%r4							\n\
154f8328864SLeandro Lupori 	addi	%r4, %r4, (2f - 1b)					\n\
155f8328864SLeandro Lupori 	mtlr	%r4							\n\
156f8328864SLeandro Lupori 	/* Switch to BE and transfer control to OF entry */		\n\
157f8328864SLeandro Lupori 	rfid								\n\
158f8328864SLeandro Lupori 2:									\n\
159f8328864SLeandro Lupori 	/* Control is returned here, but in BE. */			\n\
160f8328864SLeandro Lupori 	.long	0x05009f42	/* LOAD_LR_NIA			      */\n\
161f8328864SLeandro Lupori 				/* 0:			 	      */\n\
162f8328864SLeandro Lupori 	.long	0xa603db7f	/* mtsrr1 	%r30		      */\n\
163f8328864SLeandro Lupori 	.long	0xa602c87f	/* mflr		%r30		      */\n\
164f8328864SLeandro Lupori 	.long	0x1400de3b	/* addi		%r30, %r30, (1f - 0b) */\n\
165f8328864SLeandro Lupori 	.long	0xa603da7f	/* mtsrr0	%r30		      */\n\
166f8328864SLeandro Lupori 	.long	0x2400004c	/* rfid				      */\n\
167f8328864SLeandro Lupori 				/* 1:				      */\n\
168f8328864SLeandro Lupori 1:									\n\
169f8328864SLeandro Lupori 	/* Back to normal. Tidy up for return. */			\n\
170f8328864SLeandro Lupori 	lwz	%r30, 8(%r1)						\n\
171f8328864SLeandro Lupori 	lwz	%r0, 20(%r1)						\n\
172f8328864SLeandro Lupori 	addi	%r1, %r1, 16						\n\
173f8328864SLeandro Lupori 	mtlr	%r0							\n\
174f8328864SLeandro Lupori 	blr								\n\
175f8328864SLeandro Lupori ");
176f8328864SLeandro Lupori }
177f8328864SLeandro Lupori 
178f8328864SLeandro Lupori /*
179f8328864SLeandro Lupori  * Little-endian OFW entrypoint replacement.
180f8328864SLeandro Lupori  *
181f8328864SLeandro Lupori  * We are doing all the byteswapping in one place here to save space.
182f8328864SLeandro Lupori  * This means instance handles will be byteswapped as well.
183f8328864SLeandro Lupori  */
184f8328864SLeandro Lupori int
call_ofw(ofwcell_t * buf)185f8328864SLeandro Lupori call_ofw(ofwcell_t* buf)
186f8328864SLeandro Lupori {
187f8328864SLeandro Lupori 	int ret, i, ncells;
188f8328864SLeandro Lupori 
189f8328864SLeandro Lupori 	ncells = 3 + buf[1] + buf[2];
190f8328864SLeandro Lupori 	for (i = 0; i < ncells; i++)
191f8328864SLeandro Lupori 		buf[i] = htobe32(buf[i]);
192f8328864SLeandro Lupori 
193f8328864SLeandro Lupori 	ret = (ofwtramp(buf, realofw));
194f8328864SLeandro Lupori 	for (i = 0; i < ncells; i++)
195f8328864SLeandro Lupori 		buf[i] = be32toh(buf[i]);
196f8328864SLeandro Lupori 	return (ret);
197f8328864SLeandro Lupori }
198f8328864SLeandro Lupori #endif
199f8328864SLeandro Lupori 
200ca987d46SWarner Losh void
ofw_init(void * vpd,int res,ofwfp_t openfirm,char * arg,int argl)201f8328864SLeandro Lupori ofw_init(void *vpd, int res, ofwfp_t openfirm, char *arg, int argl)
202ca987d46SWarner Losh {
203ca987d46SWarner Losh 	char *av[16];
204ca987d46SWarner Losh 	char *p;
205ca987d46SWarner Losh 	int ac;
206ca987d46SWarner Losh 
207f8328864SLeandro Lupori #if BYTE_ORDER == LITTLE_ENDIAN
208f8328864SLeandro Lupori 	realofw = openfirm;
209f8328864SLeandro Lupori 	ofw = call_ofw;
210f8328864SLeandro Lupori #else
211f8328864SLeandro Lupori 	realofw = ofw = openfirm;
212f8328864SLeandro Lupori #endif
213ca987d46SWarner Losh 
214ca987d46SWarner Losh 	chosenh = ofw_finddevice("/chosen");
215ca987d46SWarner Losh 	ofw_getprop(chosenh, "stdin", &stdinh, sizeof(stdinh));
216f8328864SLeandro Lupori 	stdinh = be32toh(stdinh);
217ca987d46SWarner Losh 	ofw_getprop(chosenh, "stdout", &stdouth, sizeof(stdouth));
218f8328864SLeandro Lupori 	stdouth = be32toh(stdouth);
219ca987d46SWarner Losh 	ofw_getprop(chosenh, "bootargs", bootargs, sizeof(bootargs));
220ca987d46SWarner Losh 	ofw_getprop(chosenh, "bootpath", bootpath, sizeof(bootpath));
221ca987d46SWarner Losh 
222ca987d46SWarner Losh 	bootargs[sizeof(bootargs) - 1] = '\0';
223ca987d46SWarner Losh 	bootpath[sizeof(bootpath) - 1] = '\0';
224ca987d46SWarner Losh 
225ca987d46SWarner Losh 	p = bootpath;
226ca987d46SWarner Losh 	while (*p != '\0') {
227ca987d46SWarner Losh 		/* Truncate partition ID */
228ca987d46SWarner Losh 		if (*p == ':') {
229ca987d46SWarner Losh 			ofw_close(bootdev);
230ca987d46SWarner Losh 			*(++p) = '\0';
231ca987d46SWarner Losh 			break;
232ca987d46SWarner Losh 		}
233ca987d46SWarner Losh 		p++;
234ca987d46SWarner Losh 	}
235ca987d46SWarner Losh 
236ca987d46SWarner Losh 	ac = 0;
237ca987d46SWarner Losh 	p = bootargs;
238ca987d46SWarner Losh 	for (;;) {
239ca987d46SWarner Losh 		while (*p == ' ' && *p != '\0')
240ca987d46SWarner Losh 			p++;
241ca987d46SWarner Losh 		if (*p == '\0' || ac >= 16)
242ca987d46SWarner Losh 			break;
243ca987d46SWarner Losh 		av[ac++] = p;
244ca987d46SWarner Losh 		while (*p != ' ' && *p != '\0')
245ca987d46SWarner Losh 			p++;
246ca987d46SWarner Losh 		if (*p != '\0')
247ca987d46SWarner Losh 			*p++ = '\0';
248ca987d46SWarner Losh 	}
249ca987d46SWarner Losh 
250ca987d46SWarner Losh 	exit(main(ac, av));
251ca987d46SWarner Losh }
252ca987d46SWarner Losh 
253ca987d46SWarner Losh static ofwh_t
ofw_finddevice(const char * name)254ca987d46SWarner Losh ofw_finddevice(const char *name)
255ca987d46SWarner Losh {
256ca987d46SWarner Losh 	ofwcell_t args[] = {
257ca987d46SWarner Losh 		(ofwcell_t)"finddevice",
258ca987d46SWarner Losh 		1,
259ca987d46SWarner Losh 		1,
260ca987d46SWarner Losh 		(ofwcell_t)name,
261ca987d46SWarner Losh 		0
262ca987d46SWarner Losh 	};
263ca987d46SWarner Losh 
264ca987d46SWarner Losh 	if ((*ofw)(args)) {
265ca987d46SWarner Losh 		printf("ofw_finddevice: name=\"%s\"\n", name);
266ca987d46SWarner Losh 		return (1);
267ca987d46SWarner Losh 	}
268ca987d46SWarner Losh 	return (args[4]);
269ca987d46SWarner Losh }
270ca987d46SWarner Losh 
271ca987d46SWarner Losh static int
ofw_getprop(ofwh_t ofwh,const char * name,void * buf,size_t len)272ca987d46SWarner Losh ofw_getprop(ofwh_t ofwh, const char *name, void *buf, size_t len)
273ca987d46SWarner Losh {
274ca987d46SWarner Losh 	ofwcell_t args[] = {
275ca987d46SWarner Losh 		(ofwcell_t)"getprop",
276ca987d46SWarner Losh 		4,
277ca987d46SWarner Losh 		1,
278ca987d46SWarner Losh 		(u_ofwh_t)ofwh,
279ca987d46SWarner Losh 		(ofwcell_t)name,
280ca987d46SWarner Losh 		(ofwcell_t)buf,
281ca987d46SWarner Losh 		len,
282ca987d46SWarner Losh 	0
283ca987d46SWarner Losh 	};
284ca987d46SWarner Losh 
285ca987d46SWarner Losh 	if ((*ofw)(args)) {
286ca987d46SWarner Losh 		printf("ofw_getprop: ofwh=0x%x buf=%p len=%u\n",
287ca987d46SWarner Losh 			ofwh, buf, len);
288ca987d46SWarner Losh 		return (1);
289ca987d46SWarner Losh 	}
290ca987d46SWarner Losh 	return (0);
291ca987d46SWarner Losh }
292ca987d46SWarner Losh 
293ca987d46SWarner Losh static int
ofw_setprop(ofwh_t ofwh,const char * name,void * buf,size_t len)294ca987d46SWarner Losh ofw_setprop(ofwh_t ofwh, const char *name, void *buf, size_t len)
295ca987d46SWarner Losh {
296ca987d46SWarner Losh 	ofwcell_t args[] = {
297ca987d46SWarner Losh 		(ofwcell_t)"setprop",
298ca987d46SWarner Losh 		4,
299ca987d46SWarner Losh 		1,
300ca987d46SWarner Losh 		(u_ofwh_t)ofwh,
301ca987d46SWarner Losh 		(ofwcell_t)name,
302ca987d46SWarner Losh 		(ofwcell_t)buf,
303ca987d46SWarner Losh 		len,
304ca987d46SWarner Losh 	0
305ca987d46SWarner Losh 	};
306ca987d46SWarner Losh 
307ca987d46SWarner Losh 	if ((*ofw)(args)) {
308ca987d46SWarner Losh 		printf("ofw_setprop: ofwh=0x%x buf=%p len=%u\n",
309ca987d46SWarner Losh 			ofwh, buf, len);
310ca987d46SWarner Losh 		return (1);
311ca987d46SWarner Losh 	}
312ca987d46SWarner Losh 	return (0);
313ca987d46SWarner Losh }
314ca987d46SWarner Losh 
315ca987d46SWarner Losh static ofwh_t
ofw_open(const char * path)316ca987d46SWarner Losh ofw_open(const char *path)
317ca987d46SWarner Losh {
318ca987d46SWarner Losh 	ofwcell_t args[] = {
319ca987d46SWarner Losh 		(ofwcell_t)"open",
320ca987d46SWarner Losh 		1,
321ca987d46SWarner Losh 		1,
322ca987d46SWarner Losh 		(ofwcell_t)path,
323ca987d46SWarner Losh 		0
324ca987d46SWarner Losh 	};
325ca987d46SWarner Losh 
326ca987d46SWarner Losh 	if ((*ofw)(args)) {
327ca987d46SWarner Losh 		printf("ofw_open: path=\"%s\"\n", path);
328ca987d46SWarner Losh 		return (-1);
329ca987d46SWarner Losh 	}
330ca987d46SWarner Losh 	return (args[4]);
331ca987d46SWarner Losh }
332ca987d46SWarner Losh 
333ca987d46SWarner Losh static int
ofw_close(ofwh_t devh)334ca987d46SWarner Losh ofw_close(ofwh_t devh)
335ca987d46SWarner Losh {
336ca987d46SWarner Losh 	ofwcell_t args[] = {
337ca987d46SWarner Losh 		(ofwcell_t)"close",
338ca987d46SWarner Losh 		1,
339ca987d46SWarner Losh 		0,
340ca987d46SWarner Losh 		(u_ofwh_t)devh
341ca987d46SWarner Losh 	};
342ca987d46SWarner Losh 
343ca987d46SWarner Losh 	if ((*ofw)(args)) {
344ca987d46SWarner Losh 		printf("ofw_close: devh=0x%x\n", devh);
345ca987d46SWarner Losh 		return (1);
346ca987d46SWarner Losh 	}
347ca987d46SWarner Losh 	return (0);
348ca987d46SWarner Losh }
349ca987d46SWarner Losh 
350ca987d46SWarner Losh static int
ofw_claim(void * virt,size_t len,u_int align)351ca987d46SWarner Losh ofw_claim(void *virt, size_t len, u_int align)
352ca987d46SWarner Losh {
353ca987d46SWarner Losh 	ofwcell_t args[] = {
354ca987d46SWarner Losh 		(ofwcell_t)"claim",
355ca987d46SWarner Losh 		3,
356ca987d46SWarner Losh 		1,
357ca987d46SWarner Losh 		(ofwcell_t)virt,
358ca987d46SWarner Losh 		len,
359ca987d46SWarner Losh 		align,
360ca987d46SWarner Losh 		0,
361ca987d46SWarner Losh 		0
362ca987d46SWarner Losh 	};
363ca987d46SWarner Losh 
364ca987d46SWarner Losh 	if ((*ofw)(args)) {
365ca987d46SWarner Losh 		printf("ofw_claim: virt=%p len=%u\n", virt, len);
366ca987d46SWarner Losh 		return (1);
367ca987d46SWarner Losh 	}
368ca987d46SWarner Losh 
369ca987d46SWarner Losh 	return (0);
370ca987d46SWarner Losh }
371ca987d46SWarner Losh 
372ca987d46SWarner Losh static int
ofw_read(ofwh_t devh,void * buf,size_t len)373ca987d46SWarner Losh ofw_read(ofwh_t devh, void *buf, size_t len)
374ca987d46SWarner Losh {
375ca987d46SWarner Losh 	ofwcell_t args[] = {
376ca987d46SWarner Losh 		(ofwcell_t)"read",
377ca987d46SWarner Losh 		3,
378ca987d46SWarner Losh 		1,
379ca987d46SWarner Losh 		(u_ofwh_t)devh,
380ca987d46SWarner Losh 		(ofwcell_t)buf,
381ca987d46SWarner Losh 		len,
382ca987d46SWarner Losh 		0
383ca987d46SWarner Losh 	};
384ca987d46SWarner Losh 
385ca987d46SWarner Losh 	if ((*ofw)(args)) {
386ca987d46SWarner Losh 		printf("ofw_read: devh=0x%x buf=%p len=%u\n", devh, buf, len);
387ca987d46SWarner Losh 		return (1);
388ca987d46SWarner Losh 	}
389ca987d46SWarner Losh 	return (0);
390ca987d46SWarner Losh }
391ca987d46SWarner Losh 
392ca987d46SWarner Losh static int
ofw_write(ofwh_t devh,const void * buf,size_t len)393ca987d46SWarner Losh ofw_write(ofwh_t devh, const void *buf, size_t len)
394ca987d46SWarner Losh {
395ca987d46SWarner Losh 	ofwcell_t args[] = {
396ca987d46SWarner Losh 		(ofwcell_t)"write",
397ca987d46SWarner Losh 		3,
398ca987d46SWarner Losh 		1,
399ca987d46SWarner Losh 		(u_ofwh_t)devh,
400ca987d46SWarner Losh 		(ofwcell_t)buf,
401ca987d46SWarner Losh 		len,
402ca987d46SWarner Losh 		0
403ca987d46SWarner Losh 	};
404ca987d46SWarner Losh 
405ca987d46SWarner Losh 	if ((*ofw)(args)) {
406ca987d46SWarner Losh 		printf("ofw_write: devh=0x%x buf=%p len=%u\n", devh, buf, len);
407ca987d46SWarner Losh 		return (1);
408ca987d46SWarner Losh 	}
409ca987d46SWarner Losh 	return (0);
410ca987d46SWarner Losh }
411ca987d46SWarner Losh 
412ca987d46SWarner Losh static int
ofw_seek(ofwh_t devh,uint64_t off)41356e53cb8SWarner Losh ofw_seek(ofwh_t devh, uint64_t off)
414ca987d46SWarner Losh {
415ca987d46SWarner Losh 	ofwcell_t args[] = {
416ca987d46SWarner Losh 		(ofwcell_t)"seek",
417ca987d46SWarner Losh 		3,
418ca987d46SWarner Losh 		1,
419ca987d46SWarner Losh 		(u_ofwh_t)devh,
420ca987d46SWarner Losh 		off >> 32,
421ca987d46SWarner Losh 		off,
422ca987d46SWarner Losh 		0
423ca987d46SWarner Losh 	};
424ca987d46SWarner Losh 
425ca987d46SWarner Losh 	if ((*ofw)(args)) {
426ca987d46SWarner Losh 		printf("ofw_seek: devh=0x%x off=0x%lx\n", devh, off);
427ca987d46SWarner Losh 		return (1);
428ca987d46SWarner Losh 	}
429ca987d46SWarner Losh 	return (0);
430ca987d46SWarner Losh }
431ca987d46SWarner Losh 
432ca987d46SWarner Losh static void
ofw_exit(void)433ca987d46SWarner Losh ofw_exit(void)
434ca987d46SWarner Losh {
435ca987d46SWarner Losh 	ofwcell_t args[3];
436ca987d46SWarner Losh 
437ca987d46SWarner Losh 	args[0] = (ofwcell_t)"exit";
438ca987d46SWarner Losh 	args[1] = 0;
439ca987d46SWarner Losh 	args[2] = 0;
440ca987d46SWarner Losh 
441ca987d46SWarner Losh 	for (;;)
442ca987d46SWarner Losh 		(*ofw)(args);
443ca987d46SWarner Losh }
444ca987d46SWarner Losh 
445ca987d46SWarner Losh static void
bcopy(const void * src,void * dst,size_t len)446ca987d46SWarner Losh bcopy(const void *src, void *dst, size_t len)
447ca987d46SWarner Losh {
448ca987d46SWarner Losh 	const char *s = src;
449ca987d46SWarner Losh 	char *d = dst;
450ca987d46SWarner Losh 
451ca987d46SWarner Losh 	while (len-- != 0)
452ca987d46SWarner Losh 		*d++ = *s++;
453ca987d46SWarner Losh }
454ca987d46SWarner Losh 
455ca987d46SWarner Losh static void
memcpy(void * dst,const void * src,size_t len)456ca987d46SWarner Losh memcpy(void *dst, const void *src, size_t len)
457ca987d46SWarner Losh {
458ca987d46SWarner Losh 	bcopy(src, dst, len);
459ca987d46SWarner Losh }
460ca987d46SWarner Losh 
461ca987d46SWarner Losh static void
bzero(void * b,size_t len)462ca987d46SWarner Losh bzero(void *b, size_t len)
463ca987d46SWarner Losh {
464ca987d46SWarner Losh 	char *p = b;
465ca987d46SWarner Losh 
466ca987d46SWarner Losh 	while (len-- != 0)
467ca987d46SWarner Losh 		*p++ = 0;
468ca987d46SWarner Losh }
469ca987d46SWarner Losh 
470ca987d46SWarner Losh static int
strcmp(const char * s1,const char * s2)471ca987d46SWarner Losh strcmp(const char *s1, const char *s2)
472ca987d46SWarner Losh {
473ca987d46SWarner Losh 	for (; *s1 == *s2 && *s1; s1++, s2++)
474ca987d46SWarner Losh 		;
475ca987d46SWarner Losh 	return ((u_char)*s1 - (u_char)*s2);
476ca987d46SWarner Losh }
477ca987d46SWarner Losh 
478ca987d46SWarner Losh #include "ufsread.c"
479ca987d46SWarner Losh 
480ca987d46SWarner Losh int
main(int ac,char ** av)481ca987d46SWarner Losh main(int ac, char **av)
482ca987d46SWarner Losh {
483ca987d46SWarner Losh 	const char *path;
484ca987d46SWarner Losh 	char bootpath_full[255];
485ca987d46SWarner Losh 	int i, len;
486ca987d46SWarner Losh 
487ca987d46SWarner Losh 	path = PATH_LOADER;
488ca987d46SWarner Losh 	for (i = 0; i < ac; i++) {
489ca987d46SWarner Losh 		switch (av[i][0]) {
490ca987d46SWarner Losh 		case '-':
491ca987d46SWarner Losh 			switch (av[i][1]) {
492ca987d46SWarner Losh 			default:
493ca987d46SWarner Losh 				usage();
494ca987d46SWarner Losh 			}
495ca987d46SWarner Losh 			break;
496ca987d46SWarner Losh 		default:
497ca987d46SWarner Losh 			path = av[i];
498ca987d46SWarner Losh 			break;
499ca987d46SWarner Losh 		}
500ca987d46SWarner Losh 	}
501ca987d46SWarner Losh 
502ca987d46SWarner Losh 	printf(" \n>> FreeBSD/powerpc Open Firmware boot block\n"
503ca987d46SWarner Losh 	"   Boot path:   %s\n"
504ca987d46SWarner Losh 	"   Boot loader: %s\n", bootpath, path);
505ca987d46SWarner Losh 
506ca987d46SWarner Losh 	len = 0;
507ca987d46SWarner Losh 	while (bootpath[len] != '\0') len++;
508ca987d46SWarner Losh 
509ca987d46SWarner Losh 	memcpy(bootpath_full,bootpath,len+1);
510ca987d46SWarner Losh 
511ca987d46SWarner Losh 	if (bootpath_full[len-1] != ':') {
512ca987d46SWarner Losh 		/* First try full volume */
513ca987d46SWarner Losh 		if (domount(bootpath_full,1) == 0)
514ca987d46SWarner Losh 			goto out;
515ca987d46SWarner Losh 
516ca987d46SWarner Losh 		/* Add a : so that we try partitions if that fails */
517ca987d46SWarner Losh 		if (bootdev > 0)
518ca987d46SWarner Losh 			ofw_close(bootdev);
519ca987d46SWarner Losh 		bootpath_full[len] = ':';
520ca987d46SWarner Losh 		len += 1;
521ca987d46SWarner Losh 	}
522ca987d46SWarner Losh 
523ca987d46SWarner Losh 	/* Loop through first 16 partitions to find a UFS one */
524ca987d46SWarner Losh 	for (i = 0; i < 16; i++) {
525ca987d46SWarner Losh 		if (i < 10) {
526ca987d46SWarner Losh 			bootpath_full[len] = i + '0';
527ca987d46SWarner Losh 			bootpath_full[len+1] = '\0';
528ca987d46SWarner Losh 		} else {
529ca987d46SWarner Losh 			bootpath_full[len] = '1';
530ca987d46SWarner Losh 			bootpath_full[len+1] = i - 10 + '0';
531ca987d46SWarner Losh 			bootpath_full[len+2] = '\0';
532ca987d46SWarner Losh 		}
533ca987d46SWarner Losh 
534ca987d46SWarner Losh 		if (domount(bootpath_full,1) >= 0)
535ca987d46SWarner Losh 			break;
536ca987d46SWarner Losh 
537ca987d46SWarner Losh 		if (bootdev > 0)
538ca987d46SWarner Losh 			ofw_close(bootdev);
539ca987d46SWarner Losh 	}
540ca987d46SWarner Losh 
541ca987d46SWarner Losh 	if (i >= 16)
542ca987d46SWarner Losh 		panic("domount");
543ca987d46SWarner Losh 
544ca987d46SWarner Losh out:
545ca987d46SWarner Losh 	printf("   Boot volume:   %s\n",bootpath_full);
546ca987d46SWarner Losh 	ofw_setprop(chosenh, "bootargs", bootpath_full, len+2);
547ca987d46SWarner Losh 	load(path);
548ca987d46SWarner Losh 	return (1);
549ca987d46SWarner Losh }
550ca987d46SWarner Losh 
551ca987d46SWarner Losh static void
usage(void)552ca987d46SWarner Losh usage(void)
553ca987d46SWarner Losh {
554ca987d46SWarner Losh 
555ca987d46SWarner Losh 	printf("usage: boot device [/path/to/loader]\n");
556ca987d46SWarner Losh 	exit(1);
557ca987d46SWarner Losh }
558ca987d46SWarner Losh 
559ca987d46SWarner Losh static void
exit(int code)560ca987d46SWarner Losh exit(int code)
561ca987d46SWarner Losh {
562ca987d46SWarner Losh 
563ca987d46SWarner Losh 	ofw_exit();
564ca987d46SWarner Losh }
565ca987d46SWarner Losh 
566ca987d46SWarner Losh static struct dmadat __dmadat;
567ca987d46SWarner Losh 
568ca987d46SWarner Losh static int
domount(const char * device,int quiet)569ca987d46SWarner Losh domount(const char *device, int quiet)
570ca987d46SWarner Losh {
571ca987d46SWarner Losh 
572ca987d46SWarner Losh 	dmadat = &__dmadat;
573ca987d46SWarner Losh 	if ((bootdev = ofw_open(device)) == -1) {
574ca987d46SWarner Losh 		printf("domount: can't open device\n");
575ca987d46SWarner Losh 		return (-1);
576ca987d46SWarner Losh 	}
577ca987d46SWarner Losh 	if (fsread(0, NULL, 0)) {
578ca987d46SWarner Losh 		if (!quiet)
579ca987d46SWarner Losh 			printf("domount: can't read superblock\n");
580ca987d46SWarner Losh 		return (-1);
581ca987d46SWarner Losh 	}
582ca987d46SWarner Losh 	return (0);
583ca987d46SWarner Losh }
584ca987d46SWarner Losh 
585ca987d46SWarner Losh static void
load(const char * fname)586ca987d46SWarner Losh load(const char *fname)
587ca987d46SWarner Losh {
588ca987d46SWarner Losh 	Elf32_Ehdr eh;
589ca987d46SWarner Losh 	Elf32_Phdr ph;
590ca987d46SWarner Losh 	caddr_t p;
591ca987d46SWarner Losh 	ufs_ino_t ino;
592ca987d46SWarner Losh 	int i;
593ca987d46SWarner Losh 
594ca987d46SWarner Losh 	if ((ino = lookup(fname)) == 0) {
595ca987d46SWarner Losh 		printf("File %s not found\n", fname);
596ca987d46SWarner Losh 		return;
597ca987d46SWarner Losh 	}
598ca987d46SWarner Losh 	if (fsread(ino, &eh, sizeof(eh)) != sizeof(eh)) {
599ca987d46SWarner Losh 		printf("Can't read elf header\n");
600ca987d46SWarner Losh 		return;
601ca987d46SWarner Losh 	}
602ca987d46SWarner Losh 	if (!IS_ELF(eh)) {
603ca987d46SWarner Losh 		printf("Not an ELF file\n");
604ca987d46SWarner Losh 		return;
605ca987d46SWarner Losh 	}
606ca987d46SWarner Losh 	for (i = 0; i < eh.e_phnum; i++) {
607ca987d46SWarner Losh 		fs_off = eh.e_phoff + i * eh.e_phentsize;
608ca987d46SWarner Losh 		if (fsread(ino, &ph, sizeof(ph)) != sizeof(ph)) {
609ca987d46SWarner Losh 			printf("Can't read program header %d\n", i);
610ca987d46SWarner Losh 			return;
611ca987d46SWarner Losh 		}
612ca987d46SWarner Losh 		if (ph.p_type != PT_LOAD)
613ca987d46SWarner Losh 			continue;
614ca987d46SWarner Losh 		fs_off = ph.p_offset;
615ca987d46SWarner Losh 		p = (caddr_t)ph.p_vaddr;
616ca987d46SWarner Losh 		ofw_claim(p,(ph.p_filesz > ph.p_memsz) ?
617ca987d46SWarner Losh 		    ph.p_filesz : ph.p_memsz,0);
618ca987d46SWarner Losh 		if (fsread(ino, p, ph.p_filesz) != ph.p_filesz) {
619ca987d46SWarner Losh 			printf("Can't read content of section %d\n", i);
620ca987d46SWarner Losh 			return;
621ca987d46SWarner Losh 		}
622ca987d46SWarner Losh 		if (ph.p_filesz != ph.p_memsz)
623ca987d46SWarner Losh 			bzero(p + ph.p_filesz, ph.p_memsz - ph.p_filesz);
624ca987d46SWarner Losh 		__syncicache(p, ph.p_memsz);
625ca987d46SWarner Losh 	}
626ca987d46SWarner Losh 	ofw_close(bootdev);
627ca987d46SWarner Losh 	(*(void (*)(void *, int, ofwfp_t, char *, int))eh.e_entry)(NULL, 0,
628f8328864SLeandro Lupori 	    realofw, NULL, 0);
629ca987d46SWarner Losh }
630ca987d46SWarner Losh 
631ca987d46SWarner Losh static int
dskread(void * buf,uint64_t lba,int nblk)63256e53cb8SWarner Losh dskread(void *buf, uint64_t lba, int nblk)
633ca987d46SWarner Losh {
634ca987d46SWarner Losh 	/*
635ca987d46SWarner Losh 	 * The Open Firmware should open the correct partition for us.
636ca987d46SWarner Losh 	 * That means, if we read from offset zero on an open instance handle,
637ca987d46SWarner Losh 	 * we should read from offset zero of that partition.
638ca987d46SWarner Losh 	 */
639ca987d46SWarner Losh 	ofw_seek(bootdev, lba * DEV_BSIZE);
640ca987d46SWarner Losh 	ofw_read(bootdev, buf, nblk * DEV_BSIZE);
641ca987d46SWarner Losh 	return (0);
642ca987d46SWarner Losh }
643ca987d46SWarner Losh 
644ca987d46SWarner Losh static void
panic(const char * fmt,...)645ca987d46SWarner Losh panic(const char *fmt, ...)
646ca987d46SWarner Losh {
647ca987d46SWarner Losh 	char buf[128];
648ca987d46SWarner Losh 	va_list ap;
649ca987d46SWarner Losh 
650ca987d46SWarner Losh 	va_start(ap, fmt);
651ca987d46SWarner Losh 	vsnprintf(buf, sizeof buf, fmt, ap);
652ca987d46SWarner Losh 	printf("panic: %s\n", buf);
653ca987d46SWarner Losh 	va_end(ap);
654ca987d46SWarner Losh 
655ca987d46SWarner Losh 	exit(1);
656ca987d46SWarner Losh }
657ca987d46SWarner Losh 
658ca987d46SWarner Losh static int
printf(const char * fmt,...)659ca987d46SWarner Losh printf(const char *fmt, ...)
660ca987d46SWarner Losh {
661ca987d46SWarner Losh 	va_list ap;
662ca987d46SWarner Losh 	int ret;
663ca987d46SWarner Losh 
664ca987d46SWarner Losh 	va_start(ap, fmt);
665ca987d46SWarner Losh 	ret = vprintf(fmt, ap);
666ca987d46SWarner Losh 	va_end(ap);
667ca987d46SWarner Losh 	return (ret);
668ca987d46SWarner Losh }
669ca987d46SWarner Losh 
670ca987d46SWarner Losh static int
putchar(char c,void * arg)671ca987d46SWarner Losh putchar(char c, void *arg)
672ca987d46SWarner Losh {
673ca987d46SWarner Losh 	char buf;
674ca987d46SWarner Losh 
675ca987d46SWarner Losh 	if (c == '\n') {
676ca987d46SWarner Losh 		buf = '\r';
677ca987d46SWarner Losh 		ofw_write(stdouth, &buf, 1);
678ca987d46SWarner Losh 	}
679ca987d46SWarner Losh 	buf = c;
680ca987d46SWarner Losh 	ofw_write(stdouth, &buf, 1);
681ca987d46SWarner Losh 	return (1);
682ca987d46SWarner Losh }
683ca987d46SWarner Losh 
684ca987d46SWarner Losh static int
vprintf(const char * fmt,va_list ap)685ca987d46SWarner Losh vprintf(const char *fmt, va_list ap)
686ca987d46SWarner Losh {
687ca987d46SWarner Losh 	int ret;
688ca987d46SWarner Losh 
689ca987d46SWarner Losh 	ret = __printf(fmt, putchar, 0, ap);
690ca987d46SWarner Losh 	return (ret);
691ca987d46SWarner Losh }
692ca987d46SWarner Losh 
693ca987d46SWarner Losh static int
vsnprintf(char * str,size_t sz,const char * fmt,va_list ap)694ca987d46SWarner Losh vsnprintf(char *str, size_t sz, const char *fmt, va_list ap)
695ca987d46SWarner Losh {
696ca987d46SWarner Losh 	struct sp_data sp;
697ca987d46SWarner Losh 	int ret;
698ca987d46SWarner Losh 
699ca987d46SWarner Losh 	sp.sp_buf = str;
700ca987d46SWarner Losh 	sp.sp_len = 0;
701ca987d46SWarner Losh 	sp.sp_size = sz;
702ca987d46SWarner Losh 	ret = __printf(fmt, __sputc, &sp, ap);
703ca987d46SWarner Losh 	return (ret);
704ca987d46SWarner Losh }
705ca987d46SWarner Losh 
706ca987d46SWarner Losh static int
__printf(const char * fmt,putc_func_t * putc,void * arg,va_list ap)707ca987d46SWarner Losh __printf(const char *fmt, putc_func_t *putc, void *arg, va_list ap)
708ca987d46SWarner Losh {
709ca987d46SWarner Losh 	char buf[(sizeof(long) * 8) + 1];
710ca987d46SWarner Losh 	char *nbuf;
711ca987d46SWarner Losh 	u_long ul;
712ca987d46SWarner Losh 	u_int ui;
713ca987d46SWarner Losh 	int lflag;
714ca987d46SWarner Losh 	int sflag;
715ca987d46SWarner Losh 	char *s;
716ca987d46SWarner Losh 	int pad;
717ca987d46SWarner Losh 	int ret;
718ca987d46SWarner Losh 	int c;
719ca987d46SWarner Losh 
720ca987d46SWarner Losh 	nbuf = &buf[sizeof buf - 1];
721ca987d46SWarner Losh 	ret = 0;
722ca987d46SWarner Losh 	while ((c = *fmt++) != 0) {
723ca987d46SWarner Losh 		if (c != '%') {
724ca987d46SWarner Losh 			ret += putc(c, arg);
725ca987d46SWarner Losh 			continue;
726ca987d46SWarner Losh 		}
727ca987d46SWarner Losh 		lflag = 0;
728ca987d46SWarner Losh 		sflag = 0;
729ca987d46SWarner Losh 		pad = 0;
730ca987d46SWarner Losh reswitch:	c = *fmt++;
731ca987d46SWarner Losh 		switch (c) {
732ca987d46SWarner Losh 		case '#':
733ca987d46SWarner Losh 			sflag = 1;
734ca987d46SWarner Losh 			goto reswitch;
735ca987d46SWarner Losh 		case '%':
736ca987d46SWarner Losh 			ret += putc('%', arg);
737ca987d46SWarner Losh 			break;
738ca987d46SWarner Losh 		case 'c':
739ca987d46SWarner Losh 			c = va_arg(ap, int);
740ca987d46SWarner Losh 			ret += putc(c, arg);
741ca987d46SWarner Losh 			break;
742ca987d46SWarner Losh 		case 'd':
743ca987d46SWarner Losh 			if (lflag == 0) {
744ca987d46SWarner Losh 				ui = (u_int)va_arg(ap, int);
745ca987d46SWarner Losh 				if (ui < (int)ui) {
746ca987d46SWarner Losh 					ui = -ui;
747ca987d46SWarner Losh 					ret += putc('-', arg);
748ca987d46SWarner Losh 				}
749ca987d46SWarner Losh 				s = __uitoa(nbuf, ui, 10);
750ca987d46SWarner Losh 			} else {
751ca987d46SWarner Losh 				ul = (u_long)va_arg(ap, long);
752ca987d46SWarner Losh 				if (ul < (long)ul) {
753ca987d46SWarner Losh 					ul = -ul;
754ca987d46SWarner Losh 					ret += putc('-', arg);
755ca987d46SWarner Losh 				}
756ca987d46SWarner Losh 				s = __ultoa(nbuf, ul, 10);
757ca987d46SWarner Losh 			}
758ca987d46SWarner Losh 			ret += __puts(s, putc, arg);
759ca987d46SWarner Losh 			break;
760ca987d46SWarner Losh 		case 'l':
761ca987d46SWarner Losh 			lflag = 1;
762ca987d46SWarner Losh 			goto reswitch;
763ca987d46SWarner Losh 		case 'o':
764ca987d46SWarner Losh 			if (lflag == 0) {
765ca987d46SWarner Losh 				ui = (u_int)va_arg(ap, u_int);
766ca987d46SWarner Losh 				s = __uitoa(nbuf, ui, 8);
767ca987d46SWarner Losh 			} else {
768ca987d46SWarner Losh 				ul = (u_long)va_arg(ap, u_long);
769ca987d46SWarner Losh 				s = __ultoa(nbuf, ul, 8);
770ca987d46SWarner Losh 			}
771ca987d46SWarner Losh 			ret += __puts(s, putc, arg);
772ca987d46SWarner Losh 			break;
773ca987d46SWarner Losh 		case 'p':
774ca987d46SWarner Losh 			ul = (u_long)va_arg(ap, void *);
775ca987d46SWarner Losh 			s = __ultoa(nbuf, ul, 16);
776ca987d46SWarner Losh 			ret += __puts("0x", putc, arg);
777ca987d46SWarner Losh 			ret += __puts(s, putc, arg);
778ca987d46SWarner Losh 			break;
779ca987d46SWarner Losh 		case 's':
780ca987d46SWarner Losh 			s = va_arg(ap, char *);
781ca987d46SWarner Losh 			ret += __puts(s, putc, arg);
782ca987d46SWarner Losh 			break;
783ca987d46SWarner Losh 		case 'u':
784ca987d46SWarner Losh 			if (lflag == 0) {
785ca987d46SWarner Losh 				ui = va_arg(ap, u_int);
786ca987d46SWarner Losh 				s = __uitoa(nbuf, ui, 10);
787ca987d46SWarner Losh 			} else {
788ca987d46SWarner Losh 				ul = va_arg(ap, u_long);
789ca987d46SWarner Losh 				s = __ultoa(nbuf, ul, 10);
790ca987d46SWarner Losh 			}
791ca987d46SWarner Losh 			ret += __puts(s, putc, arg);
792ca987d46SWarner Losh 			break;
793ca987d46SWarner Losh 		case 'x':
794ca987d46SWarner Losh 			if (lflag == 0) {
795ca987d46SWarner Losh 				ui = va_arg(ap, u_int);
796ca987d46SWarner Losh 				s = __uitoa(nbuf, ui, 16);
797ca987d46SWarner Losh 			} else {
798ca987d46SWarner Losh 				ul = va_arg(ap, u_long);
799ca987d46SWarner Losh 				s = __ultoa(nbuf, ul, 16);
800ca987d46SWarner Losh 			}
801ca987d46SWarner Losh 			if (sflag)
802ca987d46SWarner Losh 				ret += __puts("0x", putc, arg);
803ca987d46SWarner Losh 			ret += __puts(s, putc, arg);
804ca987d46SWarner Losh 			break;
805ca987d46SWarner Losh 		case '0': case '1': case '2': case '3': case '4':
806ca987d46SWarner Losh 		case '5': case '6': case '7': case '8': case '9':
807ca987d46SWarner Losh 			pad = pad * 10 + c - '0';
808ca987d46SWarner Losh 			goto reswitch;
809ca987d46SWarner Losh 		default:
810ca987d46SWarner Losh 			break;
811ca987d46SWarner Losh 		}
812ca987d46SWarner Losh 	}
813ca987d46SWarner Losh 	return (ret);
814ca987d46SWarner Losh }
815ca987d46SWarner Losh 
816ca987d46SWarner Losh static int
__sputc(char c,void * arg)817ca987d46SWarner Losh __sputc(char c, void *arg)
818ca987d46SWarner Losh {
819ca987d46SWarner Losh 	struct sp_data *sp;
820ca987d46SWarner Losh 
821ca987d46SWarner Losh 	sp = arg;
822ca987d46SWarner Losh 	if (sp->sp_len < sp->sp_size)
823ca987d46SWarner Losh 		sp->sp_buf[sp->sp_len++] = c;
824ca987d46SWarner Losh 	sp->sp_buf[sp->sp_len] = '\0';
825ca987d46SWarner Losh 	return (1);
826ca987d46SWarner Losh }
827ca987d46SWarner Losh 
828ca987d46SWarner Losh static int
__puts(const char * s,putc_func_t * putc,void * arg)829ca987d46SWarner Losh __puts(const char *s, putc_func_t *putc, void *arg)
830ca987d46SWarner Losh {
831ca987d46SWarner Losh 	const char *p;
832ca987d46SWarner Losh 	int ret;
833ca987d46SWarner Losh 
834ca987d46SWarner Losh 	ret = 0;
835ca987d46SWarner Losh 	for (p = s; *p != '\0'; p++)
836ca987d46SWarner Losh 		ret += putc(*p, arg);
837ca987d46SWarner Losh 	return (ret);
838ca987d46SWarner Losh }
839ca987d46SWarner Losh 
840ca987d46SWarner Losh static char *
__uitoa(char * buf,u_int ui,int base)841ca987d46SWarner Losh __uitoa(char *buf, u_int ui, int base)
842ca987d46SWarner Losh {
843ca987d46SWarner Losh 	char *p;
844ca987d46SWarner Losh 
845ca987d46SWarner Losh 	p = buf;
846ca987d46SWarner Losh 	*p = '\0';
847ca987d46SWarner Losh 	do
848ca987d46SWarner Losh 		*--p = digits[ui % base];
849ca987d46SWarner Losh 	while ((ui /= base) != 0);
850ca987d46SWarner Losh 	return (p);
851ca987d46SWarner Losh }
852ca987d46SWarner Losh 
853ca987d46SWarner Losh static char *
__ultoa(char * buf,u_long ul,int base)854ca987d46SWarner Losh __ultoa(char *buf, u_long ul, int base)
855ca987d46SWarner Losh {
856ca987d46SWarner Losh 	char *p;
857ca987d46SWarner Losh 
858ca987d46SWarner Losh 	p = buf;
859ca987d46SWarner Losh 	*p = '\0';
860ca987d46SWarner Losh 	do
861ca987d46SWarner Losh 		*--p = digits[ul % base];
862ca987d46SWarner Losh 	while ((ul /= base) != 0);
863ca987d46SWarner Losh 	return (p);
864ca987d46SWarner Losh }
865