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 /*
  23  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
  24  * Use is subject to license terms.
  25  *
  26  * Copyright (c) 2010, Intel Corporation.
  27  * All rights reserved.
  28  *
  29  * Copyright 2013 Joyent, Inc.  All rights reserved.
  30  */
  31 
  32 /*
  33  * This file contains the functionality that mimics the boot operations
  34  * on SPARC systems or the old boot.bin/multiboot programs on x86 systems.
  35  * The x86 kernel now does everything on its own.
  36  */
  37 
  38 #include <sys/types.h>
  39 #include <sys/bootconf.h>
  40 #include <sys/bootsvcs.h>
  41 #include <sys/bootinfo.h>
  42 #include <sys/multiboot.h>
  43 #include <sys/bootvfs.h>
  44 #include <sys/bootprops.h>
  45 #include <sys/varargs.h>
  46 #include <sys/param.h>
  47 #include <sys/machparam.h>
  48 #include <sys/machsystm.h>
  49 #include <sys/archsystm.h>
  50 #include <sys/boot_console.h>
  51 #include <sys/cmn_err.h>
  52 #include <sys/systm.h>
  53 #include <sys/promif.h>
  54 #include <sys/archsystm.h>
  55 #include <sys/x86_archext.h>
  56 #include <sys/kobj.h>
  57 #include <sys/privregs.h>
  58 #include <sys/sysmacros.h>
  59 #include <sys/ctype.h>
  60 #include <sys/fastboot.h>
  61 #ifdef __xpv
  62 #include <sys/hypervisor.h>
  63 #include <net/if.h>
  64 #endif
  65 #include <vm/kboot_mmu.h>
  66 #include <vm/hat_pte.h>
  67 #include <sys/kobj.h>
  68 #include <sys/kobj_lex.h>
  69 #include <sys/pci_cfgspace_impl.h>
  70 #include <sys/fastboot_impl.h>
  71 #include <sys/acpi/acconfig.h>
  72 #include <sys/acpi/acpi.h>
  73 
  74 static int have_console = 0;    /* set once primitive console is initialized */
  75 static char *boot_args = "";
  76 
  77 /*
  78  * Debugging macros
  79  */
  80 static uint_t kbm_debug = 0;
  81 #define DBG_MSG(s)      { if (kbm_debug) bop_printf(NULL, "%s", s); }
  82 #define DBG(x)          { if (kbm_debug)                        \
  83         bop_printf(NULL, "%s is %" PRIx64 "\n", #x, (uint64_t)(x));     \
  84         }
  85 
  86 #define PUT_STRING(s) {                         \
  87         char *cp;                               \
  88         for (cp = (s); *cp; ++cp)               \
  89                 bcons_putchar(*cp);             \
  90         }
  91 
  92 bootops_t bootop;       /* simple bootops we'll pass on to kernel */
  93 struct bsys_mem bm;
  94 
  95 /*
  96  * Boot info from "glue" code in low memory. xbootp is used by:
  97  *      do_bop_phys_alloc(), do_bsys_alloc() and boot_prop_finish().
  98  */
  99 static struct xboot_info *xbootp;
 100 static uintptr_t next_virt;     /* next available virtual address */
 101 static paddr_t next_phys;       /* next available physical address from dboot */
 102 static paddr_t high_phys = -(paddr_t)1; /* last used physical address */
 103 
 104 /*
 105  * buffer for vsnprintf for console I/O
 106  */
 107 #define BUFFERSIZE      512
 108 static char buffer[BUFFERSIZE];
 109 
 110 /*
 111  * stuff to store/report/manipulate boot property settings.
 112  */
 113 typedef struct bootprop {
 114         struct bootprop *bp_next;
 115         char *bp_name;
 116         uint_t bp_vlen;
 117         char *bp_value;
 118 } bootprop_t;
 119 
 120 static bootprop_t *bprops = NULL;
 121 static char *curr_page = NULL;          /* ptr to avail bprop memory */
 122 static int curr_space = 0;              /* amount of memory at curr_page */
 123 
 124 #ifdef __xpv
 125 start_info_t *xen_info;
 126 shared_info_t *HYPERVISOR_shared_info;
 127 #endif
 128 
 129 /*
 130  * some allocator statistics
 131  */
 132 static ulong_t total_bop_alloc_scratch = 0;
 133 static ulong_t total_bop_alloc_kernel = 0;
 134 
 135 static void build_firmware_properties(void);
 136 
 137 static int early_allocation = 1;
 138 
 139 int force_fastreboot = 0;
 140 volatile int fastreboot_onpanic = 0;
 141 int post_fastreboot = 0;
 142 #ifdef  __xpv
 143 volatile int fastreboot_capable = 0;
 144 #else
 145 volatile int fastreboot_capable = 1;
 146 #endif
 147 
 148 /*
 149  * Information saved from current boot for fast reboot.
 150  * If the information size exceeds what we have allocated, fast reboot
 151  * will not be supported.
 152  */
 153 multiboot_info_t saved_mbi;
 154 mb_memory_map_t saved_mmap[FASTBOOT_SAVED_MMAP_COUNT];
 155 uint8_t saved_drives[FASTBOOT_SAVED_DRIVES_SIZE];
 156 char saved_cmdline[FASTBOOT_SAVED_CMDLINE_LEN];
 157 int saved_cmdline_len = 0;
 158 size_t saved_file_size[FASTBOOT_MAX_FILES_MAP];
 159 
 160 /*
 161  * Turn off fastreboot_onpanic to avoid panic loop.
 162  */
 163 char fastreboot_onpanic_cmdline[FASTBOOT_SAVED_CMDLINE_LEN];
 164 static const char fastreboot_onpanic_args[] = " -B fastreboot_onpanic=0";
 165 
 166 /*
 167  * Pointers to where System Resource Affinity Table (SRAT), System Locality
 168  * Information Table (SLIT) and Maximum System Capability Table (MSCT)
 169  * are mapped into virtual memory
 170  */
 171 ACPI_TABLE_SRAT *srat_ptr = NULL;
 172 ACPI_TABLE_SLIT *slit_ptr = NULL;
 173 ACPI_TABLE_MSCT *msct_ptr = NULL;
 174 
 175 /*
 176  * Arbitrary limit on number of localities we handle; if
 177  * this limit is raised to more than UINT16_MAX, make sure
 178  * process_slit() knows how to handle it.
 179  */
 180 #define SLIT_LOCALITIES_MAX     (4096)
 181 
 182 #define SLIT_NUM_PROPNAME       "acpi-slit-localities"
 183 #define SLIT_PROPNAME           "acpi-slit"
 184 
 185 /*
 186  * Allocate aligned physical memory at boot time. This allocator allocates
 187  * from the highest possible addresses. This avoids exhausting memory that
 188  * would be useful for DMA buffers.
 189  */
 190 paddr_t
 191 do_bop_phys_alloc(uint64_t size, uint64_t align)
 192 {
 193         paddr_t pa = 0;
 194         paddr_t start;
 195         paddr_t end;
 196         struct memlist  *ml = (struct memlist *)xbootp->bi_phys_install;
 197 
 198         /*
 199          * Be careful if high memory usage is limited in startup.c
 200          * Since there are holes in the low part of the physical address
 201          * space we can treat physmem as a pfn (not just a pgcnt) and
 202          * get a conservative upper limit.
 203          */
 204         if (physmem != 0 && high_phys > pfn_to_pa(physmem))
 205                 high_phys = pfn_to_pa(physmem);
 206 
 207         /*
 208          * find the lowest or highest available memory in physinstalled
 209          * On 32 bit avoid physmem above 4Gig if PAE isn't enabled
 210          */
 211 #if defined(__i386)
 212         if (xbootp->bi_use_pae == 0 && high_phys > FOUR_GIG)
 213                 high_phys = FOUR_GIG;
 214 #endif
 215 
 216         /*
 217          * find the highest available memory in physinstalled
 218          */
 219         size = P2ROUNDUP(size, align);
 220         for (; ml; ml = ml->ml_next) {
 221                 start = P2ROUNDUP(ml->ml_address, align);
 222                 end = P2ALIGN(ml->ml_address + ml->ml_size, align);
 223                 if (start < next_phys)
 224                         start = P2ROUNDUP(next_phys, align);
 225                 if (end > high_phys)
 226                         end = P2ALIGN(high_phys, align);
 227 
 228                 if (end <= start)
 229                         continue;
 230                 if (end - start < size)
 231                         continue;
 232 
 233                 /*
 234                  * Early allocations need to use low memory, since
 235                  * physmem might be further limited by bootenv.rc
 236                  */
 237                 if (early_allocation) {
 238                         if (pa == 0 || start < pa)
 239                                 pa = start;
 240                 } else {
 241                         if (end - size > pa)
 242                                 pa = end - size;
 243                 }
 244         }
 245         if (pa != 0) {
 246                 if (early_allocation)
 247                         next_phys = pa + size;
 248                 else
 249                         high_phys = pa;
 250                 return (pa);
 251         }
 252         bop_panic("do_bop_phys_alloc(0x%" PRIx64 ", 0x%" PRIx64
 253             ") Out of memory\n", size, align);
 254         /*NOTREACHED*/
 255 }
 256 
 257 uintptr_t
 258 alloc_vaddr(size_t size, paddr_t align)
 259 {
 260         uintptr_t rv;
 261 
 262         next_virt = P2ROUNDUP(next_virt, (uintptr_t)align);
 263         rv = (uintptr_t)next_virt;
 264         next_virt += size;
 265         return (rv);
 266 }
 267 
 268 /*
 269  * Allocate virtual memory. The size is always rounded up to a multiple
 270  * of base pagesize.
 271  */
 272 
 273 /*ARGSUSED*/
 274 static caddr_t
 275 do_bsys_alloc(bootops_t *bop, caddr_t virthint, size_t size, int align)
 276 {
 277         paddr_t a = align;      /* same type as pa for masking */
 278         uint_t pgsize;
 279         paddr_t pa;
 280         uintptr_t va;
 281         ssize_t s;              /* the aligned size */
 282         uint_t level;
 283         uint_t is_kernel = (virthint != 0);
 284 
 285         if (a < MMU_PAGESIZE)
 286                 a = MMU_PAGESIZE;
 287         else if (!ISP2(a))
 288                 prom_panic("do_bsys_alloc() incorrect alignment");
 289         size = P2ROUNDUP(size, MMU_PAGESIZE);
 290 
 291         /*
 292          * Use the next aligned virtual address if we weren't given one.
 293          */
 294         if (virthint == NULL) {
 295                 virthint = (caddr_t)alloc_vaddr(size, a);
 296                 total_bop_alloc_scratch += size;
 297         } else {
 298                 total_bop_alloc_kernel += size;
 299         }
 300 
 301         /*
 302          * allocate the physical memory
 303          */
 304         pa = do_bop_phys_alloc(size, a);
 305 
 306         /*
 307          * Add the mappings to the page tables, try large pages first.
 308          */
 309         va = (uintptr_t)virthint;
 310         s = size;
 311         level = 1;
 312         pgsize = xbootp->bi_use_pae ? TWO_MEG : FOUR_MEG;
 313         if (xbootp->bi_use_largepage && a == pgsize) {
 314                 while (IS_P2ALIGNED(pa, pgsize) && IS_P2ALIGNED(va, pgsize) &&
 315                     s >= pgsize) {
 316                         kbm_map(va, pa, level, is_kernel);
 317                         va += pgsize;
 318                         pa += pgsize;
 319                         s -= pgsize;
 320                 }
 321         }
 322 
 323         /*
 324          * Map remaining pages use small mappings
 325          */
 326         level = 0;
 327         pgsize = MMU_PAGESIZE;
 328         while (s > 0) {
 329                 kbm_map(va, pa, level, is_kernel);
 330                 va += pgsize;
 331                 pa += pgsize;
 332                 s -= pgsize;
 333         }
 334         return (virthint);
 335 }
 336 
 337 /*
 338  * Free virtual memory - we'll just ignore these.
 339  */
 340 /*ARGSUSED*/
 341 static void
 342 do_bsys_free(bootops_t *bop, caddr_t virt, size_t size)
 343 {
 344         bop_printf(NULL, "do_bsys_free(virt=0x%p, size=0x%lx) ignored\n",
 345             (void *)virt, size);
 346 }
 347 
 348 /*
 349  * Old interface
 350  */
 351 /*ARGSUSED*/
 352 static caddr_t
 353 do_bsys_ealloc(bootops_t *bop, caddr_t virthint, size_t size,
 354     int align, int flags)
 355 {
 356         prom_panic("unsupported call to BOP_EALLOC()\n");
 357         return (0);
 358 }
 359 
 360 
 361 static void
 362 bsetprop(char *name, int nlen, void *value, int vlen)
 363 {
 364         uint_t size;
 365         uint_t need_size;
 366         bootprop_t *b;
 367 
 368         /*
 369          * align the size to 16 byte boundary
 370          */
 371         size = sizeof (bootprop_t) + nlen + 1 + vlen;
 372         size = (size + 0xf) & ~0xf;
 373         if (size > curr_space) {
 374                 need_size = (size + (MMU_PAGEOFFSET)) & MMU_PAGEMASK;
 375                 curr_page = do_bsys_alloc(NULL, 0, need_size, MMU_PAGESIZE);
 376                 curr_space = need_size;
 377         }
 378 
 379         /*
 380          * use a bootprop_t at curr_page and link into list
 381          */
 382         b = (bootprop_t *)curr_page;
 383         curr_page += sizeof (bootprop_t);
 384         curr_space -=  sizeof (bootprop_t);
 385         b->bp_next = bprops;
 386         bprops = b;
 387 
 388         /*
 389          * follow by name and ending zero byte
 390          */
 391         b->bp_name = curr_page;
 392         bcopy(name, curr_page, nlen);
 393         curr_page += nlen;
 394         *curr_page++ = 0;
 395         curr_space -= nlen + 1;
 396 
 397         /*
 398          * copy in value, but no ending zero byte
 399          */
 400         b->bp_value = curr_page;
 401         b->bp_vlen = vlen;
 402         if (vlen > 0) {
 403                 bcopy(value, curr_page, vlen);
 404                 curr_page += vlen;
 405                 curr_space -= vlen;
 406         }
 407 
 408         /*
 409          * align new values of curr_page, curr_space
 410          */
 411         while (curr_space & 0xf) {
 412                 ++curr_page;
 413                 --curr_space;
 414         }
 415 }
 416 
 417 static void
 418 bsetprops(char *name, char *value)
 419 {
 420         bsetprop(name, strlen(name), value, strlen(value) + 1);
 421 }
 422 
 423 static void
 424 bsetprop64(char *name, uint64_t value)
 425 {
 426         bsetprop(name, strlen(name), (void *)&value, sizeof (value));
 427 }
 428 
 429 static void
 430 bsetpropsi(char *name, int value)
 431 {
 432         char prop_val[32];
 433 
 434         (void) snprintf(prop_val, sizeof (prop_val), "%d", value);
 435         bsetprops(name, prop_val);
 436 }
 437 
 438 /*
 439  * to find the size of the buffer to allocate
 440  */
 441 /*ARGSUSED*/
 442 int
 443 do_bsys_getproplen(bootops_t *bop, const char *name)
 444 {
 445         bootprop_t *b;
 446 
 447         for (b = bprops; b; b = b->bp_next) {
 448                 if (strcmp(name, b->bp_name) != 0)
 449                         continue;
 450                 return (b->bp_vlen);
 451         }
 452         return (-1);
 453 }
 454 
 455 /*
 456  * get the value associated with this name
 457  */
 458 /*ARGSUSED*/
 459 int
 460 do_bsys_getprop(bootops_t *bop, const char *name, void *value)
 461 {
 462         bootprop_t *b;
 463 
 464         for (b = bprops; b; b = b->bp_next) {
 465                 if (strcmp(name, b->bp_name) != 0)
 466                         continue;
 467                 bcopy(b->bp_value, value, b->bp_vlen);
 468                 return (0);
 469         }
 470         return (-1);
 471 }
 472 
 473 /*
 474  * get the name of the next property in succession from the standalone
 475  */
 476 /*ARGSUSED*/
 477 static char *
 478 do_bsys_nextprop(bootops_t *bop, char *name)
 479 {
 480         bootprop_t *b;
 481 
 482         /*
 483          * A null name is a special signal for the 1st boot property
 484          */
 485         if (name == NULL || strlen(name) == 0) {
 486                 if (bprops == NULL)
 487                         return (NULL);
 488                 return (bprops->bp_name);
 489         }
 490 
 491         for (b = bprops; b; b = b->bp_next) {
 492                 if (name != b->bp_name)
 493                         continue;
 494                 b = b->bp_next;
 495                 if (b == NULL)
 496                         return (NULL);
 497                 return (b->bp_name);
 498         }
 499         return (NULL);
 500 }
 501 
 502 /*
 503  * Parse numeric value from a string. Understands decimal, hex, octal, - and ~
 504  */
 505 static int
 506 parse_value(char *p, uint64_t *retval)
 507 {
 508         int adjust = 0;
 509         uint64_t tmp = 0;
 510         int digit;
 511         int radix = 10;
 512 
 513         *retval = 0;
 514         if (*p == '-' || *p == '~')
 515                 adjust = *p++;
 516 
 517         if (*p == '0') {
 518                 ++p;
 519                 if (*p == 0)
 520                         return (0);
 521                 if (*p == 'x' || *p == 'X') {
 522                         radix = 16;
 523                         ++p;
 524                 } else {
 525                         radix = 8;
 526                         ++p;
 527                 }
 528         }
 529         while (*p) {
 530                 if ('0' <= *p && *p <= '9')
 531                         digit = *p - '0';
 532                 else if ('a' <= *p && *p <= 'f')
 533                         digit = 10 + *p - 'a';
 534                 else if ('A' <= *p && *p <= 'F')
 535                         digit = 10 + *p - 'A';
 536                 else
 537                         return (-1);
 538                 if (digit >= radix)
 539                         return (-1);
 540                 tmp = tmp * radix + digit;
 541                 ++p;
 542         }
 543         if (adjust == '-')
 544                 tmp = -tmp;
 545         else if (adjust == '~')
 546                 tmp = ~tmp;
 547         *retval = tmp;
 548         return (0);
 549 }
 550 
 551 static boolean_t
 552 unprintable(char *value, int size)
 553 {
 554         int i;
 555 
 556         if (size <= 0 || value[0] == '\0')
 557                 return (B_TRUE);
 558 
 559         for (i = 0; i < size; i++) {
 560                 if (value[i] == '\0')
 561                         return (i != (size - 1));
 562 
 563                 if (!isprint(value[i]))
 564                         return (B_TRUE);
 565         }
 566         return (B_FALSE);
 567 }
 568 
 569 /*
 570  * Print out information about all boot properties.
 571  * buffer is pointer to pre-allocated space to be used as temporary
 572  * space for property values.
 573  */
 574 static void
 575 boot_prop_display(char *buffer)
 576 {
 577         char *name = "";
 578         int i, len;
 579 
 580         bop_printf(NULL, "\nBoot properties:\n");
 581 
 582         while ((name = do_bsys_nextprop(NULL, name)) != NULL) {
 583                 bop_printf(NULL, "\t0x%p %s = ", (void *)name, name);
 584                 (void) do_bsys_getprop(NULL, name, buffer);
 585                 len = do_bsys_getproplen(NULL, name);
 586                 bop_printf(NULL, "len=%d ", len);
 587                 if (!unprintable(buffer, len)) {
 588                         buffer[len] = 0;
 589                         bop_printf(NULL, "%s\n", buffer);
 590                         continue;
 591                 }
 592                 for (i = 0; i < len; i++) {
 593                         bop_printf(NULL, "%02x", buffer[i] & 0xff);
 594                         if (i < len - 1)
 595                                 bop_printf(NULL, ".");
 596                 }
 597                 bop_printf(NULL, "\n");
 598         }
 599 }
 600 
 601 /*
 602  * 2nd part of building the table of boot properties. This includes:
 603  * - values from /boot/solaris/bootenv.rc (ie. eeprom(1m) values)
 604  *
 605  * lines look like one of:
 606  * ^$
 607  * ^# comment till end of line
 608  * setprop name 'value'
 609  * setprop name value
 610  * setprop name "value"
 611  *
 612  * we do single character I/O since this is really just looking at memory
 613  */
 614 void
 615 boot_prop_finish(void)
 616 {
 617         int fd;
 618         char *line;
 619         int c;
 620         int bytes_read;
 621         char *name;
 622         int n_len;
 623         char *value;
 624         int v_len;
 625         char *inputdev; /* these override the command line if serial ports */
 626         char *outputdev;
 627         char *consoledev;
 628         uint64_t lvalue;
 629         int use_xencons = 0;
 630 
 631 #ifdef __xpv
 632         if (!DOMAIN_IS_INITDOMAIN(xen_info))
 633                 use_xencons = 1;
 634 #endif /* __xpv */
 635 
 636         DBG_MSG("Opening /boot/solaris/bootenv.rc\n");
 637         fd = BRD_OPEN(bfs_ops, "/boot/solaris/bootenv.rc", 0);
 638         DBG(fd);
 639 
 640         line = do_bsys_alloc(NULL, NULL, MMU_PAGESIZE, MMU_PAGESIZE);
 641         while (fd >= 0) {
 642 
 643                 /*
 644                  * get a line
 645                  */
 646                 for (c = 0; ; ++c) {
 647                         bytes_read = BRD_READ(bfs_ops, fd, line + c, 1);
 648                         if (bytes_read == 0) {
 649                                 if (c == 0)
 650                                         goto done;
 651                                 break;
 652                         }
 653                         if (line[c] == '\n')
 654                                 break;
 655                 }
 656                 line[c] = 0;
 657 
 658                 /*
 659                  * ignore comment lines
 660                  */
 661                 c = 0;
 662                 while (ISSPACE(line[c]))
 663                         ++c;
 664                 if (line[c] == '#' || line[c] == 0)
 665                         continue;
 666 
 667                 /*
 668                  * must have "setprop " or "setprop\t"
 669                  */
 670                 if (strncmp(line + c, "setprop ", 8) != 0 &&
 671                     strncmp(line + c, "setprop\t", 8) != 0)
 672                         continue;
 673                 c += 8;
 674                 while (ISSPACE(line[c]))
 675                         ++c;
 676                 if (line[c] == 0)
 677                         continue;
 678 
 679                 /*
 680                  * gather up the property name
 681                  */
 682                 name = line + c;
 683                 n_len = 0;
 684                 while (line[c] && !ISSPACE(line[c]))
 685                         ++n_len, ++c;
 686 
 687                 /*
 688                  * gather up the value, if any
 689                  */
 690                 value = "";
 691                 v_len = 0;
 692                 while (ISSPACE(line[c]))
 693                         ++c;
 694                 if (line[c] != 0) {
 695                         value = line + c;
 696                         while (line[c] && !ISSPACE(line[c]))
 697                                 ++v_len, ++c;
 698                 }
 699 
 700                 if (v_len >= 2 && value[0] == value[v_len - 1] &&
 701                     (value[0] == '\'' || value[0] == '"')) {
 702                         ++value;
 703                         v_len -= 2;
 704                 }
 705                 name[n_len] = 0;
 706                 if (v_len > 0)
 707                         value[v_len] = 0;
 708                 else
 709                         continue;
 710 
 711                 /*
 712                  * ignore "boot-file" property, it's now meaningless
 713                  */
 714                 if (strcmp(name, "boot-file") == 0)
 715                         continue;
 716                 if (strcmp(name, "boot-args") == 0 &&
 717                     strlen(boot_args) > 0)
 718                         continue;
 719 
 720                 /*
 721                  * If a property was explicitly set on the command line
 722                  * it will override a setting in bootenv.rc
 723                  */
 724                 if (do_bsys_getproplen(NULL, name) > 0)
 725                         continue;
 726 
 727                 bsetprop(name, n_len, value, v_len + 1);
 728         }
 729 done:
 730         if (fd >= 0)
 731                 (void) BRD_CLOSE(bfs_ops, fd);
 732 
 733         /*
 734          * Check if we have to limit the boot time allocator
 735          */
 736         if (do_bsys_getproplen(NULL, "physmem") != -1 &&
 737             do_bsys_getprop(NULL, "physmem", line) >= 0 &&
 738             parse_value(line, &lvalue) != -1) {
 739                 if (0 < lvalue && (lvalue < physmem || physmem == 0)) {
 740                         physmem = (pgcnt_t)lvalue;
 741                         DBG(physmem);
 742                 }
 743         }
 744         early_allocation = 0;
 745 
 746         /*
 747          * check to see if we have to override the default value of the console
 748          */
 749         if (!use_xencons) {
 750                 inputdev = line;
 751                 v_len = do_bsys_getproplen(NULL, "input-device");
 752                 if (v_len > 0)
 753                         (void) do_bsys_getprop(NULL, "input-device", inputdev);
 754                 else
 755                         v_len = 0;
 756                 inputdev[v_len] = 0;
 757 
 758                 outputdev = inputdev + v_len + 1;
 759                 v_len = do_bsys_getproplen(NULL, "output-device");
 760                 if (v_len > 0)
 761                         (void) do_bsys_getprop(NULL, "output-device",
 762                             outputdev);
 763                 else
 764                         v_len = 0;
 765                 outputdev[v_len] = 0;
 766 
 767                 consoledev = outputdev + v_len + 1;
 768                 v_len = do_bsys_getproplen(NULL, "console");
 769                 if (v_len > 0) {
 770                         (void) do_bsys_getprop(NULL, "console", consoledev);
 771                         if (post_fastreboot &&
 772                             strcmp(consoledev, "graphics") == 0) {
 773                                 bsetprops("console", "text");
 774                                 v_len = strlen("text");
 775                                 bcopy("text", consoledev, v_len);
 776                         }
 777                 } else {
 778                         v_len = 0;
 779                 }
 780                 consoledev[v_len] = 0;
 781                 bcons_init2(inputdev, outputdev, consoledev);
 782         } else {
 783                 /*
 784                  * Ensure console property exists
 785                  * If not create it as "hypervisor"
 786                  */
 787                 v_len = do_bsys_getproplen(NULL, "console");
 788                 if (v_len < 0)
 789                         bsetprops("console", "hypervisor");
 790                 inputdev = outputdev = consoledev = "hypervisor";
 791                 bcons_init2(inputdev, outputdev, consoledev);
 792         }
 793 
 794         if (strstr((char *)xbootp->bi_cmdline, "prom_debug") || kbm_debug)
 795                 boot_prop_display(line);
 796 }
 797 
 798 /*
 799  * print formatted output
 800  */
 801 /*PRINTFLIKE2*/
 802 /*ARGSUSED*/
 803 void
 804 bop_printf(bootops_t *bop, const char *fmt, ...)
 805 {
 806         va_list ap;
 807 
 808         if (have_console == 0)
 809                 return;
 810 
 811         va_start(ap, fmt);
 812         (void) vsnprintf(buffer, BUFFERSIZE, fmt, ap);
 813         va_end(ap);
 814         PUT_STRING(buffer);
 815 }
 816 
 817 /*
 818  * Another panic() variant; this one can be used even earlier during boot than
 819  * prom_panic().
 820  */
 821 /*PRINTFLIKE1*/
 822 void
 823 bop_panic(const char *fmt, ...)
 824 {
 825         va_list ap;
 826 
 827         va_start(ap, fmt);
 828         bop_printf(NULL, fmt, ap);
 829         va_end(ap);
 830 
 831         bop_printf(NULL, "\nPress any key to reboot.\n");
 832         (void) bcons_getchar();
 833         bop_printf(NULL, "Resetting...\n");
 834         pc_reset();
 835 }
 836 
 837 /*
 838  * Do a real mode interrupt BIOS call
 839  */
 840 typedef struct bios_regs {
 841         unsigned short ax, bx, cx, dx, si, di, bp, es, ds;
 842 } bios_regs_t;
 843 typedef int (*bios_func_t)(int, bios_regs_t *);
 844 
 845 /*ARGSUSED*/
 846 static void
 847 do_bsys_doint(bootops_t *bop, int intnum, struct bop_regs *rp)
 848 {
 849 #if defined(__xpv)
 850         prom_panic("unsupported call to BOP_DOINT()\n");
 851 #else   /* __xpv */
 852         static int firsttime = 1;
 853         bios_func_t bios_func = (bios_func_t)(void *)(uintptr_t)0x5000;
 854         bios_regs_t br;
 855 
 856         /*
 857          * The first time we do this, we have to copy the pre-packaged
 858          * low memory bios call code image into place.
 859          */
 860         if (firsttime) {
 861                 extern char bios_image[];
 862                 extern uint32_t bios_size;
 863 
 864                 bcopy(bios_image, (void *)bios_func, bios_size);
 865                 firsttime = 0;
 866         }
 867 
 868         br.ax = rp->eax.word.ax;
 869         br.bx = rp->ebx.word.bx;
 870         br.cx = rp->ecx.word.cx;
 871         br.dx = rp->edx.word.dx;
 872         br.bp = rp->ebp.word.bp;
 873         br.si = rp->esi.word.si;
 874         br.di = rp->edi.word.di;
 875         br.ds = rp->ds;
 876         br.es = rp->es;
 877 
 878         DBG_MSG("Doing BIOS call...");
 879         DBG(br.ax);
 880         DBG(br.bx);
 881         DBG(br.dx);
 882         rp->eflags = bios_func(intnum, &br);
 883         DBG_MSG("done\n");
 884 
 885         rp->eax.word.ax = br.ax;
 886         rp->ebx.word.bx = br.bx;
 887         rp->ecx.word.cx = br.cx;
 888         rp->edx.word.dx = br.dx;
 889         rp->ebp.word.bp = br.bp;
 890         rp->esi.word.si = br.si;
 891         rp->edi.word.di = br.di;
 892         rp->ds = br.ds;
 893         rp->es = br.es;
 894 #endif /* __xpv */
 895 }
 896 
 897 static struct boot_syscalls bop_sysp = {
 898         bcons_getchar,
 899         bcons_putchar,
 900         bcons_ischar,
 901 };
 902 
 903 static char *whoami;
 904 
 905 #define BUFLEN  64
 906 
 907 #if defined(__xpv)
 908 
 909 static char namebuf[32];
 910 
 911 static void
 912 xen_parse_props(char *s, char *prop_map[], int n_prop)
 913 {
 914         char **prop_name = prop_map;
 915         char *cp = s, *scp;
 916 
 917         do {
 918                 scp = cp;
 919                 while ((*cp != NULL) && (*cp != ':'))
 920                         cp++;
 921 
 922                 if ((scp != cp) && (*prop_name != NULL)) {
 923                         *cp = NULL;
 924                         bsetprops(*prop_name, scp);
 925                 }
 926 
 927                 cp++;
 928                 prop_name++;
 929                 n_prop--;
 930         } while (n_prop > 0);
 931 }
 932 
 933 #define VBDPATHLEN      64
 934 
 935 /*
 936  * parse the 'xpv-root' property to create properties used by
 937  * ufs_mountroot.
 938  */
 939 static void
 940 xen_vbdroot_props(char *s)
 941 {
 942         char vbdpath[VBDPATHLEN] = "/xpvd/xdf@";
 943         const char lnamefix[] = "/dev/dsk/c0d";
 944         char *pnp;
 945         char *prop_p;
 946         char mi;
 947         short minor;
 948         long addr = 0;
 949 
 950         pnp = vbdpath + strlen(vbdpath);
 951         prop_p = s + strlen(lnamefix);
 952         while ((*prop_p != '\0') && (*prop_p != 's') && (*prop_p != 'p'))
 953                 addr = addr * 10 + *prop_p++ - '0';
 954         (void) snprintf(pnp, VBDPATHLEN, "%lx", addr);
 955         pnp = vbdpath + strlen(vbdpath);
 956         if (*prop_p == 's')
 957                 mi = 'a';
 958         else if (*prop_p == 'p')
 959                 mi = 'q';
 960         else
 961                 ASSERT(0); /* shouldn't be here */
 962         prop_p++;
 963         ASSERT(*prop_p != '\0');
 964         if (ISDIGIT(*prop_p)) {
 965                 minor = *prop_p - '0';
 966                 prop_p++;
 967                 if (ISDIGIT(*prop_p)) {
 968                         minor = minor * 10 + *prop_p - '0';
 969                 }
 970         } else {
 971                 /* malformed root path, use 0 as default */
 972                 minor = 0;
 973         }
 974         ASSERT(minor < 16); /* at most 16 partitions */
 975         mi += minor;
 976         *pnp++ = ':';
 977         *pnp++ = mi;
 978         *pnp++ = '\0';
 979         bsetprops("fstype", "ufs");
 980         bsetprops("bootpath", vbdpath);
 981 
 982         DBG_MSG("VBD bootpath set to ");
 983         DBG_MSG(vbdpath);
 984         DBG_MSG("\n");
 985 }
 986 
 987 /*
 988  * parse the xpv-nfsroot property to create properties used by
 989  * nfs_mountroot.
 990  */
 991 static void
 992 xen_nfsroot_props(char *s)
 993 {
 994         char *prop_map[] = {
 995                 BP_SERVER_IP,   /* server IP address */
 996                 BP_SERVER_NAME, /* server hostname */
 997                 BP_SERVER_PATH, /* root path */
 998         };
 999         int n_prop = sizeof (prop_map) / sizeof (prop_map[0]);
1000 
1001         bsetprop("fstype", 6, "nfs", 4);
1002 
1003         xen_parse_props(s, prop_map, n_prop);
1004 
1005         /*
1006          * If a server name wasn't specified, use a default.
1007          */
1008         if (do_bsys_getproplen(NULL, BP_SERVER_NAME) == -1)
1009                 bsetprops(BP_SERVER_NAME, "unknown");
1010 }
1011 
1012 /*
1013  * Extract our IP address, etc. from the "xpv-ip" property.
1014  */
1015 static void
1016 xen_ip_props(char *s)
1017 {
1018         char *prop_map[] = {
1019                 BP_HOST_IP,             /* IP address */
1020                 NULL,                   /* NFS server IP address (ignored in */
1021                                         /* favour of xpv-nfsroot) */
1022                 BP_ROUTER_IP,           /* IP gateway */
1023                 BP_SUBNET_MASK,         /* IP subnet mask */
1024                 "xpv-hostname",         /* hostname (ignored) */
1025                 BP_NETWORK_INTERFACE,   /* interface name */
1026                 "xpv-hcp",              /* host configuration protocol */
1027         };
1028         int n_prop = sizeof (prop_map) / sizeof (prop_map[0]);
1029         char ifname[IFNAMSIZ];
1030 
1031         xen_parse_props(s, prop_map, n_prop);
1032 
1033         /*
1034          * A Linux dom0 administrator expects all interfaces to be
1035          * called "ethX", which is not the case here.
1036          *
1037          * If the interface name specified is "eth0", presume that
1038          * this is really intended to be "xnf0" (the first domU ->
1039          * dom0 interface for this domain).
1040          */
1041         if ((do_bsys_getprop(NULL, BP_NETWORK_INTERFACE, ifname) == 0) &&
1042             (strcmp("eth0", ifname) == 0)) {
1043                 bsetprops(BP_NETWORK_INTERFACE, "xnf0");
1044                 bop_printf(NULL,
1045                     "network interface name 'eth0' replaced with 'xnf0'\n");
1046         }
1047 }
1048 
1049 #else   /* __xpv */
1050 
1051 static void
1052 setup_rarp_props(struct sol_netinfo *sip)
1053 {
1054         char buf[BUFLEN];       /* to hold ip/mac addrs */
1055         uint8_t *val;
1056 
1057         val = (uint8_t *)&sip->sn_ciaddr;
1058         (void) snprintf(buf, BUFLEN, "%d.%d.%d.%d",
1059             val[0], val[1], val[2], val[3]);
1060         bsetprops(BP_HOST_IP, buf);
1061 
1062         val = (uint8_t *)&sip->sn_siaddr;
1063         (void) snprintf(buf, BUFLEN, "%d.%d.%d.%d",
1064             val[0], val[1], val[2], val[3]);
1065         bsetprops(BP_SERVER_IP, buf);
1066 
1067         if (sip->sn_giaddr != 0) {
1068                 val = (uint8_t *)&sip->sn_giaddr;
1069                 (void) snprintf(buf, BUFLEN, "%d.%d.%d.%d",
1070                     val[0], val[1], val[2], val[3]);
1071                 bsetprops(BP_ROUTER_IP, buf);
1072         }
1073 
1074         if (sip->sn_netmask != 0) {
1075                 val = (uint8_t *)&sip->sn_netmask;
1076                 (void) snprintf(buf, BUFLEN, "%d.%d.%d.%d",
1077                     val[0], val[1], val[2], val[3]);
1078                 bsetprops(BP_SUBNET_MASK, buf);
1079         }
1080 
1081         if (sip->sn_mactype != 4 || sip->sn_maclen != 6) {
1082                 bop_printf(NULL, "unsupported mac type %d, mac len %d\n",
1083                     sip->sn_mactype, sip->sn_maclen);
1084         } else {
1085                 val = sip->sn_macaddr;
1086                 (void) snprintf(buf, BUFLEN, "%x:%x:%x:%x:%x:%x",
1087                     val[0], val[1], val[2], val[3], val[4], val[5]);
1088                 bsetprops(BP_BOOT_MAC, buf);
1089         }
1090 }
1091 
1092 #endif  /* __xpv */
1093 
1094 static void
1095 build_panic_cmdline(const char *cmd, int cmdlen)
1096 {
1097         int proplen;
1098         size_t arglen;
1099 
1100         arglen = sizeof (fastreboot_onpanic_args);
1101         /*
1102          * If we allready have fastreboot-onpanic set to zero,
1103          * don't add them again.
1104          */
1105         if ((proplen = do_bsys_getproplen(NULL, FASTREBOOT_ONPANIC)) > 0 &&
1106             proplen <=  sizeof (fastreboot_onpanic_cmdline)) {
1107                 (void) do_bsys_getprop(NULL, FASTREBOOT_ONPANIC,
1108                     fastreboot_onpanic_cmdline);
1109                 if (FASTREBOOT_ONPANIC_NOTSET(fastreboot_onpanic_cmdline))
1110                         arglen = 1;
1111         }
1112 
1113         /*
1114          * construct fastreboot_onpanic_cmdline
1115          */
1116         if (cmdlen + arglen > sizeof (fastreboot_onpanic_cmdline)) {
1117                 DBG_MSG("Command line too long: clearing "
1118                     FASTREBOOT_ONPANIC "\n");
1119                 fastreboot_onpanic = 0;
1120         } else {
1121                 bcopy(cmd, fastreboot_onpanic_cmdline, cmdlen);
1122                 if (arglen != 1)
1123                         bcopy(fastreboot_onpanic_args,
1124                             fastreboot_onpanic_cmdline + cmdlen, arglen);
1125                 else
1126                         fastreboot_onpanic_cmdline[cmdlen] = 0;
1127         }
1128 }
1129 
1130 
1131 #ifndef __xpv
1132 /*
1133  * Construct boot command line for Fast Reboot
1134  */
1135 static void
1136 build_fastboot_cmdline(struct xboot_info *xbp)
1137 {
1138         saved_cmdline_len =  strlen(xbp->bi_cmdline) + 1;
1139         if (saved_cmdline_len > FASTBOOT_SAVED_CMDLINE_LEN) {
1140                 DBG(saved_cmdline_len);
1141                 DBG_MSG("Command line too long: clearing fastreboot_capable\n");
1142                 fastreboot_capable = 0;
1143         } else {
1144                 bcopy((void *)(xbp->bi_cmdline), (void *)saved_cmdline,
1145                     saved_cmdline_len);
1146                 saved_cmdline[saved_cmdline_len - 1] = '\0';
1147                 build_panic_cmdline(saved_cmdline, saved_cmdline_len - 1);
1148         }
1149 }
1150 
1151 /*
1152  * Save memory layout, disk drive information, unix and boot archive sizes for
1153  * Fast Reboot.
1154  */
1155 static void
1156 save_boot_info(struct xboot_info *xbi)
1157 {
1158         multiboot_info_t *mbi = xbi->bi_mb_info;
1159         struct boot_modules *modp;
1160         int i;
1161 
1162         bcopy(mbi, &saved_mbi, sizeof (multiboot_info_t));
1163         if (mbi->mmap_length > sizeof (saved_mmap)) {
1164                 DBG_MSG("mbi->mmap_length too big: clearing "
1165                     "fastreboot_capable\n");
1166                 fastreboot_capable = 0;
1167         } else {
1168                 bcopy((void *)(uintptr_t)mbi->mmap_addr, (void *)saved_mmap,
1169                     mbi->mmap_length);
1170         }
1171 
1172         if ((mbi->flags & MB_INFO_DRIVE_INFO) != 0) {
1173                 if (mbi->drives_length > sizeof (saved_drives)) {
1174                         DBG(mbi->drives_length);
1175                         DBG_MSG("mbi->drives_length too big: clearing "
1176                             "fastreboot_capable\n");
1177                         fastreboot_capable = 0;
1178                 } else {
1179                         bcopy((void *)(uintptr_t)mbi->drives_addr,
1180                             (void *)saved_drives, mbi->drives_length);
1181                 }
1182         } else {
1183                 saved_mbi.drives_length = 0;
1184                 saved_mbi.drives_addr = NULL;
1185         }
1186 
1187         /*
1188          * Current file sizes.  Used by fastboot.c to figure out how much
1189          * memory to reserve for panic reboot.
1190          * Use the module list from the dboot-constructed xboot_info
1191          * instead of the list referenced by the multiboot structure
1192          * because that structure may not be addressable now.
1193          */
1194         saved_file_size[FASTBOOT_NAME_UNIX] = FOUR_MEG - PAGESIZE;
1195         for (i = 0, modp = (struct boot_modules *)(uintptr_t)xbi->bi_modules;
1196             i < xbi->bi_module_cnt; i++, modp++) {
1197                 saved_file_size[FASTBOOT_NAME_BOOTARCHIVE] += modp->bm_size;
1198         }
1199 }
1200 #endif  /* __xpv */
1201 
1202 
1203 /*
1204  * 1st pass at building the table of boot properties. This includes:
1205  * - values set on the command line: -B a=x,b=y,c=z ....
1206  * - known values we just compute (ie. from xbp)
1207  * - values from /boot/solaris/bootenv.rc (ie. eeprom(1m) values)
1208  *
1209  * the grub command line looked like:
1210  * kernel boot-file [-B prop=value[,prop=value]...] [boot-args]
1211  *
1212  * whoami is the same as boot-file
1213  */
1214 static void
1215 build_boot_properties(struct xboot_info *xbp)
1216 {
1217         char *name;
1218         int name_len;
1219         char *value;
1220         int value_len;
1221         struct boot_modules *bm, *rdbm;
1222         char *propbuf;
1223         int quoted = 0;
1224         int boot_arg_len;
1225         uint_t i, midx;
1226         char modid[32];
1227 #ifndef __xpv
1228         static int stdout_val = 0;
1229         uchar_t boot_device;
1230         char str[3];
1231         multiboot_info_t *mbi;
1232         int netboot;
1233         struct sol_netinfo *sip;
1234 #endif
1235 
1236         /*
1237          * These have to be done first, so that kobj_mount_root() works
1238          */
1239         DBG_MSG("Building boot properties\n");
1240         propbuf = do_bsys_alloc(NULL, NULL, MMU_PAGESIZE, 0);
1241         DBG((uintptr_t)propbuf);
1242         if (xbp->bi_module_cnt > 0) {
1243                 bm = xbp->bi_modules;
1244                 rdbm = NULL;
1245                 for (midx = i = 0; i < xbp->bi_module_cnt; i++) {
1246                         if (bm[i].bm_type == BMT_ROOTFS) {
1247                                 rdbm = &bm[i];
1248                                 continue;
1249                         }
1250                         if (bm[i].bm_type == BMT_HASH || bm[i].bm_name == NULL)
1251                                 continue;
1252 
1253                         (void) snprintf(modid, sizeof (modid),
1254                             "module-name-%u", midx);
1255                         bsetprops(modid, (char *)bm[i].bm_name);
1256                         (void) snprintf(modid, sizeof (modid),
1257                             "module-addr-%u", midx);
1258                         bsetprop64(modid, (uint64_t)(uintptr_t)bm[i].bm_addr);
1259                         (void) snprintf(modid, sizeof (modid),
1260                             "module-size-%u", midx);
1261                         bsetprop64(modid, (uint64_t)bm[i].bm_size);
1262                         ++midx;
1263                 }
1264                 if (rdbm != NULL) {
1265                         bsetprop64("ramdisk_start",
1266                             (uint64_t)(uintptr_t)rdbm->bm_addr);
1267                         bsetprop64("ramdisk_end",
1268                             (uint64_t)(uintptr_t)rdbm->bm_addr + rdbm->bm_size);
1269                 }
1270         }
1271 
1272         /*
1273          * If there are any boot time modules or hashes present, then disable
1274          * fast reboot.
1275          */
1276         if (xbp->bi_module_cnt > 1) {
1277                 fastreboot_disable(FBNS_BOOTMOD);
1278         }
1279 
1280         DBG_MSG("Parsing command line for boot properties\n");
1281         value = xbp->bi_cmdline;
1282 
1283         /*
1284          * allocate memory to collect boot_args into
1285          */
1286         boot_arg_len = strlen(xbp->bi_cmdline) + 1;
1287         boot_args = do_bsys_alloc(NULL, NULL, boot_arg_len, MMU_PAGESIZE);
1288         boot_args[0] = 0;
1289         boot_arg_len = 0;
1290 
1291 #ifdef __xpv
1292         /*
1293          * Xen puts a lot of device information in front of the kernel name
1294          * let's grab them and make them boot properties.  The first
1295          * string w/o an "=" in it will be the boot-file property.
1296          */
1297         (void) strcpy(namebuf, "xpv-");
1298         for (;;) {
1299                 /*
1300                  * get to next property
1301                  */
1302                 while (ISSPACE(*value))
1303                         ++value;
1304                 name = value;
1305                 /*
1306                  * look for an "="
1307                  */
1308                 while (*value && !ISSPACE(*value) && *value != '=') {
1309                         value++;
1310                 }
1311                 if (*value != '=') { /* no "=" in the property */
1312                         value = name;
1313                         break;
1314                 }
1315                 name_len = value - name;
1316                 value_len = 0;
1317                 /*
1318                  * skip over the "="
1319                  */
1320                 value++;
1321                 while (value[value_len] && !ISSPACE(value[value_len])) {
1322                         ++value_len;
1323                 }
1324                 /*
1325                  * build property name with "xpv-" prefix
1326                  */
1327                 if (name_len + 4 > 32) { /* skip if name too long */
1328                         value += value_len;
1329                         continue;
1330                 }
1331                 bcopy(name, &namebuf[4], name_len);
1332                 name_len += 4;
1333                 namebuf[name_len] = 0;
1334                 bcopy(value, propbuf, value_len);
1335                 propbuf[value_len] = 0;
1336                 bsetprops(namebuf, propbuf);
1337 
1338                 /*
1339                  * xpv-root is set to the logical disk name of the xen
1340                  * VBD when booting from a disk-based filesystem.
1341                  */
1342                 if (strcmp(namebuf, "xpv-root") == 0)
1343                         xen_vbdroot_props(propbuf);
1344                 /*
1345                  * While we're here, if we have a "xpv-nfsroot" property
1346                  * then we need to set "fstype" to "nfs" so we mount
1347                  * our root from the nfs server.  Also parse the xpv-nfsroot
1348                  * property to create the properties that nfs_mountroot will
1349                  * need to find the root and mount it.
1350                  */
1351                 if (strcmp(namebuf, "xpv-nfsroot") == 0)
1352                         xen_nfsroot_props(propbuf);
1353 
1354                 if (strcmp(namebuf, "xpv-ip") == 0)
1355                         xen_ip_props(propbuf);
1356                 value += value_len;
1357         }
1358 #endif
1359 
1360         while (ISSPACE(*value))
1361                 ++value;
1362         /*
1363          * value now points at the boot-file
1364          */
1365         value_len = 0;
1366         while (value[value_len] && !ISSPACE(value[value_len]))
1367                 ++value_len;
1368         if (value_len > 0) {
1369                 whoami = propbuf;
1370                 bcopy(value, whoami, value_len);
1371                 whoami[value_len] = 0;
1372                 bsetprops("boot-file", whoami);
1373                 /*
1374                  * strip leading path stuff from whoami, so running from
1375                  * PXE/miniroot makes sense.
1376                  */
1377                 if (strstr(whoami, "/platform/") != NULL)
1378                         whoami = strstr(whoami, "/platform/");
1379                 bsetprops("whoami", whoami);
1380         }
1381 
1382         /*
1383          * Values forcibly set boot properties on the command line via -B.
1384          * Allow use of quotes in values. Other stuff goes on kernel
1385          * command line.
1386          */
1387         name = value + value_len;
1388         while (*name != 0) {
1389                 /*
1390                  * anything not " -B" is copied to the command line
1391                  */
1392                 if (!ISSPACE(name[0]) || name[1] != '-' || name[2] != 'B') {
1393                         boot_args[boot_arg_len++] = *name;
1394                         boot_args[boot_arg_len] = 0;
1395                         ++name;
1396                         continue;
1397                 }
1398 
1399                 /*
1400                  * skip the " -B" and following white space
1401                  */
1402                 name += 3;
1403                 while (ISSPACE(*name))
1404                         ++name;
1405                 while (*name && !ISSPACE(*name)) {
1406                         value = strstr(name, "=");
1407                         if (value == NULL)
1408                                 break;
1409                         name_len = value - name;
1410                         ++value;
1411                         value_len = 0;
1412                         quoted = 0;
1413                         for (; ; ++value_len) {
1414                                 if (!value[value_len])
1415                                         break;
1416 
1417                                 /*
1418                                  * is this value quoted?
1419                                  */
1420                                 if (value_len == 0 &&
1421                                     (value[0] == '\'' || value[0] == '"')) {
1422                                         quoted = value[0];
1423                                         ++value_len;
1424                                 }
1425 
1426                                 /*
1427                                  * In the quote accept any character,
1428                                  * but look for ending quote.
1429                                  */
1430                                 if (quoted) {
1431                                         if (value[value_len] == quoted)
1432                                                 quoted = 0;
1433                                         continue;
1434                                 }
1435 
1436                                 /*
1437                                  * a comma or white space ends the value
1438                                  */
1439                                 if (value[value_len] == ',' ||
1440                                     ISSPACE(value[value_len]))
1441                                         break;
1442                         }
1443 
1444                         if (value_len == 0) {
1445                                 bsetprop(name, name_len, "true", 5);
1446                         } else {
1447                                 char *v = value;
1448                                 int l = value_len;
1449                                 if (v[0] == v[l - 1] &&
1450                                     (v[0] == '\'' || v[0] == '"')) {
1451                                         ++v;
1452                                         l -= 2;
1453                                 }
1454                                 bcopy(v, propbuf, l);
1455                                 propbuf[l] = '\0';
1456                                 bsetprop(name, name_len, propbuf,
1457                                     l + 1);
1458                         }
1459                         name = value + value_len;
1460                         while (*name == ',')
1461                                 ++name;
1462                 }
1463         }
1464 
1465         /*
1466          * set boot-args property
1467          * 1275 name is bootargs, so set
1468          * that too
1469          */
1470         bsetprops("boot-args", boot_args);
1471         bsetprops("bootargs", boot_args);
1472 
1473 #ifndef __xpv
1474         /*
1475          * set the BIOS boot device from GRUB
1476          */
1477         netboot = 0;
1478         mbi = xbp->bi_mb_info;
1479 
1480         /*
1481          * Build boot command line for Fast Reboot
1482          */
1483         build_fastboot_cmdline(xbp);
1484 
1485         /*
1486          * Save various boot information for Fast Reboot
1487          */
1488         save_boot_info(xbp);
1489 
1490         if (mbi != NULL && mbi->flags & MB_INFO_BOOTDEV) {
1491                 boot_device = mbi->boot_device >> 24;
1492                 if (boot_device == 0x20)
1493                         netboot++;
1494                 str[0] = (boot_device >> 4) + '0';
1495                 str[1] = (boot_device & 0xf) + '0';
1496                 str[2] = 0;
1497                 bsetprops("bios-boot-device", str);
1498         } else {
1499                 netboot = 1;
1500         }
1501 
1502         /*
1503          * In the netboot case, drives_info is overloaded with the dhcp ack.
1504          * This is not multiboot compliant and requires special pxegrub!
1505          */
1506         if (netboot && mbi->drives_length != 0) {
1507                 sip = (struct sol_netinfo *)(uintptr_t)mbi->drives_addr;
1508                 if (sip->sn_infotype == SN_TYPE_BOOTP)
1509                         bsetprop("bootp-response", sizeof ("bootp-response"),
1510                             (void *)(uintptr_t)mbi->drives_addr,
1511                             mbi->drives_length);
1512                 else if (sip->sn_infotype == SN_TYPE_RARP)
1513                         setup_rarp_props(sip);
1514         }
1515         bsetprop("stdout", strlen("stdout"),
1516             &stdout_val, sizeof (stdout_val));
1517 #endif /* __xpv */
1518 
1519         /*
1520          * more conjured up values for made up things....
1521          */
1522 #if defined(__xpv)
1523         bsetprops("mfg-name", "i86xpv");
1524         bsetprops("impl-arch-name", "i86xpv");
1525 #else
1526         bsetprops("mfg-name", "i86pc");
1527         bsetprops("impl-arch-name", "i86pc");
1528 #endif
1529 
1530         /*
1531          * Build firmware-provided system properties
1532          */
1533         build_firmware_properties();
1534 
1535         /*
1536          * XXPV
1537          *
1538          * Find out what these are:
1539          * - cpuid_feature_ecx_include
1540          * - cpuid_feature_ecx_exclude
1541          * - cpuid_feature_edx_include
1542          * - cpuid_feature_edx_exclude
1543          *
1544          * Find out what these are in multiboot:
1545          * - netdev-path
1546          * - fstype
1547          */
1548 }
1549 
1550 #ifdef __xpv
1551 /*
1552  * Under the Hypervisor, memory usable for DMA may be scarce. One
1553  * very likely large pool of DMA friendly memory is occupied by
1554  * the boot_archive, as it was loaded by grub into low MFNs.
1555  *
1556  * Here we free up that memory by copying the boot archive to what are
1557  * likely higher MFN pages and then swapping the mfn/pfn mappings.
1558  */
1559 #define PFN_2GIG        0x80000
1560 static void
1561 relocate_boot_archive(struct xboot_info *xbp)
1562 {
1563         mfn_t max_mfn = HYPERVISOR_memory_op(XENMEM_maximum_ram_page, NULL);
1564         struct boot_modules *bm = xbp->bi_modules;
1565         uintptr_t va;
1566         pfn_t va_pfn;
1567         mfn_t va_mfn;
1568         caddr_t copy;
1569         pfn_t copy_pfn;
1570         mfn_t copy_mfn;
1571         size_t  len;
1572         int slop;
1573         int total = 0;
1574         int relocated = 0;
1575         int mmu_update_return;
1576         mmu_update_t t[2];
1577         x86pte_t pte;
1578 
1579         /*
1580          * If all MFN's are below 2Gig, don't bother doing this.
1581          */
1582         if (max_mfn < PFN_2GIG)
1583                 return;
1584         if (xbp->bi_module_cnt < 1) {
1585                 DBG_MSG("no boot_archive!");
1586                 return;
1587         }
1588 
1589         DBG_MSG("moving boot_archive to high MFN memory\n");
1590         va = (uintptr_t)bm->bm_addr;
1591         len = bm->bm_size;
1592         slop = va & MMU_PAGEOFFSET;
1593         if (slop) {
1594                 va += MMU_PAGESIZE - slop;
1595                 len -= MMU_PAGESIZE - slop;
1596         }
1597         len = P2ALIGN(len, MMU_PAGESIZE);
1598 
1599         /*
1600          * Go through all boot_archive pages, swapping any low MFN pages
1601          * with memory at next_phys.
1602          */
1603         while (len != 0) {
1604                 ++total;
1605                 va_pfn = mmu_btop(va - ONE_GIG);
1606                 va_mfn = mfn_list[va_pfn];
1607                 if (mfn_list[va_pfn] < PFN_2GIG) {
1608                         copy = kbm_remap_window(next_phys, 1);
1609                         bcopy((void *)va, copy, MMU_PAGESIZE);
1610                         copy_pfn = mmu_btop(next_phys);
1611                         copy_mfn = mfn_list[copy_pfn];
1612 
1613                         pte = mfn_to_ma(copy_mfn) | PT_NOCONSIST | PT_VALID;
1614                         if (HYPERVISOR_update_va_mapping(va, pte,
1615                             UVMF_INVLPG | UVMF_LOCAL))
1616                                 bop_panic("relocate_boot_archive():  "
1617                                     "HYPERVISOR_update_va_mapping() failed");
1618 
1619                         mfn_list[va_pfn] = copy_mfn;
1620                         mfn_list[copy_pfn] = va_mfn;
1621 
1622                         t[0].ptr = mfn_to_ma(copy_mfn) | MMU_MACHPHYS_UPDATE;
1623                         t[0].val = va_pfn;
1624                         t[1].ptr = mfn_to_ma(va_mfn) | MMU_MACHPHYS_UPDATE;
1625                         t[1].val = copy_pfn;
1626                         if (HYPERVISOR_mmu_update(t, 2, &mmu_update_return,
1627                             DOMID_SELF) != 0 || mmu_update_return != 2)
1628                                 bop_panic("relocate_boot_archive():  "
1629                                     "HYPERVISOR_mmu_update() failed");
1630 
1631                         next_phys += MMU_PAGESIZE;
1632                         ++relocated;
1633                 }
1634                 len -= MMU_PAGESIZE;
1635                 va += MMU_PAGESIZE;
1636         }
1637         DBG_MSG("Relocated pages:\n");
1638         DBG(relocated);
1639         DBG_MSG("Out of total pages:\n");
1640         DBG(total);
1641 }
1642 #endif /* __xpv */
1643 
1644 #if !defined(__xpv)
1645 /*
1646  * Install a temporary IDT that lets us catch errors in the boot time code.
1647  * We shouldn't get any faults at all while this is installed, so we'll
1648  * just generate a traceback and exit.
1649  */
1650 #ifdef __amd64
1651 static const int bcode_sel = B64CODE_SEL;
1652 #else
1653 static const int bcode_sel = B32CODE_SEL;
1654 #endif
1655 
1656 /*
1657  * simple description of a stack frame (args are 32 bit only currently)
1658  */
1659 typedef struct bop_frame {
1660         struct bop_frame *old_frame;
1661         pc_t retaddr;
1662         long arg[1];
1663 } bop_frame_t;
1664 
1665 void
1666 bop_traceback(bop_frame_t *frame)
1667 {
1668         pc_t pc;
1669         int cnt;
1670         char *ksym;
1671         ulong_t off;
1672 #if defined(__i386)
1673         int a;
1674 #endif
1675 
1676         bop_printf(NULL, "Stack traceback:\n");
1677         for (cnt = 0; cnt < 30; ++cnt) {     /* up to 30 frames */
1678                 pc = frame->retaddr;
1679                 if (pc == 0)
1680                         break;
1681                 ksym = kobj_getsymname(pc, &off);
1682                 if (ksym)
1683                         bop_printf(NULL, "  %s+%lx", ksym, off);
1684                 else
1685                         bop_printf(NULL, "  0x%lx", pc);
1686 
1687                 frame = frame->old_frame;
1688                 if (frame == 0) {
1689                         bop_printf(NULL, "\n");
1690                         break;
1691                 }
1692 #if defined(__i386)
1693                 for (a = 0; a < 6; ++a) {    /* try for 6 args */
1694                         if ((void *)&frame->arg[a] == (void *)frame->old_frame)
1695                                 break;
1696                         if (a == 0)
1697                                 bop_printf(NULL, "(");
1698                         else
1699                                 bop_printf(NULL, ",");
1700                         bop_printf(NULL, "0x%lx", frame->arg[a]);
1701                 }
1702                 bop_printf(NULL, ")");
1703 #endif
1704                 bop_printf(NULL, "\n");
1705         }
1706 }
1707 
1708 struct trapframe {
1709         ulong_t error_code;     /* optional */
1710         ulong_t inst_ptr;
1711         ulong_t code_seg;
1712         ulong_t flags_reg;
1713 #ifdef __amd64
1714         ulong_t stk_ptr;
1715         ulong_t stk_seg;
1716 #endif
1717 };
1718 
1719 void
1720 bop_trap(ulong_t *tfp)
1721 {
1722         struct trapframe *tf = (struct trapframe *)tfp;
1723         bop_frame_t fakeframe;
1724         static int depth = 0;
1725 
1726         /*
1727          * Check for an infinite loop of traps.
1728          */
1729         if (++depth > 2)
1730                 bop_panic("Nested trap");
1731 
1732         bop_printf(NULL, "Unexpected trap\n");
1733 
1734         /*
1735          * adjust the tf for optional error_code by detecting the code selector
1736          */
1737         if (tf->code_seg != bcode_sel)
1738                 tf = (struct trapframe *)(tfp - 1);
1739         else
1740                 bop_printf(NULL, "error code           0x%lx\n",
1741                     tf->error_code & 0xffffffff);
1742 
1743         bop_printf(NULL, "instruction pointer  0x%lx\n", tf->inst_ptr);
1744         bop_printf(NULL, "code segment         0x%lx\n", tf->code_seg & 0xffff);
1745         bop_printf(NULL, "flags register       0x%lx\n", tf->flags_reg);
1746 #ifdef __amd64
1747         bop_printf(NULL, "return %%rsp          0x%lx\n", tf->stk_ptr);
1748         bop_printf(NULL, "return %%ss           0x%lx\n", tf->stk_seg & 0xffff);
1749 #endif
1750 
1751         /* grab %[er]bp pushed by our code from the stack */
1752         fakeframe.old_frame = (bop_frame_t *)*(tfp - 3);
1753         fakeframe.retaddr = (pc_t)tf->inst_ptr;
1754         bop_printf(NULL, "Attempting stack backtrace:\n");
1755         bop_traceback(&fakeframe);
1756         bop_panic("unexpected trap in early boot");
1757 }
1758 
1759 extern void bop_trap_handler(void);
1760 
1761 static gate_desc_t *bop_idt;
1762 
1763 static desctbr_t bop_idt_info;
1764 
1765 static void
1766 bop_idt_init(void)
1767 {
1768         int t;
1769 
1770         bop_idt = (gate_desc_t *)
1771             do_bsys_alloc(NULL, NULL, MMU_PAGESIZE, MMU_PAGESIZE);
1772         bzero(bop_idt, MMU_PAGESIZE);
1773         for (t = 0; t < NIDT; ++t) {
1774                 /*
1775                  * Note that since boot runs without a TSS, the
1776                  * double fault handler cannot use an alternate stack
1777                  * (64-bit) or a task gate (32-bit).
1778                  */
1779                 set_gatesegd(&bop_idt[t], &bop_trap_handler, bcode_sel,
1780                     SDT_SYSIGT, TRP_KPL, 0);
1781         }
1782         bop_idt_info.dtr_limit = (NIDT * sizeof (gate_desc_t)) - 1;
1783         bop_idt_info.dtr_base = (uintptr_t)bop_idt;
1784         wr_idtr(&bop_idt_info);
1785 }
1786 #endif  /* !defined(__xpv) */
1787 
1788 /*
1789  * This is where we enter the kernel. It dummies up the boot_ops and
1790  * boot_syscalls vectors and jumps off to _kobj_boot()
1791  */
1792 void
1793 _start(struct xboot_info *xbp)
1794 {
1795         bootops_t *bops = &bootop;
1796         extern void _kobj_boot();
1797 
1798         /*
1799          * 1st off - initialize the console for any error messages
1800          */
1801         xbootp = xbp;
1802 #ifdef __xpv
1803         HYPERVISOR_shared_info = (void *)xbp->bi_shared_info;
1804         xen_info = xbp->bi_xen_start_info;
1805 #endif
1806 
1807 #ifndef __xpv
1808         if (*((uint32_t *)(FASTBOOT_SWTCH_PA + FASTBOOT_STACK_OFFSET)) ==
1809             FASTBOOT_MAGIC) {
1810                 post_fastreboot = 1;
1811                 *((uint32_t *)(FASTBOOT_SWTCH_PA + FASTBOOT_STACK_OFFSET)) = 0;
1812         }
1813 #endif
1814 
1815         bcons_init((void *)xbp->bi_cmdline);
1816         have_console = 1;
1817 
1818         /*
1819          * enable debugging
1820          */
1821         if (strstr((char *)xbp->bi_cmdline, "kbm_debug"))
1822                 kbm_debug = 1;
1823 
1824         DBG_MSG("\n\n*** Entered Solaris in _start() cmdline is: ");
1825         DBG_MSG((char *)xbp->bi_cmdline);
1826         DBG_MSG("\n\n\n");
1827 
1828         /*
1829          * physavail is no longer used by startup
1830          */
1831         bm.physinstalled = xbp->bi_phys_install;
1832         bm.pcimem = xbp->bi_pcimem;
1833         bm.rsvdmem = xbp->bi_rsvdmem;
1834         bm.physavail = NULL;
1835 
1836         /*
1837          * initialize the boot time allocator
1838          */
1839         next_phys = xbp->bi_next_paddr;
1840         DBG(next_phys);
1841         next_virt = (uintptr_t)xbp->bi_next_vaddr;
1842         DBG(next_virt);
1843         DBG_MSG("Initializing boot time memory management...");
1844 #ifdef __xpv
1845         {
1846                 xen_platform_parameters_t p;
1847 
1848                 /* This call shouldn't fail, dboot already did it once. */
1849                 (void) HYPERVISOR_xen_version(XENVER_platform_parameters, &p);
1850                 mfn_to_pfn_mapping = (pfn_t *)(xen_virt_start = p.virt_start);
1851                 DBG(xen_virt_start);
1852         }
1853 #endif
1854         kbm_init(xbp);
1855         DBG_MSG("done\n");
1856 
1857         /*
1858          * Fill in the bootops vector
1859          */
1860         bops->bsys_version = BO_VERSION;
1861         bops->boot_mem = &bm;
1862         bops->bsys_alloc = do_bsys_alloc;
1863         bops->bsys_free = do_bsys_free;
1864         bops->bsys_getproplen = do_bsys_getproplen;
1865         bops->bsys_getprop = do_bsys_getprop;
1866         bops->bsys_nextprop = do_bsys_nextprop;
1867         bops->bsys_printf = bop_printf;
1868         bops->bsys_doint = do_bsys_doint;
1869 
1870         /*
1871          * BOP_EALLOC() is no longer needed
1872          */
1873         bops->bsys_ealloc = do_bsys_ealloc;
1874 
1875 #ifdef __xpv
1876         /*
1877          * On domain 0 we need to free up some physical memory that is
1878          * usable for DMA. Since GRUB loaded the boot_archive, it is
1879          * sitting in low MFN memory. We'll relocated the boot archive
1880          * pages to high PFN memory.
1881          */
1882         if (DOMAIN_IS_INITDOMAIN(xen_info))
1883                 relocate_boot_archive(xbp);
1884 #endif
1885 
1886 #ifndef __xpv
1887         /*
1888          * Install an IDT to catch early pagefaults (shouldn't have any).
1889          * Also needed for kmdb.
1890          */
1891         bop_idt_init();
1892 #endif
1893 
1894         /*
1895          * Start building the boot properties from the command line
1896          */
1897         DBG_MSG("Initializing boot properties:\n");
1898         build_boot_properties(xbp);
1899 
1900         if (strstr((char *)xbp->bi_cmdline, "prom_debug") || kbm_debug) {
1901                 char *value;
1902 
1903                 value = do_bsys_alloc(NULL, NULL, MMU_PAGESIZE, MMU_PAGESIZE);
1904                 boot_prop_display(value);
1905         }
1906 
1907         /*
1908          * jump into krtld...
1909          */
1910         _kobj_boot(&bop_sysp, NULL, bops, NULL);
1911 }
1912 
1913 
1914 /*ARGSUSED*/
1915 static caddr_t
1916 no_more_alloc(bootops_t *bop, caddr_t virthint, size_t size, int align)
1917 {
1918         panic("Attempt to bsys_alloc() too late\n");
1919         return (NULL);
1920 }
1921 
1922 /*ARGSUSED*/
1923 static void
1924 no_more_free(bootops_t *bop, caddr_t virt, size_t size)
1925 {
1926         panic("Attempt to bsys_free() too late\n");
1927 }
1928 
1929 void
1930 bop_no_more_mem(void)
1931 {
1932         DBG(total_bop_alloc_scratch);
1933         DBG(total_bop_alloc_kernel);
1934         bootops->bsys_alloc = no_more_alloc;
1935         bootops->bsys_free = no_more_free;
1936 }
1937 
1938 
1939 /*
1940  * Set ACPI firmware properties
1941  */
1942 
1943 static caddr_t
1944 vmap_phys(size_t length, paddr_t pa)
1945 {
1946         paddr_t start, end;
1947         caddr_t va;
1948         size_t  len, page;
1949 
1950 #ifdef __xpv
1951         pa = pfn_to_pa(xen_assign_pfn(mmu_btop(pa))) | (pa & MMU_PAGEOFFSET);
1952 #endif
1953         start = P2ALIGN(pa, MMU_PAGESIZE);
1954         end = P2ROUNDUP(pa + length, MMU_PAGESIZE);
1955         len = end - start;
1956         va = (caddr_t)alloc_vaddr(len, MMU_PAGESIZE);
1957         for (page = 0; page < len; page += MMU_PAGESIZE)
1958                 kbm_map((uintptr_t)va + page, start + page, 0, 0);
1959         return (va + (pa & MMU_PAGEOFFSET));
1960 }
1961 
1962 static uint8_t
1963 checksum_table(uint8_t *tp, size_t len)
1964 {
1965         uint8_t sum = 0;
1966 
1967         while (len-- > 0)
1968                 sum += *tp++;
1969 
1970         return (sum);
1971 }
1972 
1973 static int
1974 valid_rsdp(ACPI_TABLE_RSDP *rp)
1975 {
1976 
1977         /* validate the V1.x checksum */
1978         if (checksum_table((uint8_t *)rp, ACPI_RSDP_CHECKSUM_LENGTH) != 0)
1979                 return (0);
1980 
1981         /* If pre-ACPI 2.0, this is a valid RSDP */
1982         if (rp->Revision < 2)
1983                 return (1);
1984 
1985         /* validate the V2.x checksum */
1986         if (checksum_table((uint8_t *)rp, ACPI_RSDP_XCHECKSUM_LENGTH) != 0)
1987                 return (0);
1988 
1989         return (1);
1990 }
1991 
1992 /*
1993  * Scan memory range for an RSDP;
1994  * see ACPI 3.0 Spec, 5.2.5.1
1995  */
1996 static ACPI_TABLE_RSDP *
1997 scan_rsdp(paddr_t start, paddr_t end)
1998 {
1999         ssize_t len  = end - start;
2000         caddr_t ptr;
2001 
2002         ptr = vmap_phys(len, start);
2003         while (len > 0) {
2004                 if (strncmp(ptr, ACPI_SIG_RSDP, strlen(ACPI_SIG_RSDP)) == 0 &&
2005                     valid_rsdp((ACPI_TABLE_RSDP *)ptr))
2006                         return ((ACPI_TABLE_RSDP *)ptr);
2007 
2008                 ptr += ACPI_RSDP_SCAN_STEP;
2009                 len -= ACPI_RSDP_SCAN_STEP;
2010         }
2011 
2012         return (NULL);
2013 }
2014 
2015 /*
2016  * Refer to ACPI 3.0 Spec, section 5.2.5.1 to understand this function
2017  */
2018 static ACPI_TABLE_RSDP *
2019 find_rsdp()
2020 {
2021         ACPI_TABLE_RSDP *rsdp;
2022         uint16_t *ebda_seg;
2023         paddr_t  ebda_addr;
2024 
2025         /*
2026          * Get the EBDA segment and scan the first 1K
2027          */
2028         ebda_seg = (uint16_t *)vmap_phys(sizeof (uint16_t),
2029             ACPI_EBDA_PTR_LOCATION);
2030         ebda_addr = *ebda_seg << 4;
2031         rsdp = scan_rsdp(ebda_addr, ebda_addr + ACPI_EBDA_WINDOW_SIZE);
2032         if (rsdp == NULL)
2033                 /* if EBDA doesn't contain RSDP, look in BIOS memory */
2034                 rsdp = scan_rsdp(ACPI_HI_RSDP_WINDOW_BASE,
2035                     ACPI_HI_RSDP_WINDOW_BASE + ACPI_HI_RSDP_WINDOW_SIZE);
2036         return (rsdp);
2037 }
2038 
2039 static ACPI_TABLE_HEADER *
2040 map_fw_table(paddr_t table_addr)
2041 {
2042         ACPI_TABLE_HEADER *tp;
2043         size_t len = MAX(sizeof (*tp), MMU_PAGESIZE);
2044 
2045         /*
2046          * Map at least a page; if the table is larger than this, remap it
2047          */
2048         tp = (ACPI_TABLE_HEADER *)vmap_phys(len, table_addr);
2049         if (tp->Length > len)
2050                 tp = (ACPI_TABLE_HEADER *)vmap_phys(tp->Length, table_addr);
2051         return (tp);
2052 }
2053 
2054 static ACPI_TABLE_HEADER *
2055 find_fw_table(char *signature)
2056 {
2057         static int revision = 0;
2058         static ACPI_TABLE_XSDT *xsdt;
2059         static int len;
2060         paddr_t xsdt_addr;
2061         ACPI_TABLE_RSDP *rsdp;
2062         ACPI_TABLE_HEADER *tp;
2063         paddr_t table_addr;
2064         int     n;
2065 
2066         if (strlen(signature) != ACPI_NAME_SIZE)
2067                 return (NULL);
2068 
2069         /*
2070          * Reading the ACPI 3.0 Spec, section 5.2.5.3 will help
2071          * understand this code.  If we haven't already found the RSDT/XSDT,
2072          * revision will be 0. Find the RSDP and check the revision
2073          * to find out whether to use the RSDT or XSDT.  If revision is
2074          * 0 or 1, use the RSDT and set internal revision to 1; if it is 2,
2075          * use the XSDT.  If the XSDT address is 0, though, fall back to
2076          * revision 1 and use the RSDT.
2077          */
2078         if (revision == 0) {
2079                 if ((rsdp = find_rsdp()) != NULL) {
2080                         revision = rsdp->Revision;
2081                         /*
2082                          * ACPI 6.0 states that current revision is 2
2083                          * from acpi_table_rsdp definition:
2084                          * Must be (0) for ACPI 1.0 or (2) for ACPI 2.0+
2085                          */
2086                         if (revision > 2)
2087                                 revision = 2;
2088                         switch (revision) {
2089                         case 2:
2090                                 /*
2091                                  * Use the XSDT unless BIOS is buggy and
2092                                  * claims to be rev 2 but has a null XSDT
2093                                  * address
2094                                  */
2095                                 xsdt_addr = rsdp->XsdtPhysicalAddress;
2096                                 if (xsdt_addr != 0)
2097                                         break;
2098                                 /* FALLTHROUGH */
2099                         case 0:
2100                                 /* treat RSDP rev 0 as revision 1 internally */
2101                                 revision = 1;
2102                                 /* FALLTHROUGH */
2103                         case 1:
2104                                 /* use the RSDT for rev 0/1 */
2105                                 xsdt_addr = rsdp->RsdtPhysicalAddress;
2106                                 break;
2107                         default:
2108                                 /* unknown revision */
2109                                 revision = 0;
2110                                 break;
2111                         }
2112                 }
2113                 if (revision == 0)
2114                         return (NULL);
2115 
2116                 /* cache the XSDT info */
2117                 xsdt = (ACPI_TABLE_XSDT *)map_fw_table(xsdt_addr);
2118                 len = (xsdt->Header.Length - sizeof (xsdt->Header)) /
2119                     ((revision == 1) ? sizeof (uint32_t) : sizeof (uint64_t));
2120         }
2121 
2122         /*
2123          * Scan the table headers looking for a signature match
2124          */
2125         for (n = 0; n < len; n++) {
2126                 ACPI_TABLE_RSDT *rsdt = (ACPI_TABLE_RSDT *)xsdt;
2127                 table_addr = (revision == 1) ? rsdt->TableOffsetEntry[n] :
2128                     xsdt->TableOffsetEntry[n];
2129 
2130                 if (table_addr == 0)
2131                         continue;
2132                 tp = map_fw_table(table_addr);
2133                 if (strncmp(tp->Signature, signature, ACPI_NAME_SIZE) == 0) {
2134                         return (tp);
2135                 }
2136         }
2137         return (NULL);
2138 }
2139 
2140 static void
2141 process_mcfg(ACPI_TABLE_MCFG *tp)
2142 {
2143         ACPI_MCFG_ALLOCATION *cfg_baap;
2144         char *cfg_baa_endp;
2145         int64_t ecfginfo[4];
2146 
2147         cfg_baap = (ACPI_MCFG_ALLOCATION *)((uintptr_t)tp + sizeof (*tp));
2148         cfg_baa_endp = ((char *)tp) + tp->Header.Length;
2149         while ((char *)cfg_baap < cfg_baa_endp) {
2150                 if (cfg_baap->Address != 0 && cfg_baap->PciSegment == 0) {
2151                         ecfginfo[0] = cfg_baap->Address;
2152                         ecfginfo[1] = cfg_baap->PciSegment;
2153                         ecfginfo[2] = cfg_baap->StartBusNumber;
2154                         ecfginfo[3] = cfg_baap->EndBusNumber;
2155                         bsetprop(MCFG_PROPNAME, strlen(MCFG_PROPNAME),
2156                             ecfginfo, sizeof (ecfginfo));
2157                         break;
2158                 }
2159                 cfg_baap++;
2160         }
2161 }
2162 
2163 #ifndef __xpv
2164 static void
2165 process_madt_entries(ACPI_TABLE_MADT *tp, uint32_t *cpu_countp,
2166     uint32_t *cpu_possible_countp, uint32_t *cpu_apicid_array)
2167 {
2168         ACPI_SUBTABLE_HEADER *item, *end;
2169         uint32_t cpu_count = 0;
2170         uint32_t cpu_possible_count = 0;
2171 
2172         /*
2173          * Determine number of CPUs and keep track of "final" APIC ID
2174          * for each CPU by walking through ACPI MADT processor list
2175          */
2176         end = (ACPI_SUBTABLE_HEADER *)(tp->Header.Length + (uintptr_t)tp);
2177         item = (ACPI_SUBTABLE_HEADER *)((uintptr_t)tp + sizeof (*tp));
2178 
2179         while (item < end) {
2180                 switch (item->Type) {
2181                 case ACPI_MADT_TYPE_LOCAL_APIC: {
2182                         ACPI_MADT_LOCAL_APIC *cpu =
2183                             (ACPI_MADT_LOCAL_APIC *) item;
2184 
2185                         if (cpu->LapicFlags & ACPI_MADT_ENABLED) {
2186                                 if (cpu_apicid_array != NULL)
2187                                         cpu_apicid_array[cpu_count] = cpu->Id;
2188                                 cpu_count++;
2189                         }
2190                         cpu_possible_count++;
2191                         break;
2192                 }
2193                 case ACPI_MADT_TYPE_LOCAL_X2APIC: {
2194                         ACPI_MADT_LOCAL_X2APIC *cpu =
2195                             (ACPI_MADT_LOCAL_X2APIC *) item;
2196 
2197                         if (cpu->LapicFlags & ACPI_MADT_ENABLED) {
2198                                 if (cpu_apicid_array != NULL)
2199                                         cpu_apicid_array[cpu_count] =
2200                                             cpu->LocalApicId;
2201                                 cpu_count++;
2202                         }
2203                         cpu_possible_count++;
2204                         break;
2205                 }
2206                 default:
2207                         if (kbm_debug)
2208                                 bop_printf(NULL, "MADT type %d\n", item->Type);
2209                         break;
2210                 }
2211 
2212                 item = (ACPI_SUBTABLE_HEADER *)((uintptr_t)item + item->Length);
2213         }
2214         if (cpu_countp)
2215                 *cpu_countp = cpu_count;
2216         if (cpu_possible_countp)
2217                 *cpu_possible_countp = cpu_possible_count;
2218 }
2219 
2220 static void
2221 process_madt(ACPI_TABLE_MADT *tp)
2222 {
2223         uint32_t cpu_count = 0;
2224         uint32_t cpu_possible_count = 0;
2225         uint32_t *cpu_apicid_array; /* x2APIC ID is 32bit! */
2226 
2227         if (tp != NULL) {
2228                 /* count cpu's */
2229                 process_madt_entries(tp, &cpu_count, &cpu_possible_count, NULL);
2230 
2231                 cpu_apicid_array = (uint32_t *)do_bsys_alloc(NULL, NULL,
2232                     cpu_count * sizeof (*cpu_apicid_array), MMU_PAGESIZE);
2233                 if (cpu_apicid_array == NULL)
2234                         bop_panic("Not enough memory for APIC ID array");
2235 
2236                 /* copy IDs */
2237                 process_madt_entries(tp, NULL, NULL, cpu_apicid_array);
2238 
2239                 /*
2240                  * Make boot property for array of "final" APIC IDs for each
2241                  * CPU
2242                  */
2243                 bsetprop(BP_CPU_APICID_ARRAY, strlen(BP_CPU_APICID_ARRAY),
2244                     cpu_apicid_array, cpu_count * sizeof (*cpu_apicid_array));
2245         }
2246 
2247         /*
2248          * Check whether property plat-max-ncpus is already set.
2249          */
2250         if (do_bsys_getproplen(NULL, PLAT_MAX_NCPUS_NAME) < 0) {
2251                 /*
2252                  * Set plat-max-ncpus to number of maximum possible CPUs given
2253                  * in MADT if it hasn't been set.
2254                  * There's no formal way to detect max possible CPUs supported
2255                  * by platform according to ACPI spec3.0b. So current CPU
2256                  * hotplug implementation expects that all possible CPUs will
2257                  * have an entry in MADT table and set plat-max-ncpus to number
2258                  * of entries in MADT.
2259                  * With introducing of ACPI4.0, Maximum System Capability Table
2260                  * (MSCT) provides maximum number of CPUs supported by platform.
2261                  * If MSCT is unavailable, fall back to old way.
2262                  */
2263                 if (tp != NULL)
2264                         bsetpropsi(PLAT_MAX_NCPUS_NAME, cpu_possible_count);
2265         }
2266 
2267         /*
2268          * Set boot property boot-max-ncpus to number of CPUs existing at
2269          * boot time. boot-max-ncpus is mainly used for optimization.
2270          */
2271         if (tp != NULL)
2272                 bsetpropsi(BOOT_MAX_NCPUS_NAME, cpu_count);
2273 
2274         /*
2275          * User-set boot-ncpus overrides firmware count
2276          */
2277         if (do_bsys_getproplen(NULL, BOOT_NCPUS_NAME) >= 0)
2278                 return;
2279 
2280         /*
2281          * Set boot property boot-ncpus to number of active CPUs given in MADT
2282          * if it hasn't been set yet.
2283          */
2284         if (tp != NULL)
2285                 bsetpropsi(BOOT_NCPUS_NAME, cpu_count);
2286 }
2287 
2288 static void
2289 process_srat(ACPI_TABLE_SRAT *tp)
2290 {
2291         ACPI_SUBTABLE_HEADER *item, *end;
2292         int i;
2293         int proc_num, mem_num;
2294 #pragma pack(1)
2295         struct {
2296                 uint32_t domain;
2297                 uint32_t apic_id;
2298                 uint32_t sapic_id;
2299         } processor;
2300         struct {
2301                 uint32_t domain;
2302                 uint32_t x2apic_id;
2303         } x2apic;
2304         struct {
2305                 uint32_t domain;
2306                 uint64_t addr;
2307                 uint64_t length;
2308                 uint32_t flags;
2309         } memory;
2310 #pragma pack()
2311         char prop_name[30];
2312         uint64_t maxmem = 0;
2313 
2314         if (tp == NULL)
2315                 return;
2316 
2317         proc_num = mem_num = 0;
2318         end = (ACPI_SUBTABLE_HEADER *)(tp->Header.Length + (uintptr_t)tp);
2319         item = (ACPI_SUBTABLE_HEADER *)((uintptr_t)tp + sizeof (*tp));
2320         while (item < end) {
2321                 switch (item->Type) {
2322                 case ACPI_SRAT_TYPE_CPU_AFFINITY: {
2323                         ACPI_SRAT_CPU_AFFINITY *cpu =
2324                             (ACPI_SRAT_CPU_AFFINITY *) item;
2325 
2326                         if (!(cpu->Flags & ACPI_SRAT_CPU_ENABLED))
2327                                 break;
2328                         processor.domain = cpu->ProximityDomainLo;
2329                         for (i = 0; i < 3; i++)
2330                                 processor.domain +=
2331                                     cpu->ProximityDomainHi[i] << ((i + 1) * 8);
2332                         processor.apic_id = cpu->ApicId;
2333                         processor.sapic_id = cpu->LocalSapicEid;
2334                         (void) snprintf(prop_name, 30, "acpi-srat-processor-%d",
2335                             proc_num);
2336                         bsetprop(prop_name, strlen(prop_name), &processor,
2337                             sizeof (processor));
2338                         proc_num++;
2339                         break;
2340                 }
2341                 case ACPI_SRAT_TYPE_MEMORY_AFFINITY: {
2342                         ACPI_SRAT_MEM_AFFINITY *mem =
2343                             (ACPI_SRAT_MEM_AFFINITY *)item;
2344 
2345                         if (!(mem->Flags & ACPI_SRAT_MEM_ENABLED))
2346                                 break;
2347                         memory.domain = mem->ProximityDomain;
2348                         memory.addr = mem->BaseAddress;
2349                         memory.length = mem->Length;
2350                         memory.flags = mem->Flags;
2351                         (void) snprintf(prop_name, 30, "acpi-srat-memory-%d",
2352                             mem_num);
2353                         bsetprop(prop_name, strlen(prop_name), &memory,
2354                             sizeof (memory));
2355                         if ((mem->Flags & ACPI_SRAT_MEM_HOT_PLUGGABLE) &&
2356                             (memory.addr + memory.length > maxmem)) {
2357                                 maxmem = memory.addr + memory.length;
2358                         }
2359                         mem_num++;
2360                         break;
2361                 }
2362                 case ACPI_SRAT_TYPE_X2APIC_CPU_AFFINITY: {
2363                         ACPI_SRAT_X2APIC_CPU_AFFINITY *x2cpu =
2364                             (ACPI_SRAT_X2APIC_CPU_AFFINITY *) item;
2365 
2366                         if (!(x2cpu->Flags & ACPI_SRAT_CPU_ENABLED))
2367                                 break;
2368                         x2apic.domain = x2cpu->ProximityDomain;
2369                         x2apic.x2apic_id = x2cpu->ApicId;
2370                         (void) snprintf(prop_name, 30, "acpi-srat-processor-%d",
2371                             proc_num);
2372                         bsetprop(prop_name, strlen(prop_name), &x2apic,
2373                             sizeof (x2apic));
2374                         proc_num++;
2375                         break;
2376                 }
2377                 default:
2378                         if (kbm_debug)
2379                                 bop_printf(NULL, "SRAT type %d\n", item->Type);
2380                         break;
2381                 }
2382 
2383                 item = (ACPI_SUBTABLE_HEADER *)
2384                     (item->Length + (uintptr_t)item);
2385         }
2386 
2387         /*
2388          * The maximum physical address calculated from the SRAT table is more
2389          * accurate than that calculated from the MSCT table.
2390          */
2391         if (maxmem != 0) {
2392                 plat_dr_physmax = btop(maxmem);
2393         }
2394 }
2395 
2396 static void
2397 process_slit(ACPI_TABLE_SLIT *tp)
2398 {
2399 
2400         /*
2401          * Check the number of localities; if it's too huge, we just
2402          * return and locality enumeration code will handle this later,
2403          * if possible.
2404          *
2405          * Note that the size of the table is the square of the
2406          * number of localities; if the number of localities exceeds
2407          * UINT16_MAX, the table size may overflow an int when being
2408          * passed to bsetprop() below.
2409          */
2410         if (tp->LocalityCount >= SLIT_LOCALITIES_MAX)
2411                 return;
2412 
2413         bsetprop(SLIT_NUM_PROPNAME, strlen(SLIT_NUM_PROPNAME),
2414             &tp->LocalityCount, sizeof (tp->LocalityCount));
2415         bsetprop(SLIT_PROPNAME, strlen(SLIT_PROPNAME), &tp->Entry,
2416             tp->LocalityCount * tp->LocalityCount);
2417 }
2418 
2419 static ACPI_TABLE_MSCT *
2420 process_msct(ACPI_TABLE_MSCT *tp)
2421 {
2422         int last_seen = 0;
2423         int proc_num = 0;
2424         ACPI_MSCT_PROXIMITY *item, *end;
2425         extern uint64_t plat_dr_options;
2426 
2427         ASSERT(tp != NULL);
2428 
2429         end = (ACPI_MSCT_PROXIMITY *)(tp->Header.Length + (uintptr_t)tp);
2430         for (item = (void *)((uintptr_t)tp + tp->ProximityOffset);
2431             item < end;
2432             item = (void *)(item->Length + (uintptr_t)item)) {
2433                 /*
2434                  * Sanity check according to section 5.2.19.1 of ACPI 4.0.
2435                  * Revision     1
2436                  * Length       22
2437                  */
2438                 if (item->Revision != 1 || item->Length != 22) {
2439                         cmn_err(CE_CONT,
2440                             "?boot: unknown proximity domain structure in MSCT "
2441                             "with Revision(%d), Length(%d).\n",
2442                             (int)item->Revision, (int)item->Length);
2443                         return (NULL);
2444                 } else if (item->RangeStart > item->RangeEnd) {
2445                         cmn_err(CE_CONT,
2446                             "?boot: invalid proximity domain structure in MSCT "
2447                             "with RangeStart(%u), RangeEnd(%u).\n",
2448                             item->RangeStart, item->RangeEnd);
2449                         return (NULL);
2450                 } else if (item->RangeStart != last_seen) {
2451                         /*
2452                          * Items must be organized in ascending order of the
2453                          * proximity domain enumerations.
2454                          */
2455                         cmn_err(CE_CONT,
2456                             "?boot: invalid proximity domain structure in MSCT,"
2457                             " items are not orginized in ascending order.\n");
2458                         return (NULL);
2459                 }
2460 
2461                 /*
2462                  * If ProcessorCapacity is 0 then there would be no CPUs in this
2463                  * domain.
2464                  */
2465                 if (item->ProcessorCapacity != 0) {
2466                         proc_num += (item->RangeEnd - item->RangeStart + 1) *
2467                             item->ProcessorCapacity;
2468                 }
2469 
2470                 last_seen = item->RangeEnd - item->RangeStart + 1;
2471                 /*
2472                  * Break out if all proximity domains have been processed.
2473                  * Some BIOSes may have unused items at the end of MSCT table.
2474                  */
2475                 if (last_seen > tp->MaxProximityDomains) {
2476                         break;
2477                 }
2478         }
2479         if (last_seen != tp->MaxProximityDomains + 1) {
2480                 cmn_err(CE_CONT,
2481                     "?boot: invalid proximity domain structure in MSCT, "
2482                     "proximity domain count doesn't match.\n");
2483                 return (NULL);
2484         }
2485 
2486         /*
2487          * Set plat-max-ncpus property if it hasn't been set yet.
2488          */
2489         if (do_bsys_getproplen(NULL, PLAT_MAX_NCPUS_NAME) < 0) {
2490                 if (proc_num != 0) {
2491                         bsetpropsi(PLAT_MAX_NCPUS_NAME, proc_num);
2492                 }
2493         }
2494 
2495         /*
2496          * Use Maximum Physical Address from the MSCT table as upper limit for
2497          * memory hot-adding by default. It may be overridden by value from
2498          * the SRAT table or the "plat-dr-physmax" boot option.
2499          */
2500         plat_dr_physmax = btop(tp->MaxAddress + 1);
2501 
2502         /*
2503          * Existence of MSCT implies CPU/memory hotplug-capability for the
2504          * platform.
2505          */
2506         plat_dr_options |= PLAT_DR_FEATURE_CPU;
2507         plat_dr_options |= PLAT_DR_FEATURE_MEMORY;
2508 
2509         return (tp);
2510 }
2511 
2512 #else /* __xpv */
2513 static void
2514 enumerate_xen_cpus()
2515 {
2516         processorid_t   id, max_id;
2517 
2518         /*
2519          * User-set boot-ncpus overrides enumeration
2520          */
2521         if (do_bsys_getproplen(NULL, BOOT_NCPUS_NAME) >= 0)
2522                 return;
2523 
2524         /*
2525          * Probe every possible virtual CPU id and remember the
2526          * highest id present; the count of CPUs is one greater
2527          * than this.  This tacitly assumes at least cpu 0 is present.
2528          */
2529         max_id = 0;
2530         for (id = 0; id < MAX_VIRT_CPUS; id++)
2531                 if (HYPERVISOR_vcpu_op(VCPUOP_is_up, id, NULL) == 0)
2532                         max_id = id;
2533 
2534         bsetpropsi(BOOT_NCPUS_NAME, max_id+1);
2535 
2536 }
2537 #endif /* __xpv */
2538 
2539 static void
2540 build_firmware_properties(void)
2541 {
2542         ACPI_TABLE_HEADER *tp = NULL;
2543 
2544 #ifndef __xpv
2545         if ((tp = find_fw_table(ACPI_SIG_MSCT)) != NULL)
2546                 msct_ptr = process_msct((ACPI_TABLE_MSCT *)tp);
2547         else
2548                 msct_ptr = NULL;
2549 
2550         if ((tp = find_fw_table(ACPI_SIG_MADT)) != NULL)
2551                 process_madt((ACPI_TABLE_MADT *)tp);
2552 
2553         if ((srat_ptr = (ACPI_TABLE_SRAT *)
2554             find_fw_table(ACPI_SIG_SRAT)) != NULL)
2555                 process_srat(srat_ptr);
2556 
2557         if (slit_ptr = (ACPI_TABLE_SLIT *)find_fw_table(ACPI_SIG_SLIT))
2558                 process_slit(slit_ptr);
2559 
2560         tp = find_fw_table(ACPI_SIG_MCFG);
2561 #else /* __xpv */
2562         enumerate_xen_cpus();
2563         if (DOMAIN_IS_INITDOMAIN(xen_info))
2564                 tp = find_fw_table(ACPI_SIG_MCFG);
2565 #endif /* __xpv */
2566         if (tp != NULL)
2567                 process_mcfg((ACPI_TABLE_MCFG *)tp);
2568 }
2569 
2570 /*
2571  * fake up a boot property for deferred early console output
2572  * this is used by both graphical boot and the (developer only)
2573  * USB serial console
2574  */
2575 void *
2576 defcons_init(size_t size)
2577 {
2578         static char *p = NULL;
2579 
2580         p = do_bsys_alloc(NULL, NULL, size, MMU_PAGESIZE);
2581         *p = 0;
2582         bsetprop("deferred-console-buf", strlen("deferred-console-buf") + 1,
2583             &p, sizeof (p));
2584         return (p);
2585 }
2586 
2587 /*ARGSUSED*/
2588 int
2589 boot_compinfo(int fd, struct compinfo *cbp)
2590 {
2591         cbp->iscmp = 0;
2592         cbp->blksize = MAXBSIZE;
2593         return (0);
2594 }
2595 
2596 #define BP_MAX_STRLEN   32
2597 
2598 /*
2599  * Get value for given boot property
2600  */
2601 int
2602 bootprop_getval(const char *prop_name, u_longlong_t *prop_value)
2603 {
2604         int             boot_prop_len;
2605         char            str[BP_MAX_STRLEN];
2606         u_longlong_t    value;
2607 
2608         boot_prop_len = BOP_GETPROPLEN(bootops, prop_name);
2609         if (boot_prop_len < 0 || boot_prop_len > sizeof (str) ||
2610             BOP_GETPROP(bootops, prop_name, str) < 0 ||
2611             kobj_getvalue(str, &value) == -1)
2612                 return (-1);
2613 
2614         if (prop_value)
2615                 *prop_value = value;
2616 
2617         return (0);
2618 }