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