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