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