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