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