boot1.c revision 234898
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/sparc64/boot1/boot1.c 234898 2012-05-01 17:16:01Z marius $"); 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 mount(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 (mount(bootpath) == -1) 351 panic("mount"); 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 ino_t ino; 419 int i; 420 421 if (zbread((char *)&eh, 0, sizeof(eh)) != sizeof(eh)) { 422 printf("Can't read elf header\n"); 423 return; 424 } 425 if (!IS_ELF(eh)) { 426 printf("Not an ELF file\n"); 427 return; 428 } 429 for (i = 0; i < eh.e_phnum; i++) { 430 fs_off = eh.e_phoff + i * eh.e_phentsize; 431 if (zbread((char *)&ph, fs_off, sizeof(ph)) != sizeof(ph)) { 432 printf("Can't read program header %d\n", i); 433 return; 434 } 435 if (ph.p_type != PT_LOAD) 436 continue; 437 fs_off = ph.p_offset; 438 p = (caddr_t)ph.p_vaddr; 439 if (zbread(p, fs_off, ph.p_filesz) != ph.p_filesz) { 440 printf("Can't read content of section %d\n", i); 441 return; 442 } 443 if (ph.p_filesz != ph.p_memsz) 444 bzero(p + ph.p_filesz, ph.p_memsz - ph.p_filesz); 445 } 446 ofw_close(bootdev); 447 (*(void (*)(int, int, int, int, ofwfp_t))eh.e_entry)(0, 0, 0, 0, ofw); 448} 449 450#else 451 452#include "ufsread.c" 453 454static struct dmadat __dmadat; 455 456static void 457load(const char *fname) 458{ 459 Elf64_Ehdr eh; 460 Elf64_Phdr ph; 461 caddr_t p; 462 ino_t ino; 463 int i; 464 465 if ((ino = lookup(fname)) == 0) { 466 printf("File %s not found\n", fname); 467 return; 468 } 469 if (fsread(ino, &eh, sizeof(eh)) != sizeof(eh)) { 470 printf("Can't read elf header\n"); 471 return; 472 } 473 if (!IS_ELF(eh)) { 474 printf("Not an ELF file\n"); 475 return; 476 } 477 for (i = 0; i < eh.e_phnum; i++) { 478 fs_off = eh.e_phoff + i * eh.e_phentsize; 479 if (fsread(ino, &ph, sizeof(ph)) != sizeof(ph)) { 480 printf("Can't read program header %d\n", i); 481 return; 482 } 483 if (ph.p_type != PT_LOAD) 484 continue; 485 fs_off = ph.p_offset; 486 p = (caddr_t)ph.p_vaddr; 487 if (fsread(ino, p, ph.p_filesz) != ph.p_filesz) { 488 printf("Can't read content of section %d\n", i); 489 return; 490 } 491 if (ph.p_filesz != ph.p_memsz) 492 bzero(p + ph.p_filesz, ph.p_memsz - ph.p_filesz); 493 } 494 ofw_close(bootdev); 495 (*(void (*)(int, int, int, int, ofwfp_t))eh.e_entry)(0, 0, 0, 0, ofw); 496} 497 498#endif /* ZFSBOOT */ 499 500static int 501mount(const char *device) 502{ 503 504 if ((bootdev = ofw_open(device)) == -1) { 505 printf("mount: can't open device\n"); 506 return (-1); 507 } 508#ifndef ZFSBOOT 509 dmadat = &__dmadat; 510 if (fsread(0, NULL, 0)) { 511 printf("mount: can't read superblock\n"); 512 return (-1); 513 } 514#endif 515 return (0); 516} 517 518static int 519dskread(void *buf, u_int64_t lba, int nblk) 520{ 521 522 /* 523 * The Open Firmware should open the correct partition for us. 524 * That means, if we read from offset zero on an open instance handle, 525 * we should read from offset zero of that partition. 526 */ 527 ofw_seek(bootdev, lba * DEV_BSIZE); 528 ofw_read(bootdev, buf, nblk * DEV_BSIZE); 529 return (0); 530} 531 532static void 533panic(const char *fmt, ...) 534{ 535 char buf[128]; 536 va_list ap; 537 538 va_start(ap, fmt); 539 vsnprintf(buf, sizeof buf, fmt, ap); 540 printf("panic: %s\n", buf); 541 va_end(ap); 542 543 exit(1); 544} 545 546static int 547printf(const char *fmt, ...) 548{ 549 va_list ap; 550 int ret; 551 552 va_start(ap, fmt); 553 ret = vprintf(fmt, ap); 554 va_end(ap); 555 return (ret); 556} 557 558static int 559putchar(char c, void *arg) 560{ 561 char buf; 562 563 if (c == '\n') { 564 buf = '\r'; 565 ofw_write(stdouth, &buf, 1); 566 } 567 buf = c; 568 ofw_write(stdouth, &buf, 1); 569 return (1); 570} 571 572static int 573vprintf(const char *fmt, va_list ap) 574{ 575 int ret; 576 577 ret = __printf(fmt, putchar, 0, ap); 578 return (ret); 579} 580 581static int 582vsnprintf(char *str, size_t sz, const char *fmt, va_list ap) 583{ 584 struct sp_data sp; 585 int ret; 586 587 sp.sp_buf = str; 588 sp.sp_len = 0; 589 sp.sp_size = sz; 590 ret = __printf(fmt, __sputc, &sp, ap); 591 return (ret); 592} 593 594static int 595__printf(const char *fmt, putc_func_t *putc, void *arg, va_list ap) 596{ 597 char buf[(sizeof(long) * 8) + 1]; 598 char *nbuf; 599 u_long ul; 600 u_int ui; 601 int lflag; 602 int sflag; 603 char *s; 604 int pad; 605 int ret; 606 int c; 607 608 nbuf = &buf[sizeof buf - 1]; 609 ret = 0; 610 while ((c = *fmt++) != 0) { 611 if (c != '%') { 612 ret += putc(c, arg); 613 continue; 614 } 615 lflag = 0; 616 sflag = 0; 617 pad = 0; 618reswitch: c = *fmt++; 619 switch (c) { 620 case '#': 621 sflag = 1; 622 goto reswitch; 623 case '%': 624 ret += putc('%', arg); 625 break; 626 case 'c': 627 c = va_arg(ap, int); 628 ret += putc(c, arg); 629 break; 630 case 'd': 631 if (lflag == 0) { 632 ui = (u_int)va_arg(ap, int); 633 if (ui < (int)ui) { 634 ui = -ui; 635 ret += putc('-', arg); 636 } 637 s = __uitoa(nbuf, ui, 10); 638 } else { 639 ul = (u_long)va_arg(ap, long); 640 if (ul < (long)ul) { 641 ul = -ul; 642 ret += putc('-', arg); 643 } 644 s = __ultoa(nbuf, ul, 10); 645 } 646 ret += __puts(s, putc, arg); 647 break; 648 case 'l': 649 lflag = 1; 650 goto reswitch; 651 case 'o': 652 if (lflag == 0) { 653 ui = (u_int)va_arg(ap, u_int); 654 s = __uitoa(nbuf, ui, 8); 655 } else { 656 ul = (u_long)va_arg(ap, u_long); 657 s = __ultoa(nbuf, ul, 8); 658 } 659 ret += __puts(s, putc, arg); 660 break; 661 case 'p': 662 ul = (u_long)va_arg(ap, void *); 663 s = __ultoa(nbuf, ul, 16); 664 ret += __puts("0x", putc, arg); 665 ret += __puts(s, putc, arg); 666 break; 667 case 's': 668 s = va_arg(ap, char *); 669 ret += __puts(s, putc, arg); 670 break; 671 case 'u': 672 if (lflag == 0) { 673 ui = va_arg(ap, u_int); 674 s = __uitoa(nbuf, ui, 10); 675 } else { 676 ul = va_arg(ap, u_long); 677 s = __ultoa(nbuf, ul, 10); 678 } 679 ret += __puts(s, putc, arg); 680 break; 681 case 'x': 682 if (lflag == 0) { 683 ui = va_arg(ap, u_int); 684 s = __uitoa(nbuf, ui, 16); 685 } else { 686 ul = va_arg(ap, u_long); 687 s = __ultoa(nbuf, ul, 16); 688 } 689 if (sflag) 690 ret += __puts("0x", putc, arg); 691 ret += __puts(s, putc, arg); 692 break; 693 case '0': case '1': case '2': case '3': case '4': 694 case '5': case '6': case '7': case '8': case '9': 695 pad = pad * 10 + c - '0'; 696 goto reswitch; 697 default: 698 break; 699 } 700 } 701 return (ret); 702} 703 704static int 705__sputc(char c, void *arg) 706{ 707 struct sp_data *sp; 708 709 sp = arg; 710 if (sp->sp_len < sp->sp_size) 711 sp->sp_buf[sp->sp_len++] = c; 712 sp->sp_buf[sp->sp_len] = '\0'; 713 return (1); 714} 715 716static int 717__puts(const char *s, putc_func_t *putc, void *arg) 718{ 719 const char *p; 720 int ret; 721 722 ret = 0; 723 for (p = s; *p != '\0'; p++) 724 ret += putc(*p, arg); 725 return (ret); 726} 727 728static char * 729__uitoa(char *buf, u_int ui, int base) 730{ 731 char *p; 732 733 p = buf; 734 *p = '\0'; 735 do 736 *--p = digits[ui % base]; 737 while ((ui /= base) != 0); 738 return (p); 739} 740 741static char * 742__ultoa(char *buf, u_long ul, int base) 743{ 744 char *p; 745 746 p = buf; 747 *p = '\0'; 748 do 749 *--p = digits[ul % base]; 750 while ((ul /= base) != 0); 751 return (p); 752} 753