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