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