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