boot1.c revision 91295
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 91295 2002-02-26 10:05:20Z robert $"); 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#include <a.out.h> 34 35#define RBX_ASKNAME 0x0 /* -a */ 36#define RBX_SINGLE 0x1 /* -s */ 37#define RBX_DFLTROOT 0x5 /* -r */ 38#define RBX_KDB 0x6 /* -d */ 39#define RBX_CONFIG 0xa /* -c */ 40#define RBX_VERBOSE 0xb /* -v */ 41#define RBX_CDROM 0xd /* -C */ 42#define RBX_GDB 0xf /* -g */ 43 44#define RBX_MASK 0x2000ffff 45 46#define PATH_CONFIG "/boot.config" 47#define PATH_LOADER "/boot/loader" 48#define PATH_KERNEL "/kernel" 49 50#define ARGS 0x900 51#define NOPT 11 52#define BSIZEMAX 8192 53#define NDEV 5 54 55#define TYPE_AD 0 56#define TYPE_WD 1 57#define TYPE_WFD 2 58#define TYPE_FD 3 59#define TYPE_DA 4 60 61/* 62 * This structure will be refined along with the addition of a bootpath 63 * parsing routine when it is necessary to cope with bootpaths that are 64 * not in the exact <devpath>@<controller>,<disk>:<partition> format and 65 * for which we need to evaluate the disklabel ourselves. 66 */ 67struct disk { 68 int meta; 69}; 70struct disk dsk; 71 72extern uint32_t _end; 73 74static const char optstr[NOPT] = "aCcgrsv"; 75static const unsigned char flags[NOPT] = { 76 RBX_ASKNAME, 77 RBX_CDROM, 78 RBX_CONFIG, 79 RBX_GDB, 80 RBX_DFLTROOT, 81 RBX_SINGLE, 82 RBX_VERBOSE 83}; 84 85static char cmd[512]; /* command to parse */ 86static char bname[1024]; /* name of the binary to load */ 87static uint32_t opts; 88static int ls; 89static uint32_t fs_off; 90 91int main(void); 92void exit(int); 93static void load(const char *); 94static int parse(char *); 95static ino_t lookup(const char *); 96static int xfsread(ino_t, void *, size_t); 97static ssize_t fsread(ino_t, void *, size_t); 98static int dskread(void *, u_int64_t, int); 99static int printf(const char *, ...); 100static int putchar(int); 101static int keyhit(unsigned int); 102static int getc(void); 103 104static void *memcpy(void *, const void *, size_t); 105static void *memset(void *, int, size_t); 106static void *malloc(size_t); 107 108/* 109 * Open Firmware interface functions 110 */ 111typedef u_int64_t ofwcell_t; 112typedef int32_t ofwh_t; 113typedef u_int32_t u_ofwh_t; 114typedef int (*ofwfp_t)(ofwcell_t []); 115ofwfp_t ofw; /* the prom Open Firmware entry */ 116 117void ofw_init(int, int, int, int, ofwfp_t); 118ofwh_t ofw_finddevice(const char *); 119ofwh_t ofw_open(const char *); 120int ofw_getprop(ofwh_t, const char *, void *, size_t); 121int ofw_read(ofwh_t, void *, size_t); 122int ofw_write(ofwh_t, const void *, size_t); 123int ofw_seek(ofwh_t, u_int64_t); 124 125ofwh_t bootdevh; 126ofwh_t stdinh, stdouth; 127char bootpath[64]; 128 129/* 130 * This has to stay here, as the PROM seems to ignore the 131 * entry point specified in the a.out header. (or elftoaout is broken) 132 */ 133 134void 135ofw_init(int d, int d1, int d2, int d3, ofwfp_t ofwaddr) 136{ 137 ofwh_t chosenh; 138 139 ofw = ofwaddr; 140 141 chosenh = ofw_finddevice("/chosen"); 142 ofw_getprop(chosenh, "stdin", &stdinh, sizeof(stdinh)); 143 ofw_getprop(chosenh, "stdout", &stdouth, sizeof(stdouth)); 144 ofw_getprop(chosenh, "bootpath", bootpath, sizeof(bootpath)); 145 146 if ((bootdevh = ofw_open(bootpath)) == -1) { 147 printf("Could not open boot device.\n"); 148 } 149 150 main(); 151 d = d1 = d2 = d3; /* make GCC happy */ 152} 153 154ofwh_t 155ofw_finddevice(const char *name) 156{ 157 ofwcell_t args[] = { 158 (ofwcell_t)"finddevice", 159 1, 160 1, 161 (ofwcell_t)name, 162 0 163 }; 164 165 if ((*ofw)(args)) { 166 printf("ofw_finddevice: name=\"%s\"\n", name); 167 return (1); 168 } 169 return (args[4]); 170} 171 172int 173ofw_getprop(ofwh_t ofwh, const char *name, void *buf, size_t len) 174{ 175 ofwcell_t args[] = { 176 (ofwcell_t)"getprop", 177 4, 178 1, 179 (u_ofwh_t)ofwh, 180 (ofwcell_t)name, 181 (ofwcell_t)buf, 182 len, 183 0 184 }; 185 186 if ((*ofw)(args)) { 187 printf("ofw_getprop: ofwh=0x%x buf=%p len=%u\n", 188 ofwh, buf, len); 189 return (1); 190 } 191 return (0); 192} 193 194ofwh_t 195ofw_open(const char *path) 196{ 197 ofwcell_t args[] = { 198 (ofwcell_t)"open", 199 1, 200 1, 201 (ofwcell_t)path, 202 0 203 }; 204 205 if ((*ofw)(args)) { 206 printf("ofw_open: path=\"%s\"\n", path); 207 return (-1); 208 } 209 return (args[4]); 210} 211 212int 213ofw_close(ofwh_t devh) 214{ 215 ofwcell_t args[] = { 216 (ofwcell_t)"close", 217 1, 218 0, 219 (u_ofwh_t)devh 220 }; 221 222 if ((*ofw)(args)) { 223 printf("ofw_close: devh=0x%x\n", devh); 224 return (1); 225 } 226 return (0); 227} 228 229int 230ofw_read(ofwh_t devh, void *buf, size_t len) 231{ 232 ofwcell_t args[] = { 233 (ofwcell_t)"read", 234 4, 235 1, 236 (u_ofwh_t)devh, 237 (ofwcell_t)buf, 238 len, 239 0 240 }; 241 242 if ((*ofw)(args)) { 243 printf("ofw_read: devh=0x%x buf=%p len=%u\n", devh, buf, len); 244 return (1); 245 } 246 return (0); 247} 248 249int 250ofw_write(ofwh_t devh, const void *buf, size_t len) 251{ 252 ofwcell_t args[] = { 253 (ofwcell_t)"write", 254 3, 255 1, 256 (u_ofwh_t)devh, 257 (ofwcell_t)buf, 258 len, 259 0 260 }; 261 262 if ((*ofw)(args)) { 263 printf("ofw_write: devh=0x%x buf=%p len=%u\n", devh, buf, len); 264 return (1); 265 } 266 return (0); 267} 268 269int 270ofw_seek(ofwh_t devh, u_int64_t off) 271{ 272 ofwcell_t args[] = { 273 (ofwcell_t)"seek", 274 4, 275 1, 276 (u_ofwh_t)devh, 277 off >> 32, 278 off & ((1UL << 32) - 1), 279 0 280 }; 281 282 if ((*ofw)(args)) { 283 printf("ofw_seek: devh=0x%x off=0x%lx\n", devh, off); 284 return (1); 285 } 286 return (0); 287} 288 289static void 290readfile(const char *fname, void *buf, size_t size) 291{ 292 ino_t ino; 293 294 if ((ino = lookup(fname))) 295 fsread(ino, buf, size); 296} 297 298static int 299strcmp(const char *s1, const char *s2) 300{ 301 for (; *s1 == *s2 && *s1; s1++, s2++) 302 ; 303 return ((u_char)*s1 - (u_char)*s2); 304} 305 306static void * 307memset(void *dst, int val, size_t len) 308{ 309 void *ret; 310 311 ret = dst; 312 while (len) { 313 *((char *)dst)++ = val; 314 len--; 315 } 316 return (ret); 317} 318 319static int 320fsfind(const char *name, ino_t * ino) 321{ 322 char buf[DEV_BSIZE]; 323 struct dirent *d; 324 char *s; 325 ssize_t n; 326 327 fs_off = 0; 328 while ((n = fsread(*ino, buf, DEV_BSIZE)) > 0) { 329 for (s = buf; s < buf + DEV_BSIZE;) { 330 d = (void *)s; 331 if (ls) 332 printf("%s ", d->d_name); 333 else if (!strcmp(name, d->d_name)) { 334 *ino = d->d_fileno; 335 return (d->d_type); 336 } 337 s += d->d_reclen; 338 } 339 } 340 if (n != -1 && ls) 341 putchar('\n'); 342 return (0); 343} 344 345static int 346getchar(void) 347{ 348 int c; 349 350 c = getc(); 351 if (c == '\r') 352 c = '\n'; 353 return (c); 354} 355 356static void 357getstr(char *str, int size) 358{ 359 char *s; 360 int c; 361 362 s = str; 363 do { 364 switch (c = getchar()) { 365 case 0: 366 break; 367 case '\b': 368 case '\177': 369 if (s > str) { 370 s--; 371 putchar('\b'); 372 putchar(' '); 373 } else 374 c = 0; 375 break; 376 case '\n': 377 *s = 0; 378 break; 379 default: 380 if (s - str < size - 1) 381 *s++ = c; 382 } 383 if (c) 384 putchar(c); 385 } while (c != '\n'); 386} 387 388static void 389putc(int c) 390{ 391 char d; 392 393 d = c; 394 ofw_write(stdouth, &d, 1); 395} 396 397int main(void) 398{ 399 readfile(PATH_CONFIG, cmd, sizeof(cmd)); 400 if (cmd[0] != '\0') { 401 printf("%s: %s", PATH_CONFIG, cmd); 402 if (parse(cmd)) 403 cmd[0] = '\0'; 404 } 405 if (bname[0] == '\0') 406 memcpy(bname, PATH_LOADER, sizeof(PATH_LOADER)); 407 408 printf(" \n>> FreeBSD/sparc64 boot block\n" 409 " Boot path: %s\n" 410 " Boot loader: %s\n", bootpath, PATH_LOADER); 411 load(bname); 412 return (1); 413} 414 415static void 416load(const char *fname) 417{ 418 Elf64_Ehdr eh; 419 Elf64_Phdr ep[2]; 420 Elf64_Shdr es[2]; 421 caddr_t p; 422 ino_t ino; 423 vm_offset_t entry; 424 int i, j; 425 426 if ((ino = lookup(fname)) == 0) { 427 if (!ls) 428 printf("File %s not found\n", fname); 429 return; 430 } 431 if (xfsread(ino, &eh, sizeof(eh))) 432 return; 433 if (!IS_ELF(eh)) { 434 printf("Not an ELF file\n"); 435 return; 436 } 437 fs_off = eh.e_phoff; 438 for (j = i = 0; i < eh.e_phnum && j < 2; i++) { 439 if (xfsread(ino, ep + j, sizeof(ep[0]))) 440 return; 441 if (ep[j].p_type == PT_LOAD) 442 j++; 443 } 444 for (i = 0; i < j; i++) { 445 p = (caddr_t)ep[i].p_vaddr; 446 fs_off = ep[i].p_offset; 447 if (xfsread(ino, p, ep[i].p_filesz)) 448 return; 449 /* 450 * Assume the second program header table entry 451 * to contain data and bss. Clear out the .bss section. 452 */ 453 if (i == 1) { 454 memset(p + ep[i].p_filesz, 0, 455 ep[i].p_memsz - ep[i].p_filesz); 456 } 457 } 458 p += roundup2(ep[1].p_memsz, PAGE_SIZE); 459 if (eh.e_shnum == eh.e_shstrndx + 3) { 460 fs_off = eh.e_shoff + sizeof(es[0]) * (eh.e_shstrndx + 1); 461 if (xfsread(ino, &es, sizeof(es))) 462 return; 463 for (i = 0; i < 2; i++) { 464 memcpy(p, &es[i].sh_size, sizeof(es[i].sh_size)); 465 p += sizeof(es[i].sh_size); 466 fs_off = es[i].sh_offset; 467 if (xfsread(ino, p, es[i].sh_size)) 468 return; 469 p += es[i].sh_size; 470 } 471 } 472 entry = eh.e_entry; 473 ofw_close(bootdevh); 474 (*(void (*)(int, int, int, int, ofwfp_t))entry)(0, 0, 0, 0, ofw); 475} 476 477static int 478parse(char *arg) 479{ 480 char *p; 481 int c, i; 482 483 while ((c = *arg++)) { 484 if (c == ' ' || c == '\t' || c == '\n') 485 continue; 486 for (p = arg; *p && *p != '\n' && *p != ' ' && *p != '\t'; p++) 487 ; 488 if (*p) 489 *p++ = 0; 490 if (c == '-') { 491 while ((c = *arg++)) { 492 for (i = 0; c != optstr[i]; i++) 493 if (i == NOPT - 1) 494 return (-1); 495 opts ^= 1 << flags[i]; 496 } 497 } 498 arg = p; 499 } 500 return (0); 501} 502 503static ino_t 504lookup(const char *path) 505{ 506 char name[MAXNAMLEN + 1]; 507 const char *s; 508 ino_t ino; 509 ssize_t n; 510 int dt; 511 512 ino = ROOTINO; 513 dt = DT_DIR; 514 for (;;) { 515 if (*path == '/') 516 path++; 517 if (!*path) 518 break; 519 for (s = path; *s && *s != '/'; s++) 520 ; 521 if ((n = s - path) > MAXNAMLEN) 522 return (0); 523 ls = *path == '?' && n == 1 && !*s; 524 memcpy(name, path, n); 525 name[n] = 0; 526 if ((dt = fsfind(name, &ino)) <= 0) 527 break; 528 path = s; 529 } 530 return (dt == DT_REG ? ino : 0); 531} 532 533static int 534xfsread(ino_t inode, void *buf, size_t nbyte) 535{ 536 if (fsread(inode, buf, nbyte) != (ssize_t)nbyte) { 537 printf("Invalid %s\n", "format"); 538 return (-1); 539 } 540 return (0); 541} 542 543static ssize_t 544fsread(ino_t inode, void *buf, size_t nbyte) 545{ 546 static struct fs fs; 547 static struct dinode din; 548 static char *blkbuf; 549 static ufs_daddr_t *indbuf; 550 static ino_t inomap; 551 static ufs_daddr_t blkmap, indmap; 552 static unsigned int fsblks; 553 char *s; 554 ufs_daddr_t lbn, addr; 555 size_t n, nb, off; 556 557 if (!dsk.meta) { 558 if (!blkbuf) 559 blkbuf = malloc(BSIZEMAX); 560 inomap = 0; 561 if (dskread(blkbuf, SBOFF / DEV_BSIZE, SBSIZE / DEV_BSIZE)) 562 return (-1); 563 memcpy(&fs, blkbuf, sizeof(fs)); 564 if (fs.fs_magic != FS_MAGIC) { 565 printf("Not ufs\n"); 566 return (-1); 567 } 568 fsblks = fs.fs_bsize >> DEV_BSHIFT; 569 dsk.meta++; 570 } 571 if (!inode) 572 return (0); 573 if (inomap != inode) { 574 if (dskread(blkbuf, fsbtodb(&fs, ino_to_fsba(&fs, inode)), 575 fsblks)) 576 return (-1); 577 din = ((struct dinode *)blkbuf)[inode % INOPB(&fs)]; 578 inomap = inode; 579 fs_off = 0; 580 blkmap = indmap = 0; 581 } 582 s = buf; 583 if (nbyte > (n = din.di_size - fs_off)) 584 nbyte = n; 585 nb = nbyte; 586 while (nb) { 587 lbn = lblkno(&fs, fs_off); 588 if (lbn < NDADDR) 589 addr = din.di_db[lbn]; 590 else { 591 if (indmap != din.di_ib[0]) { 592 if (!indbuf) 593 indbuf = malloc(BSIZEMAX); 594 if (dskread(indbuf, fsbtodb(&fs, din.di_ib[0]), 595 fsblks)) 596 return (-1); 597 indmap = din.di_ib[0]; 598 } 599 addr = indbuf[(lbn - NDADDR) % NINDIR(&fs)]; 600 } 601 n = dblksize(&fs, &din, lbn); 602 if (blkmap != addr) { 603 if (dskread(blkbuf, fsbtodb(&fs, addr), 604 n >> DEV_BSHIFT)) { 605 return (-1); 606 } 607 blkmap = addr; 608 } 609 off = blkoff(&fs, fs_off); 610 n -= off; 611 if (n > nb) 612 n = nb; 613 memcpy(s, blkbuf + off, n); 614 s += n; 615 fs_off += n; 616 nb -= n; 617 } 618 return (nbyte); 619} 620 621static int 622dskread(void *buf, u_int64_t lba, int nblk) 623{ 624 /* 625 * The OpenFirmware should open the correct partition for us. 626 * That means, if we read from offset zero on an open instance handle, 627 * we should read from offset zero of that partition. 628 */ 629 ofw_seek(bootdevh, lba * DEV_BSIZE); 630 ofw_read(bootdevh, buf, nblk * DEV_BSIZE); 631 return (0); 632} 633 634static int 635printf(const char *fmt,...) 636{ 637 static const char digits[16] = "0123456789abcdef"; 638 va_list ap; 639 char buf[10]; 640 char *s; 641 unsigned long int r, u; 642 int c; 643 644 va_start(ap, fmt); 645 while ((c = *fmt++)) { 646 if (c == '%') { 647 c = *fmt++; 648 switch (c) { 649 case 'c': 650 putchar(va_arg(ap, int)); 651 continue; 652 case 's': 653 for (s = va_arg(ap, char *); *s; s++) 654 putchar(*s); 655 continue; 656 case 'p': 657 if (c == 'p') { 658 putchar('0'); 659 putchar('x'); 660 } 661 case 'u': 662 case 'x': 663 r = c == 'u' ? 10U : 16U; 664 u = c == 'p' ? va_arg(ap, unsigned long) : 665 va_arg(ap, unsigned int); 666 s = buf; 667 do 668 *s++ = digits[u % r]; 669 while (u /= r); 670 while (--s >= buf) 671 putchar(*s); 672 continue; 673 } 674 } 675 putchar(c); 676 } 677 va_end(ap); 678 return (0); 679} 680 681static int 682putchar(int c) 683{ 684 if (c == '\n') 685 putc('\r'); 686 putc(c); 687 return (c); 688} 689 690static void * 691memcpy(void *dst, const void *src, size_t size) 692{ 693 const char *s; 694 char *d; 695 696 for (d = dst, s = src; size; size--) 697 *d++ = *s++; 698 return (dst); 699} 700 701static void * 702malloc(size_t size) 703{ 704 static vm_offset_t next = 0x10000; 705 void *p; 706 707 if (size & 0xf) 708 size = (size + 0xf) & ~0xf; 709 p = (void *)next; 710 next += size; 711 return (p); 712} 713 714static int 715keyhit(unsigned int ticks) 716{ 717 /* XXX */ 718 return (0); 719 ticks = ticks; /* make GCC happy */ 720} 721 722static int 723getc(void) 724{ 725 char c; 726 ofw_read(stdinh, &c, 1); 727 return (c); 728} 729