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