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 #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 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 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 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 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 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 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 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 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 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 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 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 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 369 memcpy(void *dst, const void *src, size_t len) 370 { 371 bcopy(src, dst, len); 372 } 373 374 static void 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 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 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 465 usage(void) 466 { 467 468 printf("usage: boot device [/path/to/loader]\n"); 469 exit(1); 470 } 471 472 static void 473 exit(int code) 474 { 475 476 ofw_exit(); 477 } 478 479 static struct dmadat __dmadat; 480 481 static int 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 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 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 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 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 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 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 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 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 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 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 * 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 * 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