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 }