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 2007 Sun Microsystems, Inc. All rights reserved. 24 * Use is subject to license terms. 25 */ 26 27 #pragma ident "%Z%%M% %I% %E% SMI" 28 29 /* 30 * This file contains the functionality that mimics the boot operations 31 * on SPARC systems or the old boot.bin/multiboot programs on x86 systems. 32 * The x86 kernel now does everything on its own. 33 */ 34 35 #include <sys/types.h> 36 #include <sys/bootconf.h> 37 #include <sys/bootsvcs.h> 38 #include <sys/bootinfo.h> 39 #include <sys/multiboot.h> 40 #include <sys/bootvfs.h> 41 #include <sys/bootprops.h> 42 #include <sys/varargs.h> 43 #include <sys/param.h> 44 #include <sys/machparam.h> 45 #include <sys/archsystm.h> 46 #include <sys/boot_console.h> 47 #include <sys/cmn_err.h> 48 #include <sys/systm.h> 49 #include <sys/promif.h> 50 #include <sys/archsystm.h> 51 #include <sys/x86_archext.h> 52 #include <sys/kobj.h> 53 #include <sys/privregs.h> 54 #include <sys/sysmacros.h> 55 #include <sys/ctype.h> 56 #include <vm/kboot_mmu.h> 57 #include <vm/hat_pte.h> 58 #include "acpi_fw.h" 59 60 static int have_console = 0; /* set once primitive console is initialized */ 61 static char *boot_args = ""; 62 63 /* 64 * Debugging macros 65 */ 66 static uint_t kbm_debug = 0; 67 #define DBG_MSG(s) { if (kbm_debug) bop_printf(NULL, "%s", s); } 68 #define DBG(x) { if (kbm_debug) \ 69 bop_printf(NULL, "%s is %" PRIx64 "\n", #x, (uint64_t)(x)); \ 70 } 71 72 #define PUT_STRING(s) { \ 73 char *cp; \ 74 for (cp = (s); *cp; ++cp) \ 75 bcons_putchar(*cp); \ 76 } 77 78 struct xboot_info *xbootp; /* boot info from "glue" code in low memory */ 79 bootops_t bootop; /* simple bootops we'll pass on to kernel */ 80 struct bsys_mem bm; 81 82 static uintptr_t next_virt; /* next available virtual address */ 83 static paddr_t next_phys; /* next available physical address from dboot */ 84 static paddr_t high_phys = -(paddr_t)1; /* last used physical address */ 85 86 /* 87 * buffer for vsnprintf for console I/O 88 */ 89 #define BUFFERSIZE 256 90 static char buffer[BUFFERSIZE]; 91 /* 92 * stuff to store/report/manipulate boot property settings. 93 */ 94 typedef struct bootprop { 95 struct bootprop *bp_next; 96 char *bp_name; 97 uint_t bp_vlen; 98 char *bp_value; 99 } bootprop_t; 100 101 static bootprop_t *bprops = NULL; 102 static char *curr_page = NULL; /* ptr to avail bprop memory */ 103 static int curr_space = 0; /* amount of memory at curr_page */ 104 105 /* 106 * some allocator statistics 107 */ 108 static ulong_t total_bop_alloc_scratch = 0; 109 static ulong_t total_bop_alloc_kernel = 0; 110 111 static void build_firmware_properties(void); 112 113 static int early_allocation = 1; 114 115 /* 116 * Allocate aligned physical memory at boot time. This allocator allocates 117 * from the highest possible addresses. This avoids exhausting memory that 118 * would be useful for DMA buffers. 119 */ 120 paddr_t 121 do_bop_phys_alloc(uint64_t size, uint64_t align) 122 { 123 paddr_t pa = 0; 124 paddr_t start; 125 paddr_t end; 126 struct memlist *ml = (struct memlist *)xbootp->bi_phys_install; 127 128 /* 129 * Be careful if high memory usage is limited in startup.c 130 * Since there are holes in the low part of the physical address 131 * space we can treat physmem as a pfn (not just a pgcnt) and 132 * get a conservative upper limit. 133 */ 134 if (physmem != 0 && high_phys > pfn_to_pa(physmem)) 135 high_phys = pfn_to_pa(physmem); 136 137 /* 138 * find the lowest or highest available memory in physinstalled 139 */ 140 size = P2ROUNDUP(size, align); 141 for (; ml; ml = ml->next) { 142 start = P2ROUNDUP(ml->address, align); 143 end = P2ALIGN(ml->address + ml->size, align); 144 if (start < next_phys) 145 start = P2ROUNDUP(next_phys, align); 146 if (end > high_phys) 147 end = P2ALIGN(high_phys, align); 148 149 if (end <= start) 150 continue; 151 if (end - start < size) 152 continue; 153 154 /* 155 * Early allocations need to use low memory, since 156 * physmem might be further limited by bootenv.rc 157 */ 158 if (early_allocation) { 159 if (pa == 0 || start < pa) 160 pa = start; 161 } else { 162 if (end - size > pa) 163 pa = end - size; 164 } 165 } 166 if (pa != 0) { 167 if (early_allocation) 168 next_phys = pa + size; 169 else 170 high_phys = pa; 171 return (pa); 172 } 173 panic("do_bop_phys_alloc(0x%" PRIx64 ", 0x%" PRIx64 ") Out of memory\n", 174 size, align); 175 /*NOTREACHED*/ 176 } 177 178 static uintptr_t 179 alloc_vaddr(size_t size, paddr_t align) 180 { 181 uintptr_t rv; 182 183 next_virt = P2ROUNDUP(next_virt, (uintptr_t)align); 184 rv = (uintptr_t)next_virt; 185 next_virt += size; 186 return (rv); 187 } 188 189 /* 190 * Allocate virtual memory. The size is always rounded up to a multiple 191 * of base pagesize. 192 */ 193 194 /*ARGSUSED*/ 195 static caddr_t 196 do_bsys_alloc(bootops_t *bop, caddr_t virthint, size_t size, int align) 197 { 198 paddr_t a = align; /* same type as pa for masking */ 199 uint_t pgsize; 200 paddr_t pa; 201 uintptr_t va; 202 ssize_t s; /* the aligned size */ 203 uint_t level; 204 uint_t is_kernel = (virthint != 0); 205 206 if (a < MMU_PAGESIZE) 207 a = MMU_PAGESIZE; 208 else if (!ISP2(a)) 209 prom_panic("do_bsys_alloc() incorrect alignment"); 210 size = P2ROUNDUP(size, MMU_PAGESIZE); 211 212 /* 213 * Use the next aligned virtual address if we weren't given one. 214 */ 215 if (virthint == NULL) { 216 virthint = (caddr_t)alloc_vaddr(size, a); 217 total_bop_alloc_scratch += size; 218 } else { 219 total_bop_alloc_kernel += size; 220 } 221 222 /* 223 * allocate the physical memory 224 */ 225 pa = do_bop_phys_alloc(size, a); 226 227 /* 228 * Add the mappings to the page tables, try large pages first. 229 */ 230 va = (uintptr_t)virthint; 231 s = size; 232 level = 1; 233 pgsize = xbootp->bi_use_pae ? TWO_MEG : FOUR_MEG; 234 if (xbootp->bi_use_largepage && a == pgsize) { 235 while (IS_P2ALIGNED(pa, pgsize) && IS_P2ALIGNED(va, pgsize) && 236 s >= pgsize) { 237 kbm_map(va, pa, level, is_kernel); 238 va += pgsize; 239 pa += pgsize; 240 s -= pgsize; 241 } 242 } 243 244 /* 245 * Map remaining pages use small mappings 246 */ 247 level = 0; 248 pgsize = MMU_PAGESIZE; 249 while (s > 0) { 250 kbm_map(va, pa, level, is_kernel); 251 va += pgsize; 252 pa += pgsize; 253 s -= pgsize; 254 } 255 return (virthint); 256 } 257 258 /* 259 * Free virtual memory - we'll just ignore these. 260 */ 261 /*ARGSUSED*/ 262 static void 263 do_bsys_free(bootops_t *bop, caddr_t virt, size_t size) 264 { 265 bop_printf(NULL, "do_bsys_free(virt=0x%p, size=0x%lx) ignored\n", 266 (void *)virt, size); 267 } 268 269 /* 270 * Old interface 271 */ 272 /*ARGSUSED*/ 273 static caddr_t 274 do_bsys_ealloc( 275 bootops_t *bop, 276 caddr_t virthint, 277 size_t size, 278 int align, 279 int flags) 280 { 281 prom_panic("unsupported call to BOP_EALLOC()\n"); 282 return (0); 283 } 284 285 286 static void 287 bsetprop(char *name, int nlen, void *value, int vlen) 288 { 289 uint_t size; 290 uint_t need_size; 291 bootprop_t *b; 292 293 /* 294 * align the size to 16 byte boundary 295 */ 296 size = sizeof (bootprop_t) + nlen + 1 + vlen; 297 size = (size + 0xf) & ~0xf; 298 if (size > curr_space) { 299 need_size = (size + (MMU_PAGEOFFSET)) & MMU_PAGEMASK; 300 curr_page = do_bsys_alloc(NULL, 0, need_size, MMU_PAGESIZE); 301 curr_space = need_size; 302 } 303 304 /* 305 * use a bootprop_t at curr_page and link into list 306 */ 307 b = (bootprop_t *)curr_page; 308 curr_page += sizeof (bootprop_t); 309 curr_space -= sizeof (bootprop_t); 310 b->bp_next = bprops; 311 bprops = b; 312 313 /* 314 * follow by name and ending zero byte 315 */ 316 b->bp_name = curr_page; 317 bcopy(name, curr_page, nlen); 318 curr_page += nlen; 319 *curr_page++ = 0; 320 curr_space -= nlen + 1; 321 322 /* 323 * copy in value, but no ending zero byte 324 */ 325 b->bp_value = curr_page; 326 b->bp_vlen = vlen; 327 if (vlen > 0) { 328 bcopy(value, curr_page, vlen); 329 curr_page += vlen; 330 curr_space -= vlen; 331 } 332 333 /* 334 * align new values of curr_page, curr_space 335 */ 336 while (curr_space & 0xf) { 337 ++curr_page; 338 --curr_space; 339 } 340 } 341 342 static void 343 bsetprops(char *name, char *value) 344 { 345 bsetprop(name, strlen(name), value, strlen(value) + 1); 346 } 347 348 static void 349 bsetprop64(char *name, uint64_t value) 350 { 351 bsetprop(name, strlen(name), (void *)&value, sizeof (value)); 352 } 353 354 static void 355 bsetpropsi(char *name, int value) 356 { 357 char prop_val[32]; 358 359 (void) snprintf(prop_val, sizeof (prop_val), "%d", value); 360 bsetprops(name, prop_val); 361 } 362 363 /* 364 * to find the size of the buffer to allocate 365 */ 366 /*ARGSUSED*/ 367 int 368 do_bsys_getproplen(bootops_t *bop, char *name) 369 { 370 bootprop_t *b; 371 372 for (b = bprops; b; b = b->bp_next) { 373 if (strcmp(name, b->bp_name) != 0) 374 continue; 375 return (b->bp_vlen); 376 } 377 return (-1); 378 } 379 380 /* 381 * get the value associated with this name 382 */ 383 /*ARGSUSED*/ 384 int 385 do_bsys_getprop(bootops_t *bop, char *name, void *value) 386 { 387 bootprop_t *b; 388 389 for (b = bprops; b; b = b->bp_next) { 390 if (strcmp(name, b->bp_name) != 0) 391 continue; 392 bcopy(b->bp_value, value, b->bp_vlen); 393 return (0); 394 } 395 return (-1); 396 } 397 398 /* 399 * get the name of the next property in succession from the standalone 400 */ 401 /*ARGSUSED*/ 402 static char * 403 do_bsys_nextprop(bootops_t *bop, char *name) 404 { 405 bootprop_t *b; 406 407 /* 408 * A null name is a special signal for the 1st boot property 409 */ 410 if (name == NULL || strlen(name) == 0) { 411 if (bprops == NULL) 412 return (NULL); 413 return (bprops->bp_name); 414 } 415 416 for (b = bprops; b; b = b->bp_next) { 417 if (name != b->bp_name) 418 continue; 419 b = b->bp_next; 420 if (b == NULL) 421 return (NULL); 422 return (b->bp_name); 423 } 424 return (NULL); 425 } 426 427 /* 428 * Parse numeric value from a string. Understands decimal, hex, octal, - and ~ 429 */ 430 static int 431 parse_value(char *p, uint64_t *retval) 432 { 433 int adjust = 0; 434 uint64_t tmp = 0; 435 int digit; 436 int radix = 10; 437 438 *retval = 0; 439 if (*p == '-' || *p == '~') 440 adjust = *p++; 441 442 if (*p == '0') { 443 ++p; 444 if (*p == 0) 445 return (0); 446 if (*p == 'x' || *p == 'X') { 447 radix = 16; 448 ++p; 449 } else { 450 radix = 8; 451 ++p; 452 } 453 } 454 while (*p) { 455 if ('0' <= *p && *p <= '9') 456 digit = *p - '0'; 457 else if ('a' <= *p && *p <= 'f') 458 digit = 10 + *p - 'a'; 459 else if ('A' <= *p && *p <= 'F') 460 digit = 10 + *p - 'A'; 461 else 462 return (-1); 463 if (digit >= radix) 464 return (-1); 465 tmp = tmp * radix + digit; 466 ++p; 467 } 468 if (adjust == '-') 469 tmp = -tmp; 470 else if (adjust == '~') 471 tmp = ~tmp; 472 *retval = tmp; 473 return (0); 474 } 475 476 /* 477 * 2nd part of building the table of boot properties. This includes: 478 * - values from /boot/solaris/bootenv.rc (ie. eeprom(1m) values) 479 * 480 * lines look like one of: 481 * ^$ 482 * ^# comment till end of line 483 * setprop name 'value' 484 * setprop name value 485 * setprop name "value" 486 * 487 * we do single character I/O since this is really just looking at memory 488 */ 489 void 490 boot_prop_finish(void) 491 { 492 int fd; 493 char *line; 494 int c; 495 int bytes_read; 496 char *name; 497 int n_len; 498 char *value; 499 int v_len; 500 char *inputdev; /* these override the comand line if serial ports */ 501 char *outputdev; 502 char *consoledev; 503 uint64_t lvalue; 504 505 DBG_MSG("Opening /boot/solaris/bootenv.rc\n"); 506 fd = BRD_OPEN(bfs_ops, "/boot/solaris/bootenv.rc", 0); 507 DBG(fd); 508 509 line = do_bsys_alloc(NULL, NULL, MMU_PAGESIZE, MMU_PAGESIZE); 510 while (fd >= 0) { 511 512 /* 513 * get a line 514 */ 515 for (c = 0; ; ++c) { 516 bytes_read = BRD_READ(bfs_ops, fd, line + c, 1); 517 if (bytes_read == 0) { 518 if (c == 0) 519 goto done; 520 break; 521 } 522 if (line[c] == '\n') 523 break; 524 } 525 line[c] = 0; 526 527 /* 528 * ignore comment lines 529 */ 530 c = 0; 531 while (ISSPACE(line[c])) 532 ++c; 533 if (line[c] == '#' || line[c] == 0) 534 continue; 535 536 /* 537 * must have "setprop " or "setprop\t" 538 */ 539 if (strncmp(line + c, "setprop ", 8) != 0 && 540 strncmp(line + c, "setprop\t", 8) != 0) 541 continue; 542 c += 8; 543 while (ISSPACE(line[c])) 544 ++c; 545 if (line[c] == 0) 546 continue; 547 548 /* 549 * gather up the property name 550 */ 551 name = line + c; 552 n_len = 0; 553 while (line[c] && !ISSPACE(line[c])) 554 ++n_len, ++c; 555 556 /* 557 * gather up the value, if any 558 */ 559 value = ""; 560 v_len = 0; 561 while (ISSPACE(line[c])) 562 ++c; 563 if (line[c] != 0) { 564 value = line + c; 565 while (line[c] && !ISSPACE(line[c])) 566 ++v_len, ++c; 567 } 568 569 if (v_len >= 2 && value[0] == value[v_len - 1] && 570 (value[0] == '\'' || value[0] == '"')) { 571 ++value; 572 v_len -= 2; 573 } 574 name[n_len] = 0; 575 if (v_len > 0) 576 value[v_len] = 0; 577 else 578 continue; 579 580 /* 581 * ignore "boot-file" property, it's now meaningless 582 */ 583 if (strcmp(name, "boot-file") == 0) 584 continue; 585 if (strcmp(name, "boot-args") == 0 && 586 strlen(boot_args) > 0) 587 continue; 588 589 /* 590 * If a property was explicitly set on the command line 591 * it will override a setting in bootenv.rc 592 */ 593 if (do_bsys_getproplen(NULL, name) > 0) 594 continue; 595 596 bsetprop(name, n_len, value, v_len + 1); 597 } 598 done: 599 if (fd >= 0) 600 BRD_CLOSE(bfs_ops, fd); 601 602 /* 603 * Check if we have to limit the boot time allocator 604 */ 605 if (do_bsys_getproplen(NULL, "physmem") != -1 && 606 do_bsys_getprop(NULL, "physmem", line) >= 0 && 607 parse_value(line, &lvalue) != -1) { 608 if (0 < lvalue && (lvalue < physmem || physmem == 0)) { 609 physmem = (pgcnt_t)lvalue; 610 DBG(physmem); 611 } 612 } 613 early_allocation = 0; 614 615 /* 616 * check to see if we have to override the default value of the console 617 */ 618 inputdev = line; 619 v_len = do_bsys_getproplen(NULL, "input-device"); 620 if (v_len > 0) 621 (void) do_bsys_getprop(NULL, "input-device", inputdev); 622 else 623 v_len = 0; 624 inputdev[v_len] = 0; 625 626 outputdev = inputdev + v_len + 1; 627 v_len = do_bsys_getproplen(NULL, "output-device"); 628 if (v_len > 0) 629 (void) do_bsys_getprop(NULL, "output-device", outputdev); 630 else 631 v_len = 0; 632 outputdev[v_len] = 0; 633 634 consoledev = outputdev + v_len + 1; 635 v_len = do_bsys_getproplen(NULL, "console"); 636 if (v_len > 0) 637 (void) do_bsys_getprop(NULL, "console", consoledev); 638 else 639 v_len = 0; 640 consoledev[v_len] = 0; 641 bcons_init2(inputdev, outputdev, consoledev); 642 643 if (strstr((char *)xbootp->bi_cmdline, "prom_debug") || kbm_debug) { 644 value = line; 645 bop_printf(NULL, "\nBoot properties:\n"); 646 name = ""; 647 while ((name = do_bsys_nextprop(NULL, name)) != NULL) { 648 bop_printf(NULL, "\t0x%p %s = ", (void *)name, name); 649 (void) do_bsys_getprop(NULL, name, value); 650 v_len = do_bsys_getproplen(NULL, name); 651 bop_printf(NULL, "len=%d ", v_len); 652 value[v_len] = 0; 653 bop_printf(NULL, "%s\n", value); 654 } 655 } 656 } 657 658 /* 659 * print formatted output 660 */ 661 /*PRINTFLIKE2*/ 662 /*ARGSUSED*/ 663 void 664 bop_printf(bootops_t *bop, char *fmt, ...) 665 { 666 va_list ap; 667 668 if (have_console == 0) 669 return; 670 671 va_start(ap, fmt); 672 (void) vsnprintf(buffer, BUFFERSIZE, fmt, ap); 673 va_end(ap); 674 PUT_STRING(buffer); 675 } 676 677 /* 678 * Another panic() variant; this one can be used even earlier during boot than 679 * prom_panic(). 680 */ 681 /*PRINTFLIKE1*/ 682 void 683 bop_panic(char *fmt, ...) 684 { 685 va_list ap; 686 687 va_start(ap, fmt); 688 bop_printf(NULL, fmt, ap); 689 va_end(ap); 690 691 bop_printf(NULL, "\nPress any key to reboot.\n"); 692 (void) bcons_getchar(); 693 bop_printf(NULL, "Resetting...\n"); 694 pc_reset(); 695 } 696 697 /* 698 * Do a real mode interrupt BIOS call 699 */ 700 typedef struct bios_regs { 701 unsigned short ax, bx, cx, dx, si, di, bp, es, ds; 702 } bios_regs_t; 703 typedef int (*bios_func_t)(int, bios_regs_t *); 704 705 /*ARGSUSED*/ 706 static void 707 do_bsys_doint(bootops_t *bop, int intnum, struct bop_regs *rp) 708 { 709 static int firsttime = 1; 710 bios_func_t bios_func = (bios_func_t)(void *)(uintptr_t)0x5000; 711 bios_regs_t br; 712 713 /* 714 * The first time we do this, we have to copy the pre-packaged 715 * low memory bios call code image into place. 716 */ 717 if (firsttime) { 718 extern char bios_image[]; 719 extern uint32_t bios_size; 720 721 bcopy(bios_image, (void *)bios_func, bios_size); 722 firsttime = 0; 723 } 724 725 br.ax = rp->eax.word.ax; 726 br.bx = rp->ebx.word.bx; 727 br.cx = rp->ecx.word.cx; 728 br.dx = rp->edx.word.dx; 729 br.bp = rp->ebp.word.bp; 730 br.si = rp->esi.word.si; 731 br.di = rp->edi.word.di; 732 br.ds = rp->ds; 733 br.es = rp->es; 734 735 DBG_MSG("Doing BIOS call..."); 736 rp->eflags = bios_func(intnum, &br); 737 DBG_MSG("done\n"); 738 739 rp->eax.word.ax = br.ax; 740 rp->ebx.word.bx = br.bx; 741 rp->ecx.word.cx = br.cx; 742 rp->edx.word.dx = br.dx; 743 rp->ebp.word.bp = br.bp; 744 rp->esi.word.si = br.si; 745 rp->edi.word.di = br.di; 746 rp->ds = br.ds; 747 rp->es = br.es; 748 } 749 750 static struct boot_syscalls bop_sysp = { 751 bcons_getchar, 752 bcons_putchar, 753 bcons_ischar, 754 }; 755 756 static char *whoami; 757 758 #define BUFLEN 64 759 760 static void 761 setup_rarp_props(struct sol_netinfo *sip) 762 { 763 char buf[BUFLEN]; /* to hold ip/mac addrs */ 764 uint8_t *val; 765 766 val = (uint8_t *)&sip->sn_ciaddr; 767 (void) snprintf(buf, BUFLEN, "%d.%d.%d.%d", 768 val[0], val[1], val[2], val[3]); 769 bsetprops(BP_HOST_IP, buf); 770 771 val = (uint8_t *)&sip->sn_siaddr; 772 (void) snprintf(buf, BUFLEN, "%d.%d.%d.%d", 773 val[0], val[1], val[2], val[3]); 774 bsetprops(BP_SERVER_IP, buf); 775 776 if (sip->sn_giaddr != 0) { 777 val = (uint8_t *)&sip->sn_giaddr; 778 (void) snprintf(buf, BUFLEN, "%d.%d.%d.%d", 779 val[0], val[1], val[2], val[3]); 780 bsetprops(BP_ROUTER_IP, buf); 781 } 782 783 if (sip->sn_netmask != 0) { 784 val = (uint8_t *)&sip->sn_netmask; 785 (void) snprintf(buf, BUFLEN, "%d.%d.%d.%d", 786 val[0], val[1], val[2], val[3]); 787 bsetprops(BP_SUBNET_MASK, buf); 788 } 789 790 if (sip->sn_mactype != 4 || sip->sn_maclen != 6) { 791 bop_printf(NULL, "unsupported mac type %d, mac len %d\n", 792 sip->sn_mactype, sip->sn_maclen); 793 } else { 794 val = sip->sn_macaddr; 795 (void) snprintf(buf, BUFLEN, "%x:%x:%x:%x:%x:%x", 796 val[0], val[1], val[2], val[3], val[4], val[5]); 797 bsetprops(BP_BOOT_MAC, buf); 798 } 799 } 800 801 /* 802 * 1st pass at building the table of boot properties. This includes: 803 * - values set on the command line: -B a=x,b=y,c=z .... 804 * - known values we just compute (ie. from xbootp) 805 * - values from /boot/solaris/bootenv.rc (ie. eeprom(1m) values) 806 * 807 * the grub command line looked like: 808 * kernel boot-file [-B prop=value[,prop=value]...] [boot-args] 809 * 810 * whoami is the same as boot-file 811 */ 812 static void 813 build_boot_properties(void) 814 { 815 char *name; 816 int name_len; 817 char *value; 818 int value_len; 819 static int stdout_val = 0; 820 struct boot_modules *bm; 821 char *propbuf; 822 int quoted = 0; 823 int boot_arg_len; 824 uchar_t boot_device; 825 char str[3]; 826 multiboot_info_t *mbi; 827 int netboot; 828 struct sol_netinfo *sip; 829 830 /* 831 * These have to be done first, so that kobj_mount_root() works 832 */ 833 DBG_MSG("Building boot properties\n"); 834 propbuf = do_bsys_alloc(NULL, NULL, MMU_PAGESIZE, 0); 835 DBG((uintptr_t)propbuf); 836 if (xbootp->bi_module_cnt > 0) { 837 bm = xbootp->bi_modules; 838 bsetprop64("ramdisk_start", (uint64_t)(uintptr_t)bm->bm_addr); 839 bsetprop64("ramdisk_end", (uint64_t)(uintptr_t)bm->bm_addr + 840 bm->bm_size); 841 } 842 843 DBG_MSG("Parsing command line for boot properties\n"); 844 value = xbootp->bi_cmdline; 845 846 /* 847 * allocate memory to collect boot_args into 848 */ 849 boot_arg_len = strlen(xbootp->bi_cmdline) + 1; 850 boot_args = do_bsys_alloc(NULL, NULL, boot_arg_len, MMU_PAGESIZE); 851 boot_args[0] = 0; 852 boot_arg_len = 0; 853 854 while (ISSPACE(*value)) 855 ++value; 856 /* 857 * value now points at the boot-file 858 */ 859 value_len = 0; 860 while (value[value_len] && !ISSPACE(value[value_len])) 861 ++value_len; 862 if (value_len > 0) { 863 whoami = propbuf; 864 bcopy(value, whoami, value_len); 865 whoami[value_len] = 0; 866 bsetprops("boot-file", whoami); 867 /* 868 * strip leading path stuff from whoami, so running from 869 * PXE/miniroot makes sense. 870 */ 871 if (strstr(whoami, "/platform/") != NULL) 872 whoami = strstr(whoami, "/platform/"); 873 bsetprops("whoami", whoami); 874 } 875 876 /* 877 * Values forcibly set boot properties on the command line via -B. 878 * Allow use of quotes in values. Other stuff goes on kernel 879 * command line. 880 */ 881 name = value + value_len; 882 while (*name != 0) { 883 /* 884 * anything not " -B" is copied to the command line 885 */ 886 if (!ISSPACE(name[0]) || name[1] != '-' || name[2] != 'B') { 887 boot_args[boot_arg_len++] = *name; 888 boot_args[boot_arg_len] = 0; 889 ++name; 890 continue; 891 } 892 893 /* 894 * skip the " -B" and following white space 895 */ 896 name += 3; 897 while (ISSPACE(*name)) 898 ++name; 899 while (*name && !ISSPACE(*name)) { 900 value = strstr(name, "="); 901 if (value == NULL) 902 break; 903 name_len = value - name; 904 ++value; 905 value_len = 0; 906 quoted = 0; 907 for (; ; ++value_len) { 908 if (!value[value_len]) 909 break; 910 911 /* 912 * is this value quoted? 913 */ 914 if (value_len == 0 && 915 (value[0] == '\'' || value[0] == '"')) { 916 quoted = value[0]; 917 ++value_len; 918 } 919 920 /* 921 * In the quote accept any character, 922 * but look for ending quote. 923 */ 924 if (quoted) { 925 if (value[value_len] == quoted) 926 quoted = 0; 927 continue; 928 } 929 930 /* 931 * a comma or white space ends the value 932 */ 933 if (value[value_len] == ',' || 934 ISSPACE(value[value_len])) 935 break; 936 } 937 938 if (value_len == 0) { 939 bsetprop(name, name_len, "true", 5); 940 } else { 941 char *v = value; 942 int l = value_len; 943 if (v[0] == v[l - 1] && 944 (v[0] == '\'' || v[0] == '"')) { 945 ++v; 946 l -= 2; 947 } 948 bcopy(v, propbuf, l); 949 propbuf[l] = '\0'; 950 bsetprop(name, name_len, propbuf, 951 l + 1); 952 } 953 name = value + value_len; 954 while (*name == ',') 955 ++name; 956 } 957 } 958 959 /* 960 * set boot-args property 961 */ 962 bsetprops("boot-args", boot_args); 963 964 /* 965 * set the BIOS boot device from GRUB 966 */ 967 netboot = 0; 968 mbi = xbootp->bi_mb_info; 969 if (mbi != NULL && mbi->flags & 0x2) { 970 boot_device = mbi->boot_device >> 24; 971 if (boot_device == 0x20) 972 netboot++; 973 str[0] = (boot_device >> 4) + '0'; 974 str[1] = (boot_device & 0xf) + '0'; 975 str[2] = 0; 976 bsetprops("bios-boot-device", str); 977 } else { 978 netboot = 1; 979 } 980 981 /* 982 * In the netboot case, drives_info is overloaded with the dhcp ack. 983 * This is not multiboot compliant and requires special pxegrub! 984 */ 985 if (netboot && mbi->drives_length != 0) { 986 sip = (struct sol_netinfo *)(uintptr_t)mbi->drives_addr; 987 if (sip->sn_infotype == SN_TYPE_BOOTP) 988 bsetprop("bootp-response", sizeof ("bootp-response"), 989 (void *)(uintptr_t)mbi->drives_addr, 990 mbi->drives_length); 991 else if (sip->sn_infotype == SN_TYPE_BOOTP) 992 setup_rarp_props(sip); 993 } 994 bsetprop("stdout", strlen("stdout"), 995 &stdout_val, sizeof (stdout_val)); 996 997 /* 998 * more conjured up values for made up things.... 999 */ 1000 bsetprops("mfg-name", "i86pc"); 1001 bsetprops("impl-arch-name", "i86pc"); 1002 1003 /* 1004 * Build firmware-provided system properties 1005 */ 1006 build_firmware_properties(); 1007 1008 /* 1009 * Find out what these are: 1010 * - cpuid_feature_ecx_include 1011 * - cpuid_feature_ecx_exclude 1012 * - cpuid_feature_edx_include 1013 * - cpuid_feature_edx_exclude 1014 * 1015 * Find out what these are in multiboot: 1016 * - bootp-response 1017 * - netdev-path 1018 * - fstype 1019 */ 1020 } 1021 1022 /* 1023 * Install a temporary IDT that lets us catch errors in the boot time code. 1024 * We shouldn't get any faults at all while this is installed, so we'll 1025 * just generate a traceback and exit. 1026 */ 1027 #ifdef __amd64 1028 static const int bcode_sel = B64CODE_SEL; 1029 #else 1030 static const int bcode_sel = B32CODE_SEL; 1031 #endif 1032 1033 /* 1034 * simple description of a stack frame (args are 32 bit only currently) 1035 */ 1036 typedef struct bop_frame { 1037 struct bop_frame *old_frame; 1038 pc_t retaddr; 1039 long arg[1]; 1040 } bop_frame_t; 1041 1042 void 1043 bop_traceback(bop_frame_t *frame) 1044 { 1045 pc_t pc; 1046 int cnt; 1047 int a; 1048 char *ksym; 1049 ulong_t off; 1050 1051 bop_printf(NULL, "Stack traceback:\n"); 1052 for (cnt = 0; cnt < 30; ++cnt) { /* up to 30 frames */ 1053 pc = frame->retaddr; 1054 if (pc == 0) 1055 break; 1056 ksym = kobj_getsymname(pc, &off); 1057 if (ksym) 1058 bop_printf(NULL, " %s+%lx", ksym, off); 1059 else 1060 bop_printf(NULL, " 0x%lx", pc); 1061 1062 frame = frame->old_frame; 1063 if (frame == 0) { 1064 bop_printf(NULL, "\n"); 1065 break; 1066 } 1067 for (a = 0; a < 6; ++a) { /* try for 6 args */ 1068 #if defined(__i386) 1069 if ((void *)&frame->arg[a] == (void *)frame->old_frame) 1070 break; 1071 if (a == 0) 1072 bop_printf(NULL, "("); 1073 else 1074 bop_printf(NULL, ","); 1075 bop_printf(NULL, "0x%lx", frame->arg[a]); 1076 #endif 1077 } 1078 bop_printf(NULL, ")\n"); 1079 } 1080 } 1081 1082 struct trapframe { 1083 ulong_t frame_ptr; /* %[er]bp pushed by our code */ 1084 ulong_t error_code; /* optional */ 1085 ulong_t inst_ptr; 1086 ulong_t code_seg; 1087 ulong_t flags_reg; 1088 #ifdef __amd64 1089 ulong_t stk_ptr; 1090 ulong_t stk_seg; 1091 #endif 1092 }; 1093 1094 void 1095 bop_trap(struct trapframe *tf) 1096 { 1097 bop_frame_t fakeframe; 1098 static int depth = 0; 1099 1100 /* 1101 * Check for an infinite loop of traps. 1102 */ 1103 if (++depth > 2) 1104 bop_panic("Nested trap"); 1105 1106 /* 1107 * adjust the tf for optional error_code by detecting the code selector 1108 */ 1109 if (tf->code_seg != bcode_sel) 1110 tf = (struct trapframe *)((uintptr_t)tf - sizeof (ulong_t)); 1111 1112 bop_printf(NULL, "Unexpected trap\n"); 1113 bop_printf(NULL, "instruction pointer 0x%lx\n", tf->inst_ptr); 1114 bop_printf(NULL, "error code, optional 0x%lx\n", 1115 tf->error_code & 0xffffffff); 1116 bop_printf(NULL, "code segment 0x%lx\n", tf->code_seg & 0xffff); 1117 bop_printf(NULL, "flags register 0x%lx\n", tf->flags_reg); 1118 #ifdef __amd64 1119 bop_printf(NULL, "return %%rsp 0x%lx\n", tf->stk_ptr); 1120 bop_printf(NULL, "return %%ss 0x%lx\n", tf->stk_seg & 0xffff); 1121 #endif 1122 fakeframe.old_frame = (bop_frame_t *)tf->frame_ptr; 1123 fakeframe.retaddr = (pc_t)tf->inst_ptr; 1124 bop_printf(NULL, "Attempting stack backtrace:\n"); 1125 bop_traceback(&fakeframe); 1126 bop_panic("unexpected trap in early boot"); 1127 } 1128 1129 extern void bop_trap_handler(void); 1130 1131 static gate_desc_t bop_idt[NIDT]; 1132 1133 static desctbr_t bop_idt_info; 1134 1135 static void 1136 bop_idt_init(void) 1137 { 1138 int t; 1139 1140 bzero(&bop_idt, sizeof (bop_idt)); 1141 for (t = 0; t < NIDT; ++t) { 1142 set_gatesegd(&bop_idt[t], &bop_trap_handler, bcode_sel, 1143 SDT_SYSIGT, SEL_KPL); 1144 } 1145 bop_idt_info.dtr_limit = sizeof (bop_idt) - 1; 1146 bop_idt_info.dtr_base = (uintptr_t)&bop_idt; 1147 wr_idtr(&bop_idt_info); 1148 } 1149 1150 /* 1151 * This is where we enter the kernel. It dummies up the boot_ops and 1152 * boot_syscalls vectors and jumps off to _kobj_boot() 1153 */ 1154 void 1155 _start(struct xboot_info *xbp) 1156 { 1157 bootops_t *bops = &bootop; 1158 extern void _kobj_boot(); 1159 1160 /* 1161 * 1st off - initialize the console for any error messages 1162 */ 1163 xbootp = xbp; 1164 bcons_init((void *)xbootp->bi_cmdline); 1165 have_console = 1; 1166 1167 /* 1168 * enable debugging 1169 */ 1170 if (strstr((char *)xbootp->bi_cmdline, "kbm_debug")) 1171 kbm_debug = 1; 1172 1173 DBG_MSG("\n\n*** Entered Solaris in _start() cmdline is: "); 1174 DBG_MSG((char *)xbootp->bi_cmdline); 1175 DBG_MSG("\n\n\n"); 1176 1177 /* 1178 * Install an IDT to catch early pagefaults (shouldn't have any). 1179 * Also needed for kmdb. 1180 */ 1181 bop_idt_init(); 1182 1183 /* 1184 * physavail is no longer used by startup 1185 */ 1186 bm.physinstalled = xbp->bi_phys_install; 1187 bm.pcimem = xbp->bi_pcimem; 1188 bm.physavail = NULL; 1189 1190 /* 1191 * initialize the boot time allocator 1192 */ 1193 next_phys = xbootp->bi_next_paddr; 1194 DBG(next_phys); 1195 next_virt = (uintptr_t)xbootp->bi_next_vaddr; 1196 DBG(next_virt); 1197 DBG_MSG("Initializing boot time memory management..."); 1198 kbm_init(xbootp); 1199 DBG_MSG("done\n"); 1200 1201 /* 1202 * Fill in the bootops vector 1203 */ 1204 bops->bsys_version = BO_VERSION; 1205 bops->boot_mem = &bm; 1206 bops->bsys_alloc = do_bsys_alloc; 1207 bops->bsys_free = do_bsys_free; 1208 bops->bsys_getproplen = do_bsys_getproplen; 1209 bops->bsys_getprop = do_bsys_getprop; 1210 bops->bsys_nextprop = do_bsys_nextprop; 1211 bops->bsys_printf = bop_printf; 1212 bops->bsys_doint = do_bsys_doint; 1213 1214 /* 1215 * BOP_EALLOC() is no longer needed 1216 */ 1217 bops->bsys_ealloc = do_bsys_ealloc; 1218 1219 /* 1220 * 1221 */ 1222 DBG_MSG("Initializing boot properties:\n"); 1223 build_boot_properties(); 1224 1225 if (strstr((char *)xbootp->bi_cmdline, "prom_debug") || kbm_debug) { 1226 char *name; 1227 char *value; 1228 int len; 1229 1230 value = do_bsys_alloc(NULL, NULL, MMU_PAGESIZE, MMU_PAGESIZE); 1231 bop_printf(NULL, "\nBoot properties:\n"); 1232 name = ""; 1233 while ((name = do_bsys_nextprop(NULL, name)) != NULL) { 1234 bop_printf(NULL, "\t0x%p %s = ", (void *)name, name); 1235 (void) do_bsys_getprop(NULL, name, value); 1236 len = do_bsys_getproplen(NULL, name); 1237 bop_printf(NULL, "len=%d ", len); 1238 value[len] = 0; 1239 bop_printf(NULL, "%s\n", value); 1240 } 1241 } 1242 1243 /* 1244 * jump into krtld... 1245 */ 1246 _kobj_boot(&bop_sysp, NULL, bops, NULL); 1247 } 1248 1249 1250 /*ARGSUSED*/ 1251 static caddr_t 1252 no_more_alloc(bootops_t *bop, caddr_t virthint, size_t size, int align) 1253 { 1254 panic("Attempt to bsys_alloc() too late\n"); 1255 return (NULL); 1256 } 1257 1258 /*ARGSUSED*/ 1259 static void 1260 no_more_free(bootops_t *bop, caddr_t virt, size_t size) 1261 { 1262 panic("Attempt to bsys_free() too late\n"); 1263 } 1264 1265 void 1266 bop_no_more_mem(void) 1267 { 1268 DBG(total_bop_alloc_scratch); 1269 DBG(total_bop_alloc_kernel); 1270 bootops->bsys_alloc = no_more_alloc; 1271 bootops->bsys_free = no_more_free; 1272 } 1273 1274 1275 /* 1276 * Set ACPI firmware properties 1277 */ 1278 1279 static caddr_t 1280 vmap_phys(size_t length, paddr_t pa) 1281 { 1282 paddr_t start, end; 1283 caddr_t va; 1284 size_t len, page; 1285 1286 start = P2ALIGN(pa, MMU_PAGESIZE); 1287 end = P2ROUNDUP(pa + length, MMU_PAGESIZE); 1288 len = end - start; 1289 va = (caddr_t)alloc_vaddr(len, MMU_PAGESIZE); 1290 for (page = 0; page < len; page += MMU_PAGESIZE) 1291 kbm_map((uintptr_t)va + page, start + page, 0, 0); 1292 return (va + (pa & MMU_PAGEOFFSET)); 1293 } 1294 1295 static uint8_t 1296 checksum_table(uint8_t *tp, size_t len) 1297 { 1298 uint8_t sum = 0; 1299 1300 while (len-- > 0) 1301 sum += *tp++; 1302 1303 return (sum); 1304 } 1305 1306 static int 1307 valid_rsdp(struct rsdp *rp) 1308 { 1309 1310 /* validate the V1.x checksum */ 1311 if (checksum_table((uint8_t *)&rp->v1, sizeof (struct rsdp_v1)) != 0) 1312 return (0); 1313 1314 /* If pre-ACPI 2.0, this is a valid RSDP */ 1315 if (rp->v1.revision < 2) 1316 return (1); 1317 1318 /* validate the V2.x checksum */ 1319 if (checksum_table((uint8_t *)rp, sizeof (struct rsdp)) != 0) 1320 return (0); 1321 1322 return (1); 1323 } 1324 1325 /* 1326 * Scan memory range for an RSDP; 1327 * see ACPI 3.0 Spec, 5.2.5.1 1328 */ 1329 static struct rsdp * 1330 scan_rsdp(paddr_t start, paddr_t end) 1331 { 1332 size_t len = end - start + 1; 1333 caddr_t ptr; 1334 1335 ptr = vmap_phys(len, start); 1336 while (len > 0) { 1337 if (strncmp(ptr, ACPI_RSDP_SIG, ACPI_RSDP_SIG_LEN) == 0) 1338 if (valid_rsdp((struct rsdp *)ptr)) 1339 return ((struct rsdp *)ptr); 1340 ptr += 16; 1341 len -= 16; 1342 } 1343 1344 return (NULL); 1345 } 1346 1347 /* 1348 * Refer to ACPI 3.0 Spec, section 5.2.5.1 to understand this function 1349 */ 1350 static struct rsdp * 1351 find_rsdp() { 1352 struct rsdp *rsdp; 1353 uint16_t *ebda_seg; 1354 paddr_t ebda_addr; 1355 1356 /* 1357 * Get the EBDA segment and scan the first 1K 1358 */ 1359 ebda_seg = (uint16_t *)vmap_phys(sizeof (uint16_t), ACPI_EBDA_SEG_ADDR); 1360 ebda_addr = *ebda_seg << 4; 1361 rsdp = scan_rsdp(ebda_addr, ebda_addr + ACPI_EBDA_LEN - 1); 1362 if (rsdp == NULL) 1363 /* if EBDA doesn't contain RSDP, look in BIOS memory */ 1364 rsdp = scan_rsdp(0xe0000, 0xfffff); 1365 return (rsdp); 1366 } 1367 1368 static struct table_header * 1369 map_fw_table(paddr_t table_addr) 1370 { 1371 struct table_header *tp; 1372 size_t len = MAX(sizeof (struct table_header), MMU_PAGESIZE); 1373 1374 /* 1375 * Map at least a page; if the table is larger than this, remap it 1376 */ 1377 tp = (struct table_header *)vmap_phys(len, table_addr); 1378 if (tp->len > len) 1379 tp = (struct table_header *)vmap_phys(tp->len, table_addr); 1380 return (tp); 1381 } 1382 1383 static struct table_header * 1384 find_fw_table(char *signature) 1385 { 1386 static int revision = 0; 1387 static struct xsdt *xsdt; 1388 static int len; 1389 paddr_t xsdt_addr; 1390 struct rsdp *rsdp; 1391 struct table_header *tp; 1392 paddr_t table_addr; 1393 int n; 1394 1395 if (strlen(signature) != ACPI_TABLE_SIG_LEN) 1396 return (NULL); 1397 1398 /* 1399 * Reading the ACPI 3.0 Spec, section 5.2.5.3 will help 1400 * understand this code. If we haven't already found the RSDT/XSDT, 1401 * revision will be 0. Find the RSDP and check the revision 1402 * to find out whether to use the RSDT or XSDT. If revision is 1403 * 0 or 1, use the RSDT and set internal revision to 1; if it is 2, 1404 * use the XSDT. If the XSDT address is 0, though, fall back to 1405 * revision 1 and use the RSDT. 1406 */ 1407 if (revision == 0) { 1408 if ((rsdp = (struct rsdp *)find_rsdp()) != NULL) { 1409 revision = rsdp->v1.revision; 1410 switch (revision) { 1411 case 2: 1412 /* 1413 * Use the XSDT unless BIOS is buggy and 1414 * claims to be rev 2 but has a null XSDT 1415 * address 1416 */ 1417 xsdt_addr = rsdp->xsdt; 1418 if (xsdt_addr != 0) 1419 break; 1420 /* FALLTHROUGH */ 1421 case 0: 1422 /* treat RSDP rev 0 as revision 1 internally */ 1423 revision = 1; 1424 /* FALLTHROUGH */ 1425 case 1: 1426 /* use the RSDT for rev 0/1 */ 1427 xsdt_addr = rsdp->v1.rsdt; 1428 break; 1429 default: 1430 /* unknown revision */ 1431 revision = 0; 1432 break; 1433 } 1434 } 1435 if (revision == 0) 1436 return (NULL); 1437 1438 /* cache the XSDT info */ 1439 xsdt = (struct xsdt *)map_fw_table(xsdt_addr); 1440 len = (xsdt->hdr.len - sizeof (xsdt->hdr)) / 1441 ((revision == 1) ? sizeof (uint32_t) : sizeof (uint64_t)); 1442 } 1443 1444 /* 1445 * Scan the table headers looking for a signature match 1446 */ 1447 for (n = 0; n < len; n++) { 1448 table_addr = (revision == 1) ? xsdt->p.r[n] : xsdt->p.x[n]; 1449 if (table_addr == 0) 1450 continue; 1451 tp = map_fw_table(table_addr); 1452 if (strncmp(tp->sig, signature, ACPI_TABLE_SIG_LEN) == 0) { 1453 return (tp); 1454 } 1455 } 1456 return (NULL); 1457 } 1458 1459 static void 1460 process_madt(struct madt *tp) 1461 { 1462 struct madt_processor *cpu, *end; 1463 uint32_t cpu_count = 0; 1464 1465 /* 1466 * User-set boot-ncpus overrides firmware count 1467 */ 1468 if (do_bsys_getproplen(NULL, "boot-ncpus") >= 0) 1469 return; 1470 1471 if (tp != NULL) { 1472 end = (struct madt_processor *)(tp->hdr.len + (uintptr_t)tp); 1473 cpu = tp->list; 1474 while (cpu < end) { 1475 if (cpu->type == MADT_PROCESSOR) 1476 if (cpu->flags & 1) 1477 cpu_count++; 1478 1479 cpu = (struct madt_processor *) 1480 (cpu->len + (uintptr_t)cpu); 1481 } 1482 bsetpropsi("boot-ncpus", cpu_count); 1483 } 1484 1485 } 1486 1487 static void 1488 process_srat(struct srat *tp) 1489 { 1490 struct srat_item *item, *end; 1491 int i; 1492 int proc_num, mem_num; 1493 #pragma pack(1) 1494 struct { 1495 uint32_t domain; 1496 uint32_t apic_id; 1497 uint32_t sapic_id; 1498 } processor; 1499 struct { 1500 uint32_t domain; 1501 uint64_t addr; 1502 uint64_t length; 1503 uint32_t flags; 1504 } memory; 1505 #pragma pack() 1506 char prop_name[30]; 1507 1508 if (tp == NULL) 1509 return; 1510 1511 proc_num = mem_num = 0; 1512 end = (struct srat_item *)(tp->hdr.len + (uintptr_t)tp); 1513 item = tp->list; 1514 while (item < end) { 1515 switch (item->type) { 1516 case SRAT_PROCESSOR: 1517 if (!(item->i.p.flags & SRAT_ENABLED)) 1518 break; 1519 processor.domain = item->i.p.domain1; 1520 for (i = 0; i < 3; i++) 1521 processor.domain += 1522 item->i.p.domain2[i] << ((i + 1) * 8); 1523 processor.apic_id = item->i.p.apic_id; 1524 processor.sapic_id = item->i.p.local_sapic_eid; 1525 (void) snprintf(prop_name, 30, "acpi-srat-processor-%d", 1526 proc_num); 1527 bsetprop(prop_name, strlen(prop_name), &processor, 1528 sizeof (processor)); 1529 proc_num++; 1530 break; 1531 case SRAT_MEMORY: 1532 if (!(item->i.m.flags & SRAT_ENABLED)) 1533 break; 1534 memory.domain = item->i.m.domain; 1535 memory.addr = item->i.m.base_addr; 1536 memory.length = item->i.m.len; 1537 memory.flags = item->i.m.flags; 1538 (void) snprintf(prop_name, 30, "acpi-srat-memory-%d", 1539 mem_num); 1540 bsetprop(prop_name, strlen(prop_name), &memory, 1541 sizeof (memory)); 1542 mem_num++; 1543 break; 1544 } 1545 1546 item = (struct srat_item *) 1547 (item->len + (caddr_t)item); 1548 } 1549 } 1550 1551 static void 1552 process_slit(struct slit *tp) 1553 { 1554 1555 /* 1556 * Check the number of localities; if it's too huge, we just 1557 * return and locality enumeration code will handle this later, 1558 * if possible. 1559 * 1560 * Note that the size of the table is the square of the 1561 * number of localities; if the number of localities exceeds 1562 * UINT16_MAX, the table size may overflow an int when being 1563 * passed to bsetprop() below. 1564 */ 1565 if (tp->number >= SLIT_LOCALITIES_MAX) 1566 return; 1567 1568 bsetprop(SLIT_NUM_PROPNAME, strlen(SLIT_NUM_PROPNAME), &tp->number, 1569 sizeof (tp->number)); 1570 bsetprop(SLIT_PROPNAME, strlen(SLIT_PROPNAME), &tp->entry, 1571 tp->number * tp->number); 1572 } 1573 1574 static void 1575 build_firmware_properties(void) 1576 { 1577 struct table_header *tp; 1578 1579 if (tp = find_fw_table("APIC")) 1580 process_madt((struct madt *)tp); 1581 1582 if (tp = find_fw_table("SRAT")) 1583 process_srat((struct srat *)tp); 1584 1585 if (tp = find_fw_table("SLIT")) 1586 process_slit((struct slit *)tp); 1587 } 1588 1589 /* 1590 * fake up a boot property for USB serial console early boot output 1591 */ 1592 void * 1593 usbser_init(size_t size) 1594 { 1595 static char *p = NULL; 1596 1597 p = do_bsys_alloc(NULL, NULL, size, MMU_PAGESIZE); 1598 *p = 0; 1599 bsetprop("usb-serial-buf", strlen("usb-serial-buf") + 1, 1600 &p, sizeof (p)); 1601 return (p); 1602 } 1603