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