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) __dead2; 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 459 memcpy(void *dst, const void *src, size_t len) 460 { 461 bcopy(src, dst, len); 462 } 463 464 static void 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 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 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 555 usage(void) 556 { 557 558 printf("usage: boot device [/path/to/loader]\n"); 559 exit(1); 560 } 561 562 static void 563 exit(int code) 564 { 565 566 ofw_exit(); 567 } 568 569 static struct dmadat __dmadat; 570 571 static int 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 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 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 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 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 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 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 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 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 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 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 * 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 * 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