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