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: stable/12/stand/sparc64/boot1/boot1.c 330864 2018-03-13 16:33:00Z imp $");
20
21 #include <sys/param.h>
22 #include <sys/dirent.h>
23
24 #include <machine/elf.h>
25 #include <machine/stdarg.h>
26
27 #include "paths.h"
28
29 #define READ_BUF_SIZE 8192
30
31 typedef int putc_func_t(char c, void *arg);
32 typedef int32_t ofwh_t;
33
34 struct sp_data {
35 char *sp_buf;
36 u_int sp_len;
37 u_int sp_size;
38 };
39
40 static const char digits[] = "0123456789abcdef";
41
42 static char bootpath[128];
43 static char bootargs[128];
44
45 static ofwh_t bootdev;
46
47 static uint32_t fs_off;
48
49 int main(int ac, char **av);
50 static void exit(int) __dead2;
51 static void usage(void);
52
53 #ifdef ZFSBOOT
54 static void loadzfs(void);
55 static int zbread(char *buf, off_t off, size_t bytes);
56 #else
57 static void load(const char *);
58 #endif
59
60 static void bcopy(const void *src, void *dst, size_t len);
61 static void bzero(void *b, size_t len);
62
63 static int domount(const char *device);
64 static int dskread(void *buf, uint64_t lba, int nblk);
65
66 static void panic(const char *fmt, ...) __dead2;
67 static int printf(const char *fmt, ...);
68 static int putchar(char c, void *arg);
69 static int vprintf(const char *fmt, va_list ap);
70 static int vsnprintf(char *str, size_t sz, const char *fmt, va_list ap);
71
72 static int __printf(const char *fmt, putc_func_t *putc, void *arg, va_list ap);
73 static int __puts(const char *s, putc_func_t *putc, void *arg);
74 static int __sputc(char c, void *arg);
75 static char *__uitoa(char *buf, u_int val, int base);
76 static char *__ultoa(char *buf, u_long val, int base);
77
78 /*
79 * Open Firmware interface functions
80 */
81 typedef uint64_t ofwcell_t;
82 typedef uint32_t u_ofwh_t;
83 typedef int (*ofwfp_t)(ofwcell_t []);
84 static ofwfp_t ofw; /* the PROM Open Firmware entry */
85
86 void ofw_init(int, int, int, int, ofwfp_t);
87 static ofwh_t ofw_finddevice(const char *);
88 static ofwh_t ofw_open(const char *);
89 static int ofw_getprop(ofwh_t, const char *, void *, size_t);
90 static int ofw_read(ofwh_t, void *, size_t);
91 static int ofw_write(ofwh_t, const void *, size_t);
92 static int ofw_seek(ofwh_t, uint64_t);
93 static void ofw_exit(void) __dead2;
94
95 static ofwh_t stdinh, stdouth;
96
97 /*
98 * This has to stay here, as the PROM seems to ignore the
99 * entry point specified in the a.out header. (or elftoaout is broken)
100 */
101
102 void
ofw_init(int d,int d1,int d2,int d3,ofwfp_t ofwaddr)103 ofw_init(int d, int d1, int d2, int d3, ofwfp_t ofwaddr)
104 {
105 ofwh_t chosenh;
106 char *av[16];
107 char *p;
108 int ac;
109
110 ofw = ofwaddr;
111
112 chosenh = ofw_finddevice("/chosen");
113 ofw_getprop(chosenh, "stdin", &stdinh, sizeof(stdinh));
114 ofw_getprop(chosenh, "stdout", &stdouth, sizeof(stdouth));
115 ofw_getprop(chosenh, "bootargs", bootargs, sizeof(bootargs));
116 ofw_getprop(chosenh, "bootpath", bootpath, sizeof(bootpath));
117
118 bootargs[sizeof(bootargs) - 1] = '\0';
119 bootpath[sizeof(bootpath) - 1] = '\0';
120
121 ac = 0;
122 p = bootargs;
123 for (;;) {
124 while (*p == ' ' && *p != '\0')
125 p++;
126 if (*p == '\0' || ac >= 16)
127 break;
128 av[ac++] = p;
129 while (*p != ' ' && *p != '\0')
130 p++;
131 if (*p != '\0')
132 *p++ = '\0';
133 }
134
135 exit(main(ac, av));
136 }
137
138 static ofwh_t
ofw_finddevice(const char * name)139 ofw_finddevice(const char *name)
140 {
141 ofwcell_t args[] = {
142 (ofwcell_t)"finddevice",
143 1,
144 1,
145 (ofwcell_t)name,
146 0
147 };
148
149 if ((*ofw)(args)) {
150 printf("ofw_finddevice: name=\"%s\"\n", name);
151 return (1);
152 }
153 return (args[4]);
154 }
155
156 static int
ofw_getprop(ofwh_t ofwh,const char * name,void * buf,size_t len)157 ofw_getprop(ofwh_t ofwh, const char *name, void *buf, size_t len)
158 {
159 ofwcell_t args[] = {
160 (ofwcell_t)"getprop",
161 4,
162 1,
163 (u_ofwh_t)ofwh,
164 (ofwcell_t)name,
165 (ofwcell_t)buf,
166 len,
167 0
168 };
169
170 if ((*ofw)(args)) {
171 printf("ofw_getprop: ofwh=0x%x buf=%p len=%u\n",
172 ofwh, buf, len);
173 return (1);
174 }
175 return (0);
176 }
177
178 static ofwh_t
ofw_open(const char * path)179 ofw_open(const char *path)
180 {
181 ofwcell_t args[] = {
182 (ofwcell_t)"open",
183 1,
184 1,
185 (ofwcell_t)path,
186 0
187 };
188
189 if ((*ofw)(args)) {
190 printf("ofw_open: path=\"%s\"\n", path);
191 return (-1);
192 }
193 return (args[4]);
194 }
195
196 static int
ofw_close(ofwh_t devh)197 ofw_close(ofwh_t devh)
198 {
199 ofwcell_t args[] = {
200 (ofwcell_t)"close",
201 1,
202 0,
203 (u_ofwh_t)devh
204 };
205
206 if ((*ofw)(args)) {
207 printf("ofw_close: devh=0x%x\n", devh);
208 return (1);
209 }
210 return (0);
211 }
212
213 static int
ofw_read(ofwh_t devh,void * buf,size_t len)214 ofw_read(ofwh_t devh, void *buf, size_t len)
215 {
216 ofwcell_t args[] = {
217 (ofwcell_t)"read",
218 3,
219 1,
220 (u_ofwh_t)devh,
221 (ofwcell_t)buf,
222 len,
223 0
224 };
225
226 if ((*ofw)(args)) {
227 printf("ofw_read: devh=0x%x buf=%p len=%u\n", devh, buf, len);
228 return (1);
229 }
230 return (0);
231 }
232
233 static int
ofw_write(ofwh_t devh,const void * buf,size_t len)234 ofw_write(ofwh_t devh, const void *buf, size_t len)
235 {
236 ofwcell_t args[] = {
237 (ofwcell_t)"write",
238 3,
239 1,
240 (u_ofwh_t)devh,
241 (ofwcell_t)buf,
242 len,
243 0
244 };
245
246 if ((*ofw)(args)) {
247 printf("ofw_write: devh=0x%x buf=%p len=%u\n", devh, buf, len);
248 return (1);
249 }
250 return (0);
251 }
252
253 static int
ofw_seek(ofwh_t devh,uint64_t off)254 ofw_seek(ofwh_t devh, uint64_t off)
255 {
256 ofwcell_t args[] = {
257 (ofwcell_t)"seek",
258 3,
259 1,
260 (u_ofwh_t)devh,
261 off >> 32,
262 off,
263 0
264 };
265
266 if ((*ofw)(args)) {
267 printf("ofw_seek: devh=0x%x off=0x%lx\n", devh, off);
268 return (1);
269 }
270 return (0);
271 }
272
273 static void
ofw_exit(void)274 ofw_exit(void)
275 {
276 ofwcell_t args[3];
277
278 args[0] = (ofwcell_t)"exit";
279 args[1] = 0;
280 args[2] = 0;
281
282 for (;;)
283 (*ofw)(args);
284 }
285
286 static void
bcopy(const void * src,void * dst,size_t len)287 bcopy(const void *src, void *dst, size_t len)
288 {
289 const char *s = src;
290 char *d = dst;
291
292 while (len-- != 0)
293 *d++ = *s++;
294 }
295
296 static void
memcpy(void * dst,const void * src,size_t len)297 memcpy(void *dst, const void *src, size_t len)
298 {
299
300 bcopy(src, dst, len);
301 }
302
303 static void
bzero(void * b,size_t len)304 bzero(void *b, size_t len)
305 {
306 char *p = b;
307
308 while (len-- != 0)
309 *p++ = 0;
310 }
311
312 static int
strcmp(const char * s1,const char * s2)313 strcmp(const char *s1, const char *s2)
314 {
315
316 for (; *s1 == *s2 && *s1; s1++, s2++)
317 ;
318 return ((u_char)*s1 - (u_char)*s2);
319 }
320
321 int
main(int ac,char ** av)322 main(int ac, char **av)
323 {
324 const char *path;
325 int i;
326
327 path = PATH_LOADER;
328 for (i = 0; i < ac; i++) {
329 switch (av[i][0]) {
330 case '-':
331 switch (av[i][1]) {
332 default:
333 usage();
334 }
335 break;
336 default:
337 path = av[i];
338 break;
339 }
340 }
341
342 #ifdef ZFSBOOT
343 printf(" \n>> FreeBSD/sparc64 ZFS boot block\n Boot path: %s\n",
344 bootpath);
345 #else
346 printf(" \n>> FreeBSD/sparc64 boot block\n Boot path: %s\n"
347 " Boot loader: %s\n", bootpath, path);
348 #endif
349
350 if (domount(bootpath) == -1)
351 panic("domount");
352
353 #ifdef ZFSBOOT
354 loadzfs();
355 #else
356 load(path);
357 #endif
358 return (1);
359 }
360
361 static void
usage(void)362 usage(void)
363 {
364
365 printf("usage: boot device [/path/to/loader]\n");
366 exit(1);
367 }
368
369 static void
exit(int code)370 exit(int code)
371 {
372
373 ofw_exit();
374 }
375
376 #ifdef ZFSBOOT
377
378 #define VDEV_BOOT_OFFSET (2 * 256 * 1024)
379 static char zbuf[READ_BUF_SIZE];
380
381 static int
zbread(char * buf,off_t off,size_t bytes)382 zbread(char *buf, off_t off, size_t bytes)
383 {
384 size_t len;
385 off_t poff;
386 off_t soff;
387 char *p;
388 unsigned int nb;
389 unsigned int lb;
390
391 p = buf;
392 soff = VDEV_BOOT_OFFSET + off;
393 lb = howmany(soff + bytes, DEV_BSIZE);
394 poff = soff;
395 while (poff < soff + bytes) {
396 nb = lb - poff / DEV_BSIZE;
397 if (nb > READ_BUF_SIZE / DEV_BSIZE)
398 nb = READ_BUF_SIZE / DEV_BSIZE;
399 if (dskread(zbuf, poff / DEV_BSIZE, nb))
400 break;
401 if ((poff / DEV_BSIZE + nb) * DEV_BSIZE > soff + bytes)
402 len = soff + bytes - poff;
403 else
404 len = (poff / DEV_BSIZE + nb) * DEV_BSIZE - poff;
405 memcpy(p, zbuf + poff % DEV_BSIZE, len);
406 p += len;
407 poff += len;
408 }
409 return (poff - soff);
410 }
411
412 static void
loadzfs(void)413 loadzfs(void)
414 {
415 Elf64_Ehdr eh;
416 Elf64_Phdr ph;
417 caddr_t p;
418 int i;
419
420 if (zbread((char *)&eh, 0, sizeof(eh)) != sizeof(eh)) {
421 printf("Can't read elf header\n");
422 return;
423 }
424 if (!IS_ELF(eh)) {
425 printf("Not an ELF file\n");
426 return;
427 }
428 for (i = 0; i < eh.e_phnum; i++) {
429 fs_off = eh.e_phoff + i * eh.e_phentsize;
430 if (zbread((char *)&ph, fs_off, sizeof(ph)) != sizeof(ph)) {
431 printf("Can't read program header %d\n", i);
432 return;
433 }
434 if (ph.p_type != PT_LOAD)
435 continue;
436 fs_off = ph.p_offset;
437 p = (caddr_t)ph.p_vaddr;
438 if (zbread(p, fs_off, ph.p_filesz) != ph.p_filesz) {
439 printf("Can't read content of section %d\n", i);
440 return;
441 }
442 if (ph.p_filesz != ph.p_memsz)
443 bzero(p + ph.p_filesz, ph.p_memsz - ph.p_filesz);
444 }
445 ofw_close(bootdev);
446 (*(void (*)(int, int, int, int, ofwfp_t))eh.e_entry)(0, 0, 0, 0, ofw);
447 }
448
449 #else
450
451 #include "ufsread.c"
452
453 static struct dmadat __dmadat;
454
455 static void
load(const char * fname)456 load(const char *fname)
457 {
458 Elf64_Ehdr eh;
459 Elf64_Phdr ph;
460 caddr_t p;
461 ufs_ino_t ino;
462 int i;
463
464 if ((ino = lookup(fname)) == 0) {
465 printf("File %s not found\n", fname);
466 return;
467 }
468 if (fsread(ino, &eh, sizeof(eh)) != sizeof(eh)) {
469 printf("Can't read elf header\n");
470 return;
471 }
472 if (!IS_ELF(eh)) {
473 printf("Not an ELF file\n");
474 return;
475 }
476 for (i = 0; i < eh.e_phnum; i++) {
477 fs_off = eh.e_phoff + i * eh.e_phentsize;
478 if (fsread(ino, &ph, sizeof(ph)) != sizeof(ph)) {
479 printf("Can't read program header %d\n", i);
480 return;
481 }
482 if (ph.p_type != PT_LOAD)
483 continue;
484 fs_off = ph.p_offset;
485 p = (caddr_t)ph.p_vaddr;
486 if (fsread(ino, p, ph.p_filesz) != ph.p_filesz) {
487 printf("Can't read content of section %d\n", i);
488 return;
489 }
490 if (ph.p_filesz != ph.p_memsz)
491 bzero(p + ph.p_filesz, ph.p_memsz - ph.p_filesz);
492 }
493 ofw_close(bootdev);
494 (*(void (*)(int, int, int, int, ofwfp_t))eh.e_entry)(0, 0, 0, 0, ofw);
495 }
496
497 #endif /* ZFSBOOT */
498
499 static int
domount(const char * device)500 domount(const char *device)
501 {
502
503 if ((bootdev = ofw_open(device)) == -1) {
504 printf("domount: can't open device\n");
505 return (-1);
506 }
507 #ifndef ZFSBOOT
508 dmadat = &__dmadat;
509 if (fsread(0, NULL, 0)) {
510 printf("domount: can't read superblock\n");
511 return (-1);
512 }
513 #endif
514 return (0);
515 }
516
517 static int
dskread(void * buf,uint64_t lba,int nblk)518 dskread(void *buf, uint64_t lba, int nblk)
519 {
520
521 /*
522 * The Open Firmware should open the correct partition for us.
523 * That means, if we read from offset zero on an open instance handle,
524 * we should read from offset zero of that partition.
525 */
526 ofw_seek(bootdev, lba * DEV_BSIZE);
527 ofw_read(bootdev, buf, nblk * DEV_BSIZE);
528 return (0);
529 }
530
531 static void
panic(const char * fmt,...)532 panic(const char *fmt, ...)
533 {
534 char buf[128];
535 va_list ap;
536
537 va_start(ap, fmt);
538 vsnprintf(buf, sizeof buf, fmt, ap);
539 printf("panic: %s\n", buf);
540 va_end(ap);
541
542 exit(1);
543 }
544
545 static int
printf(const char * fmt,...)546 printf(const char *fmt, ...)
547 {
548 va_list ap;
549 int ret;
550
551 va_start(ap, fmt);
552 ret = vprintf(fmt, ap);
553 va_end(ap);
554 return (ret);
555 }
556
557 static int
putchar(char c,void * arg)558 putchar(char c, void *arg)
559 {
560 char buf;
561
562 if (c == '\n') {
563 buf = '\r';
564 ofw_write(stdouth, &buf, 1);
565 }
566 buf = c;
567 ofw_write(stdouth, &buf, 1);
568 return (1);
569 }
570
571 static int
vprintf(const char * fmt,va_list ap)572 vprintf(const char *fmt, va_list ap)
573 {
574 int ret;
575
576 ret = __printf(fmt, putchar, 0, ap);
577 return (ret);
578 }
579
580 static int
vsnprintf(char * str,size_t sz,const char * fmt,va_list ap)581 vsnprintf(char *str, size_t sz, const char *fmt, va_list ap)
582 {
583 struct sp_data sp;
584 int ret;
585
586 sp.sp_buf = str;
587 sp.sp_len = 0;
588 sp.sp_size = sz;
589 ret = __printf(fmt, __sputc, &sp, ap);
590 return (ret);
591 }
592
593 static int
__printf(const char * fmt,putc_func_t * putc,void * arg,va_list ap)594 __printf(const char *fmt, putc_func_t *putc, void *arg, va_list ap)
595 {
596 char buf[(sizeof(long) * 8) + 1];
597 char *nbuf;
598 u_long ul;
599 u_int ui;
600 int lflag;
601 int sflag;
602 char *s;
603 int pad;
604 int ret;
605 int c;
606
607 nbuf = &buf[sizeof buf - 1];
608 ret = 0;
609 while ((c = *fmt++) != 0) {
610 if (c != '%') {
611 ret += putc(c, arg);
612 continue;
613 }
614 lflag = 0;
615 sflag = 0;
616 pad = 0;
617 reswitch: c = *fmt++;
618 switch (c) {
619 case '#':
620 sflag = 1;
621 goto reswitch;
622 case '%':
623 ret += putc('%', arg);
624 break;
625 case 'c':
626 c = va_arg(ap, int);
627 ret += putc(c, arg);
628 break;
629 case 'd':
630 if (lflag == 0) {
631 ui = (u_int)va_arg(ap, int);
632 if (ui < (int)ui) {
633 ui = -ui;
634 ret += putc('-', arg);
635 }
636 s = __uitoa(nbuf, ui, 10);
637 } else {
638 ul = (u_long)va_arg(ap, long);
639 if (ul < (long)ul) {
640 ul = -ul;
641 ret += putc('-', arg);
642 }
643 s = __ultoa(nbuf, ul, 10);
644 }
645 ret += __puts(s, putc, arg);
646 break;
647 case 'l':
648 lflag = 1;
649 goto reswitch;
650 case 'o':
651 if (lflag == 0) {
652 ui = (u_int)va_arg(ap, u_int);
653 s = __uitoa(nbuf, ui, 8);
654 } else {
655 ul = (u_long)va_arg(ap, u_long);
656 s = __ultoa(nbuf, ul, 8);
657 }
658 ret += __puts(s, putc, arg);
659 break;
660 case 'p':
661 ul = (u_long)va_arg(ap, void *);
662 s = __ultoa(nbuf, ul, 16);
663 ret += __puts("0x", putc, arg);
664 ret += __puts(s, putc, arg);
665 break;
666 case 's':
667 s = va_arg(ap, char *);
668 ret += __puts(s, putc, arg);
669 break;
670 case 'u':
671 if (lflag == 0) {
672 ui = va_arg(ap, u_int);
673 s = __uitoa(nbuf, ui, 10);
674 } else {
675 ul = va_arg(ap, u_long);
676 s = __ultoa(nbuf, ul, 10);
677 }
678 ret += __puts(s, putc, arg);
679 break;
680 case 'x':
681 if (lflag == 0) {
682 ui = va_arg(ap, u_int);
683 s = __uitoa(nbuf, ui, 16);
684 } else {
685 ul = va_arg(ap, u_long);
686 s = __ultoa(nbuf, ul, 16);
687 }
688 if (sflag)
689 ret += __puts("0x", putc, arg);
690 ret += __puts(s, putc, arg);
691 break;
692 case '0': case '1': case '2': case '3': case '4':
693 case '5': case '6': case '7': case '8': case '9':
694 pad = pad * 10 + c - '0';
695 goto reswitch;
696 default:
697 break;
698 }
699 }
700 return (ret);
701 }
702
703 static int
__sputc(char c,void * arg)704 __sputc(char c, void *arg)
705 {
706 struct sp_data *sp;
707
708 sp = arg;
709 if (sp->sp_len < sp->sp_size)
710 sp->sp_buf[sp->sp_len++] = c;
711 sp->sp_buf[sp->sp_len] = '\0';
712 return (1);
713 }
714
715 static int
__puts(const char * s,putc_func_t * putc,void * arg)716 __puts(const char *s, putc_func_t *putc, void *arg)
717 {
718 const char *p;
719 int ret;
720
721 ret = 0;
722 for (p = s; *p != '\0'; p++)
723 ret += putc(*p, arg);
724 return (ret);
725 }
726
727 static char *
__uitoa(char * buf,u_int ui,int base)728 __uitoa(char *buf, u_int ui, int base)
729 {
730 char *p;
731
732 p = buf;
733 *p = '\0';
734 do
735 *--p = digits[ui % base];
736 while ((ui /= base) != 0);
737 return (p);
738 }
739
740 static char *
__ultoa(char * buf,u_long ul,int base)741 __ultoa(char *buf, u_long ul, int base)
742 {
743 char *p;
744
745 p = buf;
746 *p = '\0';
747 do
748 *--p = digits[ul % base];
749 while ((ul /= base) != 0);
750 return (p);
751 }
752