1 /* 2 * CDDL HEADER START 3 * 4 * The contents of this file are subject to the terms of the 5 * Common Development and Distribution License (the "License"). 6 * You may not use this file except in compliance with the License. 7 * 8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9 * or http://www.opensolaris.org/os/licensing. 10 * See the License for the specific language governing permissions 11 * and limitations under the License. 12 * 13 * When distributing Covered Code, include this CDDL HEADER in each 14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15 * If applicable, add the following below this CDDL HEADER, with the 16 * fields enclosed by brackets "[]" replaced with your own identifying 17 * information: Portions Copyright [yyyy] [name of copyright owner] 18 * 19 * CDDL HEADER END 20 */ 21 /* 22 * Copyright 2010 Sun Microsystems, Inc. All rights reserved. 23 * Use is subject to license terms. 24 */ 25 26 #include <sys/param.h> 27 #include <sys/fcntl.h> 28 #include <sys/obpdefs.h> 29 #include <sys/reboot.h> 30 #include <sys/promif.h> 31 #include <sys/stat.h> 32 #include <sys/bootvfs.h> 33 #include <sys/platnames.h> 34 #include <sys/salib.h> 35 #include <sys/elf.h> 36 #include <sys/link.h> 37 #include <sys/auxv.h> 38 #include <sys/boot_policy.h> 39 #include <sys/boot_redirect.h> 40 #include <sys/bootconf.h> 41 #include <sys/boot.h> 42 #include "boot_plat.h" 43 44 #define SUCCESS 0 45 #define FAILURE -1 46 47 #define ISSPACE(c) (c == ' ' || c == '\t') 48 #define SKIP_WHITESPC(cp) while (*cp && ISSPACE(*cp)) cp++; 49 50 51 #ifdef DEBUG 52 int debug = 0; 53 #else 54 static const int debug = 0; 55 #endif 56 57 #define dprintf if (debug) printf 58 59 #ifdef DEBUG_LISTS 60 void print_memlist(struct memlist *av); 61 #endif 62 63 extern int (*readfile(int fd, int print))(); 64 extern void kmem_init(void); 65 extern void *kmem_alloc(size_t, int); 66 extern void kmem_free(void *, size_t); 67 extern void get_boot_args(char *buf); 68 extern void setup_bootops(void); 69 extern struct bootops bootops; 70 extern void exitto(int (*entrypoint)()); 71 extern void exitto64(int (*entrypoint)(), void *bootvec); 72 73 int openfile(char *filename); 74 75 char *default_name; 76 char *default_path; 77 78 int vac; /* virtual address cache type (none == 0) */ 79 int is_sun4v; /* sun4u vs. sun4v */ 80 int client_isLP64 = 1; /* SPARC clients are always LP64 */ 81 82 extern bootplat_defaults_t sun4u_plat_defaults; 83 extern bootplat_defaults_t sun4v_plat_defaults; 84 85 /* 86 * filename is the name of the standalone we're going to execute. 87 */ 88 char filename[MAXPATHLEN]; 89 90 char * const defname = "kernel/sparcv9/unix"; 91 92 /* 93 * We enable the cache by default 94 * but boot -n will leave it alone... 95 * that is, we use whatever state the PROM left it in. 96 */ 97 char *mfg_name; 98 int cache_state = 1; 99 char filename2[MAXPATHLEN]; 100 101 int boothowto = 0; 102 int verbosemode = 0; 103 104 105 /* 106 * Copy filename and bargs into v2args_buf, which will be exported as the 107 * boot-args boot property. We should probably warn the user if anything gets 108 * cut off. 109 */ 110 void 111 set_client_bootargs(const char *filename, const char *bargs) 112 { 113 int i = 0; 114 const char *s; 115 116 s = filename; 117 while (*s != '\0' && i < V2ARGS_BUF_SZ - 1) 118 v2args_buf[i++] = *s++; 119 120 if (i >= V2ARGS_BUF_SZ - 2) { 121 /* Not enough room for a space and any of bargs. */ 122 v2args_buf[i] = '\0'; 123 return; 124 } 125 126 v2args_buf[i++] = ' '; 127 128 s = bargs; 129 while (*s != '\0' && i < V2ARGS_BUF_SZ - 1) 130 v2args_buf[i++] = *s++; 131 132 v2args_buf[i] = '\0'; 133 } 134 135 /* 136 * The slice redirection file is used on the install CD 137 */ 138 static int 139 read_redirect(char *redirect) 140 { 141 int fd; 142 char slicec; 143 size_t nread = 0; 144 145 if ((fd = open(BOOT_REDIRECT, O_RDONLY)) != -1) { 146 /* 147 * Read the character out of the file - this is the 148 * slice to use, in base 36. 149 */ 150 nread = read(fd, &slicec, 1); 151 (void) close(fd); 152 if (nread == 1) 153 *redirect++ = slicec; 154 } 155 *redirect = '\0'; 156 157 return (nread == 1); 158 } 159 160 void 161 post_mountroot(char *bootfile, char *redirect) 162 { 163 int (*go2)(); 164 int fd; 165 166 /* Save the bootfile, just in case we need it again */ 167 (void) strcpy(filename2, bootfile); 168 169 for (;;) { 170 if (boothowto & RB_ASKNAME) { 171 char tmpname[MAXPATHLEN]; 172 173 printf("Enter filename [%s]: ", bootfile); 174 (void) cons_gets(tmpname, sizeof (tmpname)); 175 if (tmpname[0] != '\0') 176 (void) strcpy(bootfile, tmpname); 177 } 178 179 if (boothowto & RB_HALT) { 180 printf("Boot halted.\n"); 181 prom_enter_mon(); 182 } 183 184 if ((fd = openfile(bootfile)) == FAILURE) { 185 186 /* 187 * There are many reasons why this might've 188 * happened .. but one of them is that we're 189 * on the installation CD, and we need to 190 * revector ourselves off to a different partition 191 * of the CD. Check for the redirection file. 192 */ 193 if (redirect != NULL && 194 read_redirect(redirect)) { 195 /* restore bootfile */ 196 (void) strcpy(bootfile, filename2); 197 return; 198 /*NOTREACHED*/ 199 } 200 201 printf("%s: cannot open %s\n", my_own_name, bootfile); 202 boothowto |= RB_ASKNAME; 203 204 /* restore bootfile */ 205 (void) strcpy(bootfile, filename2); 206 continue; 207 } 208 209 if ((go2 = readfile(fd, boothowto & RB_VERBOSE)) != 210 (int(*)()) -1) { 211 (void) close(fd); 212 } else { 213 printf("boot failed\n"); 214 boothowto |= RB_ASKNAME; 215 continue; 216 } 217 218 if (boothowto & RB_HALT) { 219 printf("Boot halted before exit to 0x%p.\n", 220 (void *)go2); 221 prom_enter_mon(); 222 } 223 224 my_own_name = bootfile; 225 226 dprintf("Calling exitto64(%p, %p)\n", (void *)go2, 227 (void *)elfbootvecELF64); 228 exitto64(go2, (void *)elfbootvecELF64); 229 } 230 } 231 232 /*ARGSUSED*/ 233 static int 234 boot_open(char *pathname, void *arg) 235 { 236 dprintf("trying '%s'\n", pathname); 237 return (open(pathname, O_RDONLY)); 238 } 239 240 /* 241 * Open the given filename, expanding to it's 242 * platform-dependent location if necessary. 243 * 244 * Boot supports OBP and IEEE1275. 245 * 246 * XXX: Move side effects out of this function! 247 */ 248 int 249 openfile(char *filename) 250 { 251 static char *fullpath; 252 static int once; 253 int fd; 254 255 if (once == 0) { 256 257 ++once; 258 259 /* 260 * Setup exported 'boot' properties: 'mfg-name'. 261 * XXX: This shouldn't be a side effect of openfile(). 262 */ 263 if (mfg_name == NULL) 264 mfg_name = get_mfg_name(); 265 266 fullpath = (char *)kmem_alloc(MAXPATHLEN, 0); 267 } 268 269 if (*filename == '/') { 270 (void) strcpy(fullpath, filename); 271 fd = boot_open(fullpath, NULL); 272 return (fd); 273 } 274 275 fd = open_platform_file(filename, boot_open, NULL, fullpath); 276 if (fd == -1) 277 return (-1); 278 279 /* 280 * Copy back the name we actually found 281 */ 282 (void) strcpy(filename, fullpath); 283 return (fd); 284 } 285 286 /* 287 * Get the boot arguments from the PROM and split it into filename and 288 * options components. 289 * 290 * As per IEEE1275 and boot(1M), the boot arguments will have the syntax 291 * "[filename] [-options]". If filename is specified, it is copied into the 292 * first buffer. (Otherwise, the buffer is left alone.) The rest of the string 293 * is copied into the second buffer. 294 */ 295 static void 296 init_bootargs(char *fname_buf, int fname_buf_sz, char *bargs_buf, 297 int bargs_buf_sz) 298 { 299 const char *tp = prom_bootargs(); 300 301 if (!tp || *tp == '\0') { 302 *bargs_buf = '\0'; 303 return; 304 } 305 306 SKIP_WHITESPC(tp); 307 308 /* 309 * If we don't have an option indicator, then we 310 * already have our filename prepended. 311 */ 312 if (*tp && *tp != '-') { 313 int i; 314 315 /* 316 * Copy the filename into fname_buf. 317 */ 318 for (i = 0; i < fname_buf_sz && *tp && !ISSPACE(*tp); ++i) 319 *fname_buf++ = *tp++; 320 321 if (i >= fname_buf_sz) { 322 printf("boot: boot filename too long!\n"); 323 printf("boot halted.\n"); 324 prom_enter_mon(); 325 /*NOTREACHED*/ 326 } else { 327 *fname_buf = '\0'; 328 } 329 330 SKIP_WHITESPC(tp); 331 } 332 333 /* The rest of the line is the options. */ 334 while (bargs_buf_sz > 1 && *tp) { 335 *bargs_buf++ = *tp++; 336 --bargs_buf_sz; 337 } 338 *bargs_buf = '\0'; 339 340 if (bargs_buf_sz == 1) { 341 printf("boot: boot arguments too long!\n"); 342 printf("boot halted.\n"); 343 prom_enter_mon(); 344 /*NOTREACHED*/ 345 } 346 } 347 348 boolean_t 349 is_netdev(char *devpath) 350 { 351 pnode_t node = prom_finddevice(devpath); 352 char *options; 353 354 if ((node == OBP_NONODE) || (node == OBP_BADNODE)) 355 return (B_FALSE); 356 if (prom_devicetype(node, "network") != 0) 357 return (B_TRUE); 358 359 /* 360 * For Infiniband, network device names will be of the 361 * format XXX/ib@0:port=1,pkey=1234,protocol=ip[,YYY] where 362 * XXX is typically /pci@8,700000/pci@1. The device_type 363 * property will be "ib". 364 */ 365 if (prom_devicetype(node, "ib") != 0) { 366 options = prom_path_options(devpath); 367 if (options != NULL) { 368 369 #define SEARCHSTRING ",protocol=ip" 370 #define SEARCHSTRLEN strlen(SEARCHSTRING) 371 372 if (strstr(options, ",protocol=ip,") != NULL) 373 return (B_TRUE); 374 while ((options = strstr(options, SEARCHSTRING)) != 375 NULL) { 376 char nextc; 377 378 nextc = options[SEARCHSTRLEN]; 379 if ((nextc == ',') || (nextc == 0)) 380 return (B_TRUE); 381 options += SEARCHSTRLEN; 382 } 383 } 384 } 385 return (B_FALSE); 386 } 387 388 /* 389 * Hook for modifying the OS boot path. This hook allows us to handle 390 * device arguments that the OS can't handle. 391 */ 392 void 393 mangle_os_bootpath(char *bpath) 394 { 395 pnode_t node; 396 char *stripped_pathname; 397 398 node = prom_finddevice(bpath); 399 if (prom_devicetype(node, "network") == 0) 400 return; 401 402 /* 403 * The OS can't handle network device arguments 404 * eg: boot net:promiscuous,speed=100,duplex=full 405 * So, we remove any argument strings in the device 406 * pathname we hand off to the OS for network devices. 407 * 408 * Internally, within boot, bpath is used to access 409 * the device, but v2path (as the boot property "boot-path") 410 * is the pathname passed to the OS. 411 */ 412 413 stripped_pathname = kmem_alloc(OBP_MAXPATHLEN, 0); 414 prom_strip_options(bpath, stripped_pathname); 415 v2path = stripped_pathname; 416 } 417 418 /* 419 * Given the boot path in the native firmware format use 420 * the redirection string to mutate the boot path to the new device. 421 * Fix up the 'v2path' so that it matches the new firmware path. 422 */ 423 void 424 redirect_boot_path(char *bpath, char *redirect) 425 { 426 char slicec = *redirect; 427 char *p = bpath + strlen(bpath); 428 429 /* 430 * If the redirection character doesn't fall in this 431 * range, something went horribly wrong. 432 */ 433 if (slicec < '0' || slicec > '7') { 434 printf("boot: bad redirection slice '%c'\n", slicec); 435 return; 436 } 437 438 /* 439 * Handle fully qualified OpenBoot pathname. 440 */ 441 while (--p >= bpath && *p != '@' && *p != '/') 442 if (*p == ':') 443 break; 444 if (*p++ == ':') { 445 /* 446 * Convert slice number to partition 'letter'. 447 */ 448 *p++ = 'a' + slicec - '0'; 449 *p = '\0'; 450 v2path = bpath; 451 return; 452 } 453 prom_panic("redirect_boot_path: mangled boot path!"); 454 } 455 456 #define PROM_VERS_MAX_LEN 64 457 458 void 459 system_check(void) 460 { 461 char buf[PROM_VERS_MAX_LEN]; 462 pnode_t n; 463 char arch[128]; 464 size_t len; 465 bootplat_defaults_t *plat_defaults; 466 467 /* 468 * This is a sun4v machine iff the device_type property 469 * exists on the root node and has the value "sun4v". 470 * Some older sunfire proms do not have such a property. 471 */ 472 is_sun4v = 0; 473 n = prom_rootnode(); 474 len = prom_getproplen(n, "device_type"); 475 if (len > 0 && len < sizeof (arch)) { 476 (void) prom_getprop(n, "device_type", arch); 477 arch[len] = '\0'; 478 dprintf("device_type=%s\n", arch); 479 if (strcmp(arch, "sun4v") == 0) { 480 is_sun4v = 1; 481 } 482 } else { 483 dprintf("device_type: no such property, len=%d\n", (int)len); 484 } 485 486 if (!is_sun4v && cpu_is_ultrasparc_1()) { 487 printf("UltraSPARC I processors are not supported by this " 488 "release of Solaris.\n"); 489 prom_exit_to_mon(); 490 } 491 492 /* 493 * Set up defaults per platform 494 */ 495 plat_defaults = (is_sun4v) ? 496 &sun4v_plat_defaults : &sun4u_plat_defaults; 497 498 default_name = plat_defaults->plat_defaults_name; 499 default_path = plat_defaults->plat_defaults_path; 500 vac = plat_defaults->plat_defaults_vac; 501 502 dprintf("default_name: %s\n", default_name); 503 dprintf("default_path: %s\n", default_path); 504 dprintf("vac: %d\n", vac); 505 506 if (prom_version_check(buf, PROM_VERS_MAX_LEN, NULL) != PROM_VER64_OK) { 507 printf("The firmware on this system does not support the 64-bit" 508 " OS.\n\tPlease upgrade to at least the following version:" 509 "\n\n\t%s\n", buf); 510 prom_exit_to_mon(); 511 } 512 } 513 514 /* 515 * Reads in the standalone (client) program and jumps to it. If this 516 * attempt fails, prints "boot failed" and returns to its caller. 517 * 518 * It will try to determine if it is loading a Unix file by 519 * looking at what should be the magic number. If it makes 520 * sense, it will use it; otherwise it jumps to the first 521 * address of the blocks that it reads in. 522 * 523 * This new boot program will open a file, read the ELF header, 524 * attempt to allocate and map memory at the location at which 525 * the client desires to be linked, and load the program at 526 * that point. It will then jump there. 527 */ 528 /*ARGSUSED*/ 529 int 530 main(void *cookie, char **argv, int argc) 531 { 532 /* 533 * bpath is the boot device path buffer. 534 * bargs is the boot arguments buffer. 535 */ 536 static char bpath[OBP_MAXPATHLEN], bargs[OBP_MAXPATHLEN]; 537 boolean_t user_specified_filename; 538 539 prom_init("boot", cookie); 540 fiximp(); 541 542 system_check(); 543 544 dprintf("\nboot: V%d /boot interface.\n", BO_VERSION); 545 #ifdef HALTBOOT 546 prom_enter_mon(); 547 #endif /* HALTBOOT */ 548 549 init_memlists(); 550 551 #ifdef DEBUG_LISTS 552 dprintf("Physmem avail:\n"); 553 if (debug) print_memlist(pfreelistp); 554 dprintf("Virtmem avail:\n"); 555 if (debug) print_memlist(vfreelistp); 556 dprintf("Phys installed:\n"); 557 if (debug) print_memlist(pinstalledp); 558 prom_enter_mon(); 559 #endif /* DEBUG_LISTS */ 560 561 /* 562 * Initialize the default filename (exported as "default-name" and 563 * used by kadb). 564 */ 565 set_default_filename(defname); 566 567 /* 568 * Parse the arguments ASAP in case there are any flags which may 569 * affect execution. 570 */ 571 572 /* 573 * filename is the path to the standalone. Initialize it to the empty 574 * string so we can tell whether the user specified it in the 575 * arguments. 576 */ 577 filename[0] = '\0'; 578 579 /* 580 * Fetch the boot arguments from the PROM and split the filename off 581 * if it's there. 582 */ 583 init_bootargs(filename, sizeof (filename), bargs, sizeof (bargs)); 584 585 /* 586 * kadb was delivered as a standalone, and as such, people got used to 587 * typing `boot kadb'. kmdb isn't a standalone - it is loaded by krtld 588 * as just another kernel module. For compatibility, though, when we 589 * see an attempt to `boot kadb' or `boot kmdb', we'll transform that 590 * into a `boot -k' (or equivalent). 591 */ 592 if (strcmp(filename, "kmdb") == 0 || strcmp(filename, "kadb") == 0) { 593 boothowto |= RB_KMDB; 594 *filename = '\0'; /* let boot figure out which unix to use */ 595 } 596 597 bootflags(bargs, sizeof (bargs)); 598 599 user_specified_filename = (filename[0] != '\0'); 600 601 /* Fetch the boot path from the PROM. */ 602 (void) strncpy(bpath, prom_bootpath(), sizeof (bpath) - 1); 603 bpath[sizeof (bpath) - 1] = '\0'; 604 605 dprintf("arch: %s\n", is_sun4v ? "sun4v" : "sun4u"); 606 dprintf("bootpath: 0x%p %s\n", (void *)bpath, bpath); 607 dprintf("bootargs: 0x%p %s\n", (void *)bargs, bargs); 608 dprintf("filename: 0x%p %s\n", (void *)filename, filename); 609 dprintf("kernname: 0x%p %s\n", (void *)kernname, kernname); 610 611 /* 612 * *v2path will be exported to the standalone as the boot-path boot 613 * property. 614 */ 615 v2path = bpath; 616 617 /* 618 * Our memory lists should be "up" by this time 619 */ 620 621 setup_bootops(); 622 623 /* 624 * If bpath is a network card, set v2path to a copy of bpath with the 625 * options stripped off. 626 */ 627 mangle_os_bootpath(bpath); 628 629 /* 630 * Not necessary on sun4v as nvram is virtual 631 * and kept by the guest manager on the SP. 632 */ 633 if (!is_sun4v) { 634 retain_nvram_page(); 635 } 636 637 if (bootprog(bpath, bargs, user_specified_filename) == 0) { 638 post_mountroot(filename, NULL); 639 /*NOTREACHED*/ 640 } 641 642 return (0); 643 }