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