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: releng/10.2/sys/boot/powerpc/boot1.chrp/boot1.c 243254 2012-11-19 01:15:32Z trasz $"); 20 21#include <sys/param.h> 22#include <sys/dirent.h> 23#include <machine/elf.h> 24#include <machine/stdarg.h> 25 26#define _PATH_LOADER "/boot/loader" 27#define _PATH_KERNEL "/boot/kernel/kernel" 28 29#define BSIZEMAX 16384 30 31typedef int putc_func_t(char c, void *arg); 32typedef int32_t ofwh_t; 33 34struct sp_data { 35 char *sp_buf; 36 u_int sp_len; 37 u_int sp_size; 38}; 39 40static const char digits[] = "0123456789abcdef"; 41 42static char bootpath[128]; 43static char bootargs[128]; 44 45static ofwh_t bootdev; 46 47static struct fs fs; 48static char blkbuf[BSIZEMAX]; 49static unsigned int fsblks; 50 51static uint32_t fs_off; 52 53int main(int ac, char **av); 54 55static void exit(int) __dead2; 56static void load(const char *); 57static int dskread(void *, u_int64_t, int); 58 59static void usage(void); 60 61static void bcopy(const void *src, void *dst, size_t len); 62static void bzero(void *b, size_t len); 63 64static int domount(const char *device, int quiet); 65 66static void panic(const char *fmt, ...) __dead2; 67static int printf(const char *fmt, ...); 68static int putchar(char c, void *arg); 69static int vprintf(const char *fmt, va_list ap); 70static int vsnprintf(char *str, size_t sz, const char *fmt, va_list ap); 71 72static int __printf(const char *fmt, putc_func_t *putc, void *arg, va_list ap); 73static int __putc(char c, void *arg); 74static int __puts(const char *s, putc_func_t *putc, void *arg); 75static int __sputc(char c, void *arg); 76static char *__uitoa(char *buf, u_int val, int base); 77static char *__ultoa(char *buf, u_long val, int base); 78 79void __syncicache(void *, int); 80 81/* 82 * Open Firmware interface functions 83 */ 84typedef u_int32_t ofwcell_t; 85typedef u_int32_t u_ofwh_t; 86typedef int (*ofwfp_t)(void *); 87ofwfp_t ofw; /* the prom Open Firmware entry */ 88ofwh_t chosenh; 89 90void ofw_init(void *, int, int (*)(void *), char *, int); 91static ofwh_t ofw_finddevice(const char *); 92static ofwh_t ofw_open(const char *); 93static int ofw_close(ofwh_t); 94static int ofw_getprop(ofwh_t, const char *, void *, size_t); 95static int ofw_setprop(ofwh_t, const char *, void *, size_t); 96static int ofw_read(ofwh_t, void *, size_t); 97static int ofw_write(ofwh_t, const void *, size_t); 98static int ofw_claim(void *virt, size_t len, u_int align); 99static int ofw_seek(ofwh_t, u_int64_t); 100static void ofw_exit(void) __dead2; 101 102ofwh_t bootdevh; 103ofwh_t stdinh, stdouth; 104 105__asm(" \n\ 106 .data \n\ 107 .align 4 \n\ 108stack: \n\ 109 .space 16384 \n\ 110 \n\ 111 .text \n\ 112 .globl _start \n\ 113_start: \n\ 114 lis %r1,stack@ha \n\ 115 addi %r1,%r1,stack@l \n\ 116 addi %r1,%r1,8192 \n\ 117 \n\ 118 b ofw_init \n\ 119"); 120 121void 122ofw_init(void *vpd, int res, int (*openfirm)(void *), char *arg, int argl) 123{ 124 char *av[16]; 125 char *p; 126 int ac; 127 128 ofw = openfirm; 129 130 chosenh = ofw_finddevice("/chosen"); 131 ofw_getprop(chosenh, "stdin", &stdinh, sizeof(stdinh)); 132 ofw_getprop(chosenh, "stdout", &stdouth, sizeof(stdouth)); 133 ofw_getprop(chosenh, "bootargs", bootargs, sizeof(bootargs)); 134 ofw_getprop(chosenh, "bootpath", bootpath, sizeof(bootpath)); 135 136 bootargs[sizeof(bootargs) - 1] = '\0'; 137 bootpath[sizeof(bootpath) - 1] = '\0'; 138 139 p = bootpath; 140 while (*p != '\0') { 141 if (*p == ':') { 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 165static ofwh_t 166ofw_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 183static int 184ofw_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 205static int 206ofw_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 227static ofwh_t 228ofw_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 245static int 246ofw_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 262static int 263ofw_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 284static int 285ofw_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 304static int 305ofw_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 324static int 325ofw_seek(ofwh_t devh, u_int64_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 344static void 345ofw_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 357static void 358bcopy(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 367static void 368memcpy(void *dst, const void *src, size_t len) 369{ 370 bcopy(src, dst, len); 371} 372 373static void 374bzero(void *b, size_t len) 375{ 376 char *p = b; 377 378 while (len-- != 0) 379 *p++ = 0; 380} 381 382static int 383strcmp(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 392int 393main(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 for (i = 0; i < 16; i++) { 425 if (i < 10) { 426 bootpath_full[len] = i + '0'; 427 bootpath_full[len+1] = '\0'; 428 } else { 429 bootpath_full[len] = '1'; 430 bootpath_full[len+1] = i - 10 + '0'; 431 bootpath_full[len+2] = '\0'; 432 } 433 434 if (domount(bootpath_full,1) >= 0) 435 break; 436 437 if (bootdev > 0) 438 ofw_close(bootdev); 439 } 440 441 if (i >= 16) 442 panic("domount"); 443 } else { 444 if (domount(bootpath_full,0) == -1) 445 panic("domount"); 446 } 447 448 printf(" Boot volume: %s\n",bootpath_full); 449 ofw_setprop(chosenh, "bootargs", bootpath_full, len+2); 450 load(path); 451 return (1); 452} 453 454static void 455usage(void) 456{ 457 458 printf("usage: boot device [/path/to/loader]\n"); 459 exit(1); 460} 461 462static void 463exit(int code) 464{ 465 466 ofw_exit(); 467} 468 469static struct dmadat __dmadat; 470 471static int 472domount(const char *device, int quiet) 473{ 474 475 dmadat = &__dmadat; 476 if ((bootdev = ofw_open(device)) == -1) { 477 printf("domount: can't open device\n"); 478 return (-1); 479 } 480 if (fsread(0, NULL, 0)) { 481 if (!quiet) 482 printf("domount: can't read superblock\n"); 483 return (-1); 484 } 485 return (0); 486} 487 488static void 489load(const char *fname) 490{ 491 Elf32_Ehdr eh; 492 Elf32_Phdr ph; 493 caddr_t p; 494 ufs_ino_t ino; 495 int i; 496 497 if ((ino = lookup(fname)) == 0) { 498 printf("File %s not found\n", fname); 499 return; 500 } 501 if (fsread(ino, &eh, sizeof(eh)) != sizeof(eh)) { 502 printf("Can't read elf header\n"); 503 return; 504 } 505 if (!IS_ELF(eh)) { 506 printf("Not an ELF file\n"); 507 return; 508 } 509 for (i = 0; i < eh.e_phnum; i++) { 510 fs_off = eh.e_phoff + i * eh.e_phentsize; 511 if (fsread(ino, &ph, sizeof(ph)) != sizeof(ph)) { 512 printf("Can't read program header %d\n", i); 513 return; 514 } 515 if (ph.p_type != PT_LOAD) 516 continue; 517 fs_off = ph.p_offset; 518 p = (caddr_t)ph.p_vaddr; 519 ofw_claim(p,(ph.p_filesz > ph.p_memsz) ? 520 ph.p_filesz : ph.p_memsz,0); 521 if (fsread(ino, p, ph.p_filesz) != ph.p_filesz) { 522 printf("Can't read content of section %d\n", i); 523 return; 524 } 525 if (ph.p_filesz != ph.p_memsz) 526 bzero(p + ph.p_filesz, ph.p_memsz - ph.p_filesz); 527 __syncicache(p, ph.p_memsz); 528 } 529 ofw_close(bootdev); 530 (*(void (*)(void *, int, ofwfp_t, char *, int))eh.e_entry)(NULL, 0, 531 ofw,NULL,0); 532} 533 534static int 535dskread(void *buf, u_int64_t lba, int nblk) 536{ 537 /* 538 * The Open Firmware should open the correct partition for us. 539 * That means, if we read from offset zero on an open instance handle, 540 * we should read from offset zero of that partition. 541 */ 542 ofw_seek(bootdev, lba * DEV_BSIZE); 543 ofw_read(bootdev, buf, nblk * DEV_BSIZE); 544 return (0); 545} 546 547static void 548panic(const char *fmt, ...) 549{ 550 char buf[128]; 551 va_list ap; 552 553 va_start(ap, fmt); 554 vsnprintf(buf, sizeof buf, fmt, ap); 555 printf("panic: %s\n", buf); 556 va_end(ap); 557 558 exit(1); 559} 560 561static int 562printf(const char *fmt, ...) 563{ 564 va_list ap; 565 int ret; 566 567 /* Don't annoy the user as we probe for partitions */ 568 if (strcmp(fmt,"Not ufs\n") == 0) 569 return 0; 570 571 va_start(ap, fmt); 572 ret = vprintf(fmt, ap); 573 va_end(ap); 574 return (ret); 575} 576 577static int 578putchar(char c, void *arg) 579{ 580 char buf; 581 582 if (c == '\n') { 583 buf = '\r'; 584 ofw_write(stdouth, &buf, 1); 585 } 586 buf = c; 587 ofw_write(stdouth, &buf, 1); 588 return (1); 589} 590 591static int 592vprintf(const char *fmt, va_list ap) 593{ 594 int ret; 595 596 ret = __printf(fmt, putchar, 0, ap); 597 return (ret); 598} 599 600static int 601vsnprintf(char *str, size_t sz, const char *fmt, va_list ap) 602{ 603 struct sp_data sp; 604 int ret; 605 606 sp.sp_buf = str; 607 sp.sp_len = 0; 608 sp.sp_size = sz; 609 ret = __printf(fmt, __sputc, &sp, ap); 610 return (ret); 611} 612 613static int 614__printf(const char *fmt, putc_func_t *putc, void *arg, va_list ap) 615{ 616 char buf[(sizeof(long) * 8) + 1]; 617 char *nbuf; 618 u_long ul; 619 u_int ui; 620 int lflag; 621 int sflag; 622 char *s; 623 int pad; 624 int ret; 625 int c; 626 627 nbuf = &buf[sizeof buf - 1]; 628 ret = 0; 629 while ((c = *fmt++) != 0) { 630 if (c != '%') { 631 ret += putc(c, arg); 632 continue; 633 } 634 lflag = 0; 635 sflag = 0; 636 pad = 0; 637reswitch: c = *fmt++; 638 switch (c) { 639 case '#': 640 sflag = 1; 641 goto reswitch; 642 case '%': 643 ret += putc('%', arg); 644 break; 645 case 'c': 646 c = va_arg(ap, int); 647 ret += putc(c, arg); 648 break; 649 case 'd': 650 if (lflag == 0) { 651 ui = (u_int)va_arg(ap, int); 652 if (ui < (int)ui) { 653 ui = -ui; 654 ret += putc('-', arg); 655 } 656 s = __uitoa(nbuf, ui, 10); 657 } else { 658 ul = (u_long)va_arg(ap, long); 659 if (ul < (long)ul) { 660 ul = -ul; 661 ret += putc('-', arg); 662 } 663 s = __ultoa(nbuf, ul, 10); 664 } 665 ret += __puts(s, putc, arg); 666 break; 667 case 'l': 668 lflag = 1; 669 goto reswitch; 670 case 'o': 671 if (lflag == 0) { 672 ui = (u_int)va_arg(ap, u_int); 673 s = __uitoa(nbuf, ui, 8); 674 } else { 675 ul = (u_long)va_arg(ap, u_long); 676 s = __ultoa(nbuf, ul, 8); 677 } 678 ret += __puts(s, putc, arg); 679 break; 680 case 'p': 681 ul = (u_long)va_arg(ap, void *); 682 s = __ultoa(nbuf, ul, 16); 683 ret += __puts("0x", putc, arg); 684 ret += __puts(s, putc, arg); 685 break; 686 case 's': 687 s = va_arg(ap, char *); 688 ret += __puts(s, putc, arg); 689 break; 690 case 'u': 691 if (lflag == 0) { 692 ui = va_arg(ap, u_int); 693 s = __uitoa(nbuf, ui, 10); 694 } else { 695 ul = va_arg(ap, u_long); 696 s = __ultoa(nbuf, ul, 10); 697 } 698 ret += __puts(s, putc, arg); 699 break; 700 case 'x': 701 if (lflag == 0) { 702 ui = va_arg(ap, u_int); 703 s = __uitoa(nbuf, ui, 16); 704 } else { 705 ul = va_arg(ap, u_long); 706 s = __ultoa(nbuf, ul, 16); 707 } 708 if (sflag) 709 ret += __puts("0x", putc, arg); 710 ret += __puts(s, putc, arg); 711 break; 712 case '0': case '1': case '2': case '3': case '4': 713 case '5': case '6': case '7': case '8': case '9': 714 pad = pad * 10 + c - '0'; 715 goto reswitch; 716 default: 717 break; 718 } 719 } 720 return (ret); 721} 722 723static int 724__sputc(char c, void *arg) 725{ 726 struct sp_data *sp; 727 728 sp = arg; 729 if (sp->sp_len < sp->sp_size) 730 sp->sp_buf[sp->sp_len++] = c; 731 sp->sp_buf[sp->sp_len] = '\0'; 732 return (1); 733} 734 735static int 736__puts(const char *s, putc_func_t *putc, void *arg) 737{ 738 const char *p; 739 int ret; 740 741 ret = 0; 742 for (p = s; *p != '\0'; p++) 743 ret += putc(*p, arg); 744 return (ret); 745} 746 747static char * 748__uitoa(char *buf, u_int ui, int base) 749{ 750 char *p; 751 752 p = buf; 753 *p = '\0'; 754 do 755 *--p = digits[ui % base]; 756 while ((ui /= base) != 0); 757 return (p); 758} 759 760static char * 761__ultoa(char *buf, u_long ul, int base) 762{ 763 char *p; 764 765 p = buf; 766 *p = '\0'; 767 do 768 *--p = digits[ul % base]; 769 while ((ul /= base) != 0); 770 return (p); 771} 772