Merge commit '74ecdb5171c9f3673b9393b1a3dc6f3a65e93895'
[unleashed.git] / arch / x86 / kernel / platform / i86pc / os / fakebop.c
blobdfdcb4d630dcf7e254025bf9453cbed9a6340faa
1 /*
2 * CDDL HEADER START
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.
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.
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]
19 * CDDL HEADER END
23 * Copyright 2010 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
26 * Copyright (c) 2010, Intel Corporation.
27 * All rights reserved.
29 * Copyright 2018 Joyent, Inc. All rights reserved.
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.
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/multiboot2.h>
44 #include <sys/multiboot2_impl.h>
45 #include <sys/bootvfs.h>
46 #include <sys/bootprops.h>
47 #include <sys/varargs.h>
48 #include <sys/param.h>
49 #include <sys/machparam.h>
50 #include <sys/machsystm.h>
51 #include <sys/archsystm.h>
52 #include <sys/boot_console.h>
53 #include <sys/cmn_err.h>
54 #include <sys/systm.h>
55 #include <sys/promif.h>
56 #include <sys/archsystm.h>
57 #include <sys/x86_archext.h>
58 #include <sys/kobj.h>
59 #include <sys/privregs.h>
60 #include <sys/sysmacros.h>
61 #include <sys/ctype.h>
62 #include <sys/fastboot.h>
63 #include <vm/kboot_mmu.h>
64 #include <vm/hat_pte.h>
65 #include <sys/kobj.h>
66 #include <sys/kobj_lex.h>
67 #include <sys/pci_cfgspace_impl.h>
68 #include <sys/fastboot_impl.h>
69 #include <sys/acpi/acconfig.h>
70 #include <sys/acpi/acpi.h>
72 static int have_console = 0; /* set once primitive console is initialized */
73 static char *boot_args = "";
76 * Debugging macros
78 static uint_t kbm_debug = 0;
79 #define DBG_MSG(s) { if (kbm_debug) bop_printf(NULL, "%s", s); }
80 #define DBG(x) { if (kbm_debug) \
81 bop_printf(NULL, "%s is %" PRIx64 "\n", #x, (uint64_t)(x)); \
84 #define PUT_STRING(s) { \
85 char *cp; \
86 for (cp = (s); *cp; ++cp) \
87 bcons_putchar(*cp); \
90 bootops_t bootop; /* simple bootops we'll pass on to kernel */
91 struct bsys_mem bm;
94 * Boot info from "glue" code in low memory. xbootp is used by:
95 * do_bop_phys_alloc(), do_bsys_alloc() and boot_prop_finish().
97 static struct xboot_info *xbootp;
98 static uintptr_t next_virt; /* next available virtual address */
99 static paddr_t next_phys; /* next available physical address from dboot */
100 static paddr_t high_phys = -(paddr_t)1; /* last used physical address */
103 * buffer for vsnprintf for console I/O
105 #define BUFFERSIZE 512
106 static char buffer[BUFFERSIZE];
109 * stuff to store/report/manipulate boot property settings.
111 typedef struct bootprop {
112 struct bootprop *bp_next;
113 char *bp_name;
114 uint_t bp_vlen;
115 char *bp_value;
116 } bootprop_t;
118 static bootprop_t *bprops = NULL;
119 static char *curr_page = NULL; /* ptr to avail bprop memory */
120 static int curr_space = 0; /* amount of memory at curr_page */
124 * some allocator statistics
126 static ulong_t total_bop_alloc_scratch = 0;
127 static ulong_t total_bop_alloc_kernel = 0;
129 static void build_firmware_properties(struct xboot_info *);
131 static int early_allocation = 1;
133 int force_fastreboot = 0;
134 volatile int fastreboot_onpanic = 0;
135 int post_fastreboot = 0;
136 volatile int fastreboot_capable = 1;
139 * Information saved from current boot for fast reboot.
140 * If the information size exceeds what we have allocated, fast reboot
141 * will not be supported.
143 multiboot_info_t saved_mbi;
144 mb_memory_map_t saved_mmap[FASTBOOT_SAVED_MMAP_COUNT];
145 uint8_t saved_drives[FASTBOOT_SAVED_DRIVES_SIZE];
146 char saved_cmdline[FASTBOOT_SAVED_CMDLINE_LEN];
147 int saved_cmdline_len = 0;
148 size_t saved_file_size[FASTBOOT_MAX_FILES_MAP];
151 * Turn off fastreboot_onpanic to avoid panic loop.
153 char fastreboot_onpanic_cmdline[FASTBOOT_SAVED_CMDLINE_LEN];
154 static const char fastreboot_onpanic_args[] = " -B fastreboot_onpanic=0";
157 * Pointers to where System Resource Affinity Table (SRAT), System Locality
158 * Information Table (SLIT) and Maximum System Capability Table (MSCT)
159 * are mapped into virtual memory
161 ACPI_TABLE_SRAT *srat_ptr = NULL;
162 ACPI_TABLE_SLIT *slit_ptr = NULL;
163 ACPI_TABLE_MSCT *msct_ptr = NULL;
166 * Arbitrary limit on number of localities we handle; if
167 * this limit is raised to more than UINT16_MAX, make sure
168 * process_slit() knows how to handle it.
170 #define SLIT_LOCALITIES_MAX (4096)
172 #define SLIT_NUM_PROPNAME "acpi-slit-localities"
173 #define SLIT_PROPNAME "acpi-slit"
176 * Allocate aligned physical memory at boot time. This allocator allocates
177 * from the highest possible addresses. This avoids exhausting memory that
178 * would be useful for DMA buffers.
180 paddr_t
181 do_bop_phys_alloc(uint64_t size, uint64_t align)
183 paddr_t pa = 0;
184 paddr_t start;
185 paddr_t end;
186 struct memlist *ml = (struct memlist *)xbootp->bi_phys_install;
189 * Be careful if high memory usage is limited in startup.c
190 * Since there are holes in the low part of the physical address
191 * space we can treat physmem as a pfn (not just a pgcnt) and
192 * get a conservative upper limit.
194 if (physmem != 0 && high_phys > pfn_to_pa(physmem))
195 high_phys = pfn_to_pa(physmem);
198 * find the highest available memory in physinstalled
200 size = P2ROUNDUP(size, align);
201 for (; ml; ml = ml->ml_next) {
202 start = P2ROUNDUP(ml->ml_address, align);
203 end = P2ALIGN(ml->ml_address + ml->ml_size, align);
204 if (start < next_phys)
205 start = P2ROUNDUP(next_phys, align);
206 if (end > high_phys)
207 end = P2ALIGN(high_phys, align);
209 if (end <= start)
210 continue;
211 if (end - start < size)
212 continue;
215 * Early allocations need to use low memory, since
216 * physmem might be further limited by bootenv.rc
218 if (early_allocation) {
219 if (pa == 0 || start < pa)
220 pa = start;
221 } else {
222 if (end - size > pa)
223 pa = end - size;
226 if (pa != 0) {
227 if (early_allocation)
228 next_phys = pa + size;
229 else
230 high_phys = pa;
231 return (pa);
233 bop_panic("do_bop_phys_alloc(0x%" PRIx64 ", 0x%" PRIx64
234 ") Out of memory\n", size, align);
235 /*NOTREACHED*/
238 uintptr_t
239 alloc_vaddr(size_t size, paddr_t align)
241 uintptr_t rv;
243 next_virt = P2ROUNDUP(next_virt, (uintptr_t)align);
244 rv = (uintptr_t)next_virt;
245 next_virt += size;
246 return (rv);
250 * Allocate virtual memory. The size is always rounded up to a multiple
251 * of base pagesize.
254 /*ARGSUSED*/
255 static caddr_t
256 do_bsys_alloc(bootops_t *bop, caddr_t virthint, size_t size, int align)
258 paddr_t a = align; /* same type as pa for masking */
259 uint_t pgsize;
260 paddr_t pa;
261 uintptr_t va;
262 ssize_t s; /* the aligned size */
263 uint_t level;
264 uint_t is_kernel = (virthint != 0);
266 if (a < MMU_PAGESIZE)
267 a = MMU_PAGESIZE;
268 else if (!ISP2(a))
269 prom_panic("do_bsys_alloc() incorrect alignment");
270 size = P2ROUNDUP(size, MMU_PAGESIZE);
273 * Use the next aligned virtual address if we weren't given one.
275 if (virthint == NULL) {
276 virthint = (caddr_t)alloc_vaddr(size, a);
277 total_bop_alloc_scratch += size;
278 } else {
279 total_bop_alloc_kernel += size;
283 * allocate the physical memory
285 pa = do_bop_phys_alloc(size, a);
288 * Add the mappings to the page tables, try large pages first.
290 va = (uintptr_t)virthint;
291 s = size;
292 level = 1;
293 pgsize = xbootp->bi_use_pae ? TWO_MEG : FOUR_MEG;
294 if (xbootp->bi_use_largepage && a == pgsize) {
295 while (IS_P2ALIGNED(pa, pgsize) && IS_P2ALIGNED(va, pgsize) &&
296 s >= pgsize) {
297 kbm_map(va, pa, level, is_kernel);
298 va += pgsize;
299 pa += pgsize;
300 s -= pgsize;
305 * Map remaining pages use small mappings
307 level = 0;
308 pgsize = MMU_PAGESIZE;
309 while (s > 0) {
310 kbm_map(va, pa, level, is_kernel);
311 va += pgsize;
312 pa += pgsize;
313 s -= pgsize;
315 return (virthint);
319 * Free virtual memory - we'll just ignore these.
321 /*ARGSUSED*/
322 static void
323 do_bsys_free(bootops_t *bop, caddr_t virt, size_t size)
325 bop_printf(NULL, "do_bsys_free(virt=0x%p, size=0x%lx) ignored\n",
326 (void *)virt, size);
330 * Old interface
332 /*ARGSUSED*/
333 static caddr_t
334 do_bsys_ealloc(bootops_t *bop, caddr_t virthint, size_t size,
335 int align, int flags)
337 prom_panic("unsupported call to BOP_EALLOC()\n");
338 return (0);
342 static void
343 bsetprop(char *name, int nlen, void *value, int vlen)
345 uint_t size;
346 uint_t need_size;
347 bootprop_t *b;
350 * align the size to 16 byte boundary
352 size = sizeof (bootprop_t) + nlen + 1 + vlen;
353 size = (size + 0xf) & ~0xf;
354 if (size > curr_space) {
355 need_size = (size + (MMU_PAGEOFFSET)) & MMU_PAGEMASK;
356 curr_page = do_bsys_alloc(NULL, 0, need_size, MMU_PAGESIZE);
357 curr_space = need_size;
361 * use a bootprop_t at curr_page and link into list
363 b = (bootprop_t *)curr_page;
364 curr_page += sizeof (bootprop_t);
365 curr_space -= sizeof (bootprop_t);
366 b->bp_next = bprops;
367 bprops = b;
370 * follow by name and ending zero byte
372 b->bp_name = curr_page;
373 bcopy(name, curr_page, nlen);
374 curr_page += nlen;
375 *curr_page++ = 0;
376 curr_space -= nlen + 1;
379 * copy in value, but no ending zero byte
381 b->bp_value = curr_page;
382 b->bp_vlen = vlen;
383 if (vlen > 0) {
384 bcopy(value, curr_page, vlen);
385 curr_page += vlen;
386 curr_space -= vlen;
390 * align new values of curr_page, curr_space
392 while (curr_space & 0xf) {
393 ++curr_page;
394 --curr_space;
398 static void
399 bsetprops(char *name, char *value)
401 bsetprop(name, strlen(name), value, strlen(value) + 1);
404 static void
405 bsetprop64(char *name, uint64_t value)
407 bsetprop(name, strlen(name), (void *)&value, sizeof (value));
410 static void
411 bsetpropsi(char *name, int value)
413 char prop_val[32];
415 (void) snprintf(prop_val, sizeof (prop_val), "%d", value);
416 bsetprops(name, prop_val);
420 * to find the size of the buffer to allocate
422 /*ARGSUSED*/
424 do_bsys_getproplen(bootops_t *bop, const char *name)
426 bootprop_t *b;
428 for (b = bprops; b; b = b->bp_next) {
429 if (strcmp(name, b->bp_name) != 0)
430 continue;
431 return (b->bp_vlen);
433 return (-1);
437 * get the value associated with this name
439 /*ARGSUSED*/
441 do_bsys_getprop(bootops_t *bop, const char *name, void *value)
443 bootprop_t *b;
445 for (b = bprops; b; b = b->bp_next) {
446 if (strcmp(name, b->bp_name) != 0)
447 continue;
448 bcopy(b->bp_value, value, b->bp_vlen);
449 return (0);
451 return (-1);
455 * get the name of the next property in succession from the standalone
457 /*ARGSUSED*/
458 static char *
459 do_bsys_nextprop(bootops_t *bop, char *name)
461 bootprop_t *b;
464 * A null name is a special signal for the 1st boot property
466 if (name == NULL || strlen(name) == 0) {
467 if (bprops == NULL)
468 return (NULL);
469 return (bprops->bp_name);
472 for (b = bprops; b; b = b->bp_next) {
473 if (name != b->bp_name)
474 continue;
475 b = b->bp_next;
476 if (b == NULL)
477 return (NULL);
478 return (b->bp_name);
480 return (NULL);
484 * Parse numeric value from a string. Understands decimal, hex, octal, - and ~
486 static int
487 parse_value(char *p, uint64_t *retval)
489 int adjust = 0;
490 uint64_t tmp = 0;
491 int digit;
492 int radix = 10;
494 *retval = 0;
495 if (*p == '-' || *p == '~')
496 adjust = *p++;
498 if (*p == '0') {
499 ++p;
500 if (*p == 0)
501 return (0);
502 if (*p == 'x' || *p == 'X') {
503 radix = 16;
504 ++p;
505 } else {
506 radix = 8;
507 ++p;
510 while (*p) {
511 if ('0' <= *p && *p <= '9')
512 digit = *p - '0';
513 else if ('a' <= *p && *p <= 'f')
514 digit = 10 + *p - 'a';
515 else if ('A' <= *p && *p <= 'F')
516 digit = 10 + *p - 'A';
517 else
518 return (-1);
519 if (digit >= radix)
520 return (-1);
521 tmp = tmp * radix + digit;
522 ++p;
524 if (adjust == '-')
525 tmp = -tmp;
526 else if (adjust == '~')
527 tmp = ~tmp;
528 *retval = tmp;
529 return (0);
532 static boolean_t
533 unprintable(char *value, int size)
535 int i;
537 if (size <= 0 || value[0] == '\0')
538 return (B_TRUE);
540 for (i = 0; i < size; i++) {
541 if (value[i] == '\0')
542 return (i != (size - 1));
544 if (!isprint(value[i]))
545 return (B_TRUE);
547 return (B_FALSE);
551 * Print out information about all boot properties.
552 * buffer is pointer to pre-allocated space to be used as temporary
553 * space for property values.
555 static void
556 boot_prop_display(char *buffer)
558 char *name = "";
559 int i, len;
561 bop_printf(NULL, "\nBoot properties:\n");
563 while ((name = do_bsys_nextprop(NULL, name)) != NULL) {
564 bop_printf(NULL, "\t0x%p %s = ", (void *)name, name);
565 (void) do_bsys_getprop(NULL, name, buffer);
566 len = do_bsys_getproplen(NULL, name);
567 bop_printf(NULL, "len=%d ", len);
568 if (!unprintable(buffer, len)) {
569 buffer[len] = 0;
570 bop_printf(NULL, "%s\n", buffer);
571 continue;
573 for (i = 0; i < len; i++) {
574 bop_printf(NULL, "%02x", buffer[i] & 0xff);
575 if (i < len - 1)
576 bop_printf(NULL, ".");
578 bop_printf(NULL, "\n");
583 * 2nd part of building the table of boot properties. This includes:
584 * - values from /boot/solaris/bootenv.rc (ie. eeprom(1m) values)
586 * lines look like one of:
587 * ^$
588 * ^# comment till end of line
589 * setprop name 'value'
590 * setprop name value
591 * setprop name "value"
593 * we do single character I/O since this is really just looking at memory
595 void
596 boot_prop_finish(void)
598 int fd;
599 char *line;
600 int c;
601 int bytes_read;
602 char *name;
603 int n_len;
604 char *value;
605 int v_len;
606 char *inputdev; /* these override the command line if serial ports */
607 char *outputdev;
608 char *consoledev;
609 uint64_t lvalue;
610 int use_xencons = 0;
613 DBG_MSG("Opening /boot/solaris/bootenv.rc\n");
614 fd = BRD_OPEN(bfs_ops, "/boot/solaris/bootenv.rc", 0);
615 DBG(fd);
617 line = do_bsys_alloc(NULL, NULL, MMU_PAGESIZE, MMU_PAGESIZE);
618 while (fd >= 0) {
621 * get a line
623 for (c = 0; ; ++c) {
624 bytes_read = BRD_READ(bfs_ops, fd, line + c, 1);
625 if (bytes_read == 0) {
626 if (c == 0)
627 goto done;
628 break;
630 if (line[c] == '\n')
631 break;
633 line[c] = 0;
636 * ignore comment lines
638 c = 0;
639 while (ISSPACE(line[c]))
640 ++c;
641 if (line[c] == '#' || line[c] == 0)
642 continue;
645 * must have "setprop " or "setprop\t"
647 if (strncmp(line + c, "setprop ", 8) != 0 &&
648 strncmp(line + c, "setprop\t", 8) != 0)
649 continue;
650 c += 8;
651 while (ISSPACE(line[c]))
652 ++c;
653 if (line[c] == 0)
654 continue;
657 * gather up the property name
659 name = line + c;
660 n_len = 0;
661 while (line[c] && !ISSPACE(line[c]))
662 ++n_len, ++c;
665 * gather up the value, if any
667 value = "";
668 v_len = 0;
669 while (ISSPACE(line[c]))
670 ++c;
671 if (line[c] != 0) {
672 value = line + c;
673 while (line[c] && !ISSPACE(line[c]))
674 ++v_len, ++c;
677 if (v_len >= 2 && value[0] == value[v_len - 1] &&
678 (value[0] == '\'' || value[0] == '"')) {
679 ++value;
680 v_len -= 2;
682 name[n_len] = 0;
683 if (v_len > 0)
684 value[v_len] = 0;
685 else
686 continue;
689 * ignore "boot-file" property, it's now meaningless
691 if (strcmp(name, "boot-file") == 0)
692 continue;
693 if (strcmp(name, "boot-args") == 0 &&
694 strlen(boot_args) > 0)
695 continue;
698 * If a property was explicitly set on the command line
699 * it will override a setting in bootenv.rc
701 if (do_bsys_getproplen(NULL, name) > 0)
702 continue;
704 bsetprop(name, n_len, value, v_len + 1);
706 done:
707 if (fd >= 0)
708 (void) BRD_CLOSE(bfs_ops, fd);
711 * Check if we have to limit the boot time allocator
713 if (do_bsys_getproplen(NULL, "physmem") != -1 &&
714 do_bsys_getprop(NULL, "physmem", line) >= 0 &&
715 parse_value(line, &lvalue) != -1) {
716 if (0 < lvalue && (lvalue < physmem || physmem == 0)) {
717 physmem = (pgcnt_t)lvalue;
718 DBG(physmem);
721 early_allocation = 0;
724 * check to see if we have to override the default value of the console
726 if (!use_xencons) {
727 inputdev = line;
728 v_len = do_bsys_getproplen(NULL, "input-device");
729 if (v_len > 0)
730 (void) do_bsys_getprop(NULL, "input-device", inputdev);
731 else
732 v_len = 0;
733 inputdev[v_len] = 0;
735 outputdev = inputdev + v_len + 1;
736 v_len = do_bsys_getproplen(NULL, "output-device");
737 if (v_len > 0)
738 (void) do_bsys_getprop(NULL, "output-device",
739 outputdev);
740 else
741 v_len = 0;
742 outputdev[v_len] = 0;
744 consoledev = outputdev + v_len + 1;
745 v_len = do_bsys_getproplen(NULL, "console");
746 if (v_len > 0) {
747 (void) do_bsys_getprop(NULL, "console", consoledev);
748 if (post_fastreboot &&
749 strcmp(consoledev, "graphics") == 0) {
750 bsetprops("console", "text");
751 v_len = strlen("text");
752 bcopy("text", consoledev, v_len);
754 } else {
755 v_len = 0;
757 consoledev[v_len] = 0;
758 bcons_init2(inputdev, outputdev, consoledev);
759 } else {
761 * Ensure console property exists
762 * If not create it as "hypervisor"
764 v_len = do_bsys_getproplen(NULL, "console");
765 if (v_len < 0)
766 bsetprops("console", "hypervisor");
767 inputdev = outputdev = consoledev = "hypervisor";
768 bcons_init2(inputdev, outputdev, consoledev);
771 if (find_boot_prop("prom_debug") || kbm_debug)
772 boot_prop_display(line);
776 * print formatted output
778 /*PRINTFLIKE2*/
779 /*ARGSUSED*/
780 void
781 bop_printf(bootops_t *bop, const char *fmt, ...)
783 va_list ap;
785 if (have_console == 0)
786 return;
788 va_start(ap, fmt);
789 (void) vsnprintf(buffer, BUFFERSIZE, fmt, ap);
790 va_end(ap);
791 PUT_STRING(buffer);
795 * Another panic() variant; this one can be used even earlier during boot than
796 * prom_panic().
798 /*PRINTFLIKE1*/
799 void
800 bop_panic(const char *fmt, ...)
802 va_list ap;
804 va_start(ap, fmt);
805 bop_printf(NULL, fmt, ap);
806 va_end(ap);
808 bop_printf(NULL, "\nPress any key to reboot.\n");
809 (void) bcons_getchar();
810 bop_printf(NULL, "Resetting...\n");
811 pc_reset();
815 * Do a real mode interrupt BIOS call
817 typedef struct bios_regs {
818 unsigned short ax, bx, cx, dx, si, di, bp, es, ds;
819 } bios_regs_t;
820 typedef int (*bios_func_t)(int, bios_regs_t *);
822 /*ARGSUSED*/
823 static void
824 do_bsys_doint(bootops_t *bop, int intnum, struct bop_regs *rp)
826 static int firsttime = 1;
827 bios_func_t bios_func = (bios_func_t)(void *)(uintptr_t)0x5000;
828 bios_regs_t br;
831 * We're about to disable paging; we shouldn't be PCID enabled.
833 if (getcr4() & CR4_PCIDE)
834 prom_panic("do_bsys_doint() with PCID enabled\n");
837 * The first time we do this, we have to copy the pre-packaged
838 * low memory bios call code image into place.
840 if (firsttime) {
841 extern char bios_image[];
842 extern uint32_t bios_size;
844 bcopy(bios_image, (void *)bios_func, bios_size);
845 firsttime = 0;
848 br.ax = rp->eax.word.ax;
849 br.bx = rp->ebx.word.bx;
850 br.cx = rp->ecx.word.cx;
851 br.dx = rp->edx.word.dx;
852 br.bp = rp->ebp.word.bp;
853 br.si = rp->esi.word.si;
854 br.di = rp->edi.word.di;
855 br.ds = rp->ds;
856 br.es = rp->es;
858 DBG_MSG("Doing BIOS call...");
859 DBG(br.ax);
860 DBG(br.bx);
861 DBG(br.dx);
862 rp->eflags = bios_func(intnum, &br);
863 DBG_MSG("done\n");
865 rp->eax.word.ax = br.ax;
866 rp->ebx.word.bx = br.bx;
867 rp->ecx.word.cx = br.cx;
868 rp->edx.word.dx = br.dx;
869 rp->ebp.word.bp = br.bp;
870 rp->esi.word.si = br.si;
871 rp->edi.word.di = br.di;
872 rp->ds = br.ds;
873 rp->es = br.es;
876 static struct boot_syscalls bop_sysp = {
877 bcons_getchar,
878 bcons_putchar,
879 bcons_ischar,
882 static char *whoami;
884 #define BUFLEN 64
887 static void
888 setup_rarp_props(struct sol_netinfo *sip)
890 char buf[BUFLEN]; /* to hold ip/mac addrs */
891 uint8_t *val;
893 val = (uint8_t *)&sip->sn_ciaddr;
894 (void) snprintf(buf, BUFLEN, "%d.%d.%d.%d",
895 val[0], val[1], val[2], val[3]);
896 bsetprops(BP_HOST_IP, buf);
898 val = (uint8_t *)&sip->sn_siaddr;
899 (void) snprintf(buf, BUFLEN, "%d.%d.%d.%d",
900 val[0], val[1], val[2], val[3]);
901 bsetprops(BP_SERVER_IP, buf);
903 if (sip->sn_giaddr != 0) {
904 val = (uint8_t *)&sip->sn_giaddr;
905 (void) snprintf(buf, BUFLEN, "%d.%d.%d.%d",
906 val[0], val[1], val[2], val[3]);
907 bsetprops(BP_ROUTER_IP, buf);
910 if (sip->sn_netmask != 0) {
911 val = (uint8_t *)&sip->sn_netmask;
912 (void) snprintf(buf, BUFLEN, "%d.%d.%d.%d",
913 val[0], val[1], val[2], val[3]);
914 bsetprops(BP_SUBNET_MASK, buf);
917 if (sip->sn_mactype != 4 || sip->sn_maclen != 6) {
918 bop_printf(NULL, "unsupported mac type %d, mac len %d\n",
919 sip->sn_mactype, sip->sn_maclen);
920 } else {
921 val = sip->sn_macaddr;
922 (void) snprintf(buf, BUFLEN, "%x:%x:%x:%x:%x:%x",
923 val[0], val[1], val[2], val[3], val[4], val[5]);
924 bsetprops(BP_BOOT_MAC, buf);
929 static void
930 build_panic_cmdline(const char *cmd, int cmdlen)
932 int proplen;
933 size_t arglen;
935 arglen = sizeof (fastreboot_onpanic_args);
937 * If we allready have fastreboot-onpanic set to zero,
938 * don't add them again.
940 if ((proplen = do_bsys_getproplen(NULL, FASTREBOOT_ONPANIC)) > 0 &&
941 proplen <= sizeof (fastreboot_onpanic_cmdline)) {
942 (void) do_bsys_getprop(NULL, FASTREBOOT_ONPANIC,
943 fastreboot_onpanic_cmdline);
944 if (FASTREBOOT_ONPANIC_NOTSET(fastreboot_onpanic_cmdline))
945 arglen = 1;
949 * construct fastreboot_onpanic_cmdline
951 if (cmdlen + arglen > sizeof (fastreboot_onpanic_cmdline)) {
952 DBG_MSG("Command line too long: clearing "
953 FASTREBOOT_ONPANIC "\n");
954 fastreboot_onpanic = 0;
955 } else {
956 bcopy(cmd, fastreboot_onpanic_cmdline, cmdlen);
957 if (arglen != 1)
958 bcopy(fastreboot_onpanic_args,
959 fastreboot_onpanic_cmdline + cmdlen, arglen);
960 else
961 fastreboot_onpanic_cmdline[cmdlen] = 0;
967 * Construct boot command line for Fast Reboot. The saved_cmdline
968 * is also reported by "eeprom bootcmd".
970 static void
971 build_fastboot_cmdline(struct xboot_info *xbp)
973 saved_cmdline_len = strlen(xbp->bi_cmdline) + 1;
974 if (saved_cmdline_len > FASTBOOT_SAVED_CMDLINE_LEN) {
975 DBG(saved_cmdline_len);
976 DBG_MSG("Command line too long: clearing fastreboot_capable\n");
977 fastreboot_capable = 0;
978 } else {
979 bcopy((void *)(xbp->bi_cmdline), (void *)saved_cmdline,
980 saved_cmdline_len);
981 saved_cmdline[saved_cmdline_len - 1] = '\0';
982 build_panic_cmdline(saved_cmdline, saved_cmdline_len - 1);
987 * Save memory layout, disk drive information, unix and boot archive sizes for
988 * Fast Reboot.
990 static void
991 save_boot_info(struct xboot_info *xbi)
993 multiboot_info_t *mbi = xbi->bi_mb_info;
994 struct boot_modules *modp;
995 int i;
997 bcopy(mbi, &saved_mbi, sizeof (multiboot_info_t));
998 if (mbi->mmap_length > sizeof (saved_mmap)) {
999 DBG_MSG("mbi->mmap_length too big: clearing "
1000 "fastreboot_capable\n");
1001 fastreboot_capable = 0;
1002 } else {
1003 bcopy((void *)(uintptr_t)mbi->mmap_addr, (void *)saved_mmap,
1004 mbi->mmap_length);
1007 if ((mbi->flags & MB_INFO_DRIVE_INFO) != 0) {
1008 if (mbi->drives_length > sizeof (saved_drives)) {
1009 DBG(mbi->drives_length);
1010 DBG_MSG("mbi->drives_length too big: clearing "
1011 "fastreboot_capable\n");
1012 fastreboot_capable = 0;
1013 } else {
1014 bcopy((void *)(uintptr_t)mbi->drives_addr,
1015 (void *)saved_drives, mbi->drives_length);
1017 } else {
1018 saved_mbi.drives_length = 0;
1019 saved_mbi.drives_addr = (uintptr_t)NULL;
1023 * Current file sizes. Used by fastboot.c to figure out how much
1024 * memory to reserve for panic reboot.
1025 * Use the module list from the dboot-constructed xboot_info
1026 * instead of the list referenced by the multiboot structure
1027 * because that structure may not be addressable now.
1029 saved_file_size[FASTBOOT_NAME_UNIX] = FOUR_MEG - PAGESIZE;
1030 for (i = 0, modp = (struct boot_modules *)(uintptr_t)xbi->bi_modules;
1031 i < xbi->bi_module_cnt; i++, modp++) {
1032 saved_file_size[FASTBOOT_NAME_BOOTARCHIVE] += modp->bm_size;
1037 * Import boot environment module variables as properties, applying
1038 * blacklist filter for variables we know we will not use.
1040 * Since the environment can be relatively large, containing many variables
1041 * used only for boot loader purposes, we will use a blacklist based filter.
1042 * To keep the blacklist from growing too large, we use prefix based filtering.
1043 * This is possible because in many cases, the loader variable names are
1044 * using a structured layout.
1046 * We will not overwrite already set properties.
1048 static struct bop_blacklist {
1049 const char *bl_name;
1050 int bl_name_len;
1051 } bop_prop_blacklist[] = {
1052 { "ISADIR", sizeof ("ISADIR") },
1053 { "acpi", sizeof ("acpi") },
1054 { "autoboot_delay", sizeof ("autoboot_delay") },
1055 { "autoboot_delay", sizeof ("autoboot_delay") },
1056 { "beansi_", sizeof ("beansi_") },
1057 { "beastie", sizeof ("beastie") },
1058 { "bemenu", sizeof ("bemenu") },
1059 { "boot.", sizeof ("boot.") },
1060 { "bootenv", sizeof ("bootenv") },
1061 { "currdev", sizeof ("currdev") },
1062 { "dhcp.", sizeof ("dhcp.") },
1063 { "interpret", sizeof ("interpret") },
1064 { "kernel", sizeof ("kernel") },
1065 { "loaddev", sizeof ("loaddev") },
1066 { "loader_", sizeof ("loader_") },
1067 { "module_path", sizeof ("module_path") },
1068 { "nfs.", sizeof ("nfs.") },
1069 { "pcibios", sizeof ("pcibios") },
1070 { "prompt", sizeof ("prompt") },
1071 { "smbios", sizeof ("smbios") },
1072 { "tem", sizeof ("tem") },
1073 { "twiddle_divisor", sizeof ("twiddle_divisor") },
1074 { "zfs_be", sizeof ("zfs_be") },
1078 * Match the name against prefixes in above blacklist. If the match was
1079 * found, this name is blacklisted.
1081 static boolean_t
1082 name_is_blacklisted(const char *name)
1084 int i, n;
1086 n = sizeof (bop_prop_blacklist) / sizeof (bop_prop_blacklist[0]);
1087 for (i = 0; i < n; i++) {
1088 if (strncmp(bop_prop_blacklist[i].bl_name, name,
1089 bop_prop_blacklist[i].bl_name_len - 1) == 0) {
1090 return (B_TRUE);
1093 return (B_FALSE);
1096 static void
1097 process_boot_environment(struct boot_modules *benv)
1099 char *env, *ptr, *name, *value;
1100 uint32_t size, name_len, value_len;
1102 if (benv == NULL || benv->bm_type != BMT_ENV)
1103 return;
1104 ptr = env = benv->bm_addr;
1105 size = benv->bm_size;
1106 do {
1107 name = ptr;
1108 /* find '=' */
1109 while (*ptr != '=') {
1110 ptr++;
1111 if (ptr > env + size) /* Something is very wrong. */
1112 return;
1114 name_len = ptr - name;
1115 if (sizeof (buffer) <= name_len)
1116 continue;
1118 (void) strncpy(buffer, name, sizeof (buffer));
1119 buffer[name_len] = '\0';
1120 name = buffer;
1122 value_len = 0;
1123 value = ++ptr;
1124 while ((uintptr_t)ptr - (uintptr_t)env < size) {
1125 if (*ptr == '\0') {
1126 ptr++;
1127 value_len = (uintptr_t)ptr - (uintptr_t)env;
1128 break;
1130 ptr++;
1133 /* Did we reach the end of the module? */
1134 if (value_len == 0)
1135 return;
1137 if (*value == '\0')
1138 continue;
1140 /* Is this property already set? */
1141 if (do_bsys_getproplen(NULL, name) >= 0)
1142 continue;
1144 if (name_is_blacklisted(name) == B_TRUE)
1145 continue;
1147 /* Create new property. */
1148 bsetprops(name, value);
1150 /* Avoid reading past the module end. */
1151 if (size <= (uintptr_t)ptr - (uintptr_t)env)
1152 return;
1153 } while (*ptr != '\0');
1157 * 1st pass at building the table of boot properties. This includes:
1158 * - values set on the command line: -B a=x,b=y,c=z ....
1159 * - known values we just compute (ie. from xbp)
1160 * - values from /boot/solaris/bootenv.rc (ie. eeprom(1m) values)
1162 * the grub command line looked like:
1163 * kernel boot-file [-B prop=value[,prop=value]...] [boot-args]
1165 * whoami is the same as boot-file
1167 static void
1168 build_boot_properties(struct xboot_info *xbp)
1170 char *name;
1171 int name_len;
1172 char *value;
1173 int value_len;
1174 struct boot_modules *bm, *rdbm, *benv = NULL;
1175 char *propbuf;
1176 int quoted = 0;
1177 int boot_arg_len;
1178 uint_t i, midx;
1179 char modid[32];
1180 static int stdout_val = 0;
1181 uchar_t boot_device;
1182 char str[3];
1185 * These have to be done first, so that kobj_mount_root() works
1187 DBG_MSG("Building boot properties\n");
1188 propbuf = do_bsys_alloc(NULL, NULL, MMU_PAGESIZE, 0);
1189 DBG((uintptr_t)propbuf);
1190 if (xbp->bi_module_cnt > 0) {
1191 bm = xbp->bi_modules;
1192 rdbm = NULL;
1193 for (midx = i = 0; i < xbp->bi_module_cnt; i++) {
1194 if (bm[i].bm_type == BMT_ROOTFS) {
1195 rdbm = &bm[i];
1196 continue;
1198 if (bm[i].bm_type == BMT_HASH || bm[i].bm_name == NULL)
1199 continue;
1201 if (bm[i].bm_type == BMT_ENV) {
1202 if (benv == NULL)
1203 benv = &bm[i];
1204 else
1205 continue;
1208 (void) snprintf(modid, sizeof (modid),
1209 "module-name-%u", midx);
1210 bsetprops(modid, (char *)bm[i].bm_name);
1211 (void) snprintf(modid, sizeof (modid),
1212 "module-addr-%u", midx);
1213 bsetprop64(modid, (uint64_t)(uintptr_t)bm[i].bm_addr);
1214 (void) snprintf(modid, sizeof (modid),
1215 "module-size-%u", midx);
1216 bsetprop64(modid, (uint64_t)bm[i].bm_size);
1217 ++midx;
1219 if (rdbm != NULL) {
1220 bsetprop64("ramdisk_start",
1221 (uint64_t)(uintptr_t)rdbm->bm_addr);
1222 bsetprop64("ramdisk_end",
1223 (uint64_t)(uintptr_t)rdbm->bm_addr + rdbm->bm_size);
1228 * If there are any boot time modules or hashes present, then disable
1229 * fast reboot.
1231 if (xbp->bi_module_cnt > 1) {
1232 fastreboot_disable(FBNS_BOOTMOD);
1236 * Disable fast reboot if we're using the Multiboot 2 boot protocol,
1237 * since we don't currently support MB2 info and module relocation.
1238 * Note that fast reboot will have already been disabled if multiple
1239 * modules are present, since the current implementation assumes that
1240 * we only have a single module, the boot_archive.
1242 if (xbp->bi_mb_version != 1) {
1243 fastreboot_disable(FBNS_MULTIBOOT2);
1246 DBG_MSG("Parsing command line for boot properties\n");
1247 value = xbp->bi_cmdline;
1250 * allocate memory to collect boot_args into
1252 boot_arg_len = strlen(xbp->bi_cmdline) + 1;
1253 boot_args = do_bsys_alloc(NULL, NULL, boot_arg_len, MMU_PAGESIZE);
1254 boot_args[0] = 0;
1255 boot_arg_len = 0;
1258 while (ISSPACE(*value))
1259 ++value;
1261 * value now points at the boot-file
1263 value_len = 0;
1264 while (value[value_len] && !ISSPACE(value[value_len]))
1265 ++value_len;
1266 if (value_len > 0) {
1267 whoami = propbuf;
1268 bcopy(value, whoami, value_len);
1269 whoami[value_len] = 0;
1270 bsetprops("boot-file", whoami);
1272 * strip leading path stuff from whoami, so running from
1273 * PXE/miniroot makes sense.
1275 if (strstr(whoami, "/platform/") != NULL)
1276 whoami = strstr(whoami, "/platform/");
1277 bsetprops("whoami", whoami);
1281 * Values forcibly set boot properties on the command line via -B.
1282 * Allow use of quotes in values. Other stuff goes on kernel
1283 * command line.
1285 name = value + value_len;
1286 while (*name != 0) {
1288 * anything not " -B" is copied to the command line
1290 if (!ISSPACE(name[0]) || name[1] != '-' || name[2] != 'B') {
1291 boot_args[boot_arg_len++] = *name;
1292 boot_args[boot_arg_len] = 0;
1293 ++name;
1294 continue;
1298 * skip the " -B" and following white space
1300 name += 3;
1301 while (ISSPACE(*name))
1302 ++name;
1303 while (*name && !ISSPACE(*name)) {
1304 value = strstr(name, "=");
1305 if (value == NULL)
1306 break;
1307 name_len = value - name;
1308 ++value;
1309 value_len = 0;
1310 quoted = 0;
1311 for (; ; ++value_len) {
1312 if (!value[value_len])
1313 break;
1316 * is this value quoted?
1318 if (value_len == 0 &&
1319 (value[0] == '\'' || value[0] == '"')) {
1320 quoted = value[0];
1321 ++value_len;
1325 * In the quote accept any character,
1326 * but look for ending quote.
1328 if (quoted) {
1329 if (value[value_len] == quoted)
1330 quoted = 0;
1331 continue;
1335 * a comma or white space ends the value
1337 if (value[value_len] == ',' ||
1338 ISSPACE(value[value_len]))
1339 break;
1342 if (value_len == 0) {
1343 bsetprop(name, name_len, "true", 5);
1344 } else {
1345 char *v = value;
1346 int l = value_len;
1347 if (v[0] == v[l - 1] &&
1348 (v[0] == '\'' || v[0] == '"')) {
1349 ++v;
1350 l -= 2;
1352 bcopy(v, propbuf, l);
1353 propbuf[l] = '\0';
1354 bsetprop(name, name_len, propbuf,
1355 l + 1);
1357 name = value + value_len;
1358 while (*name == ',')
1359 ++name;
1364 * set boot-args property
1365 * 1275 name is bootargs, so set
1366 * that too
1368 bsetprops("boot-args", boot_args);
1369 bsetprops("bootargs", boot_args);
1371 process_boot_environment(benv);
1374 * Build boot command line for Fast Reboot
1376 build_fastboot_cmdline(xbp);
1378 if (xbp->bi_mb_version == 1) {
1379 multiboot_info_t *mbi = xbp->bi_mb_info;
1380 int netboot;
1381 struct sol_netinfo *sip;
1384 * set the BIOS boot device from GRUB
1386 netboot = 0;
1389 * Save various boot information for Fast Reboot
1391 save_boot_info(xbp);
1393 if (mbi != NULL && mbi->flags & MB_INFO_BOOTDEV) {
1394 boot_device = mbi->boot_device >> 24;
1395 if (boot_device == 0x20)
1396 netboot++;
1397 str[0] = (boot_device >> 4) + '0';
1398 str[1] = (boot_device & 0xf) + '0';
1399 str[2] = 0;
1400 bsetprops("bios-boot-device", str);
1401 } else {
1402 netboot = 1;
1406 * In the netboot case, drives_info is overloaded with the
1407 * dhcp ack. This is not multiboot compliant and requires
1408 * special pxegrub!
1410 if (netboot && mbi->drives_length != 0) {
1411 sip = (struct sol_netinfo *)(uintptr_t)mbi->drives_addr;
1412 if (sip->sn_infotype == SN_TYPE_BOOTP)
1413 bsetprop("bootp-response",
1414 sizeof ("bootp-response"),
1415 (void *)(uintptr_t)mbi->drives_addr,
1416 mbi->drives_length);
1417 else if (sip->sn_infotype == SN_TYPE_RARP)
1418 setup_rarp_props(sip);
1420 } else {
1421 multiboot2_info_header_t *mbi = xbp->bi_mb_info;
1422 multiboot_tag_bootdev_t *bootdev = NULL;
1423 multiboot_tag_network_t *netdev = NULL;
1425 if (mbi != NULL) {
1426 bootdev = dboot_multiboot2_find_tag(mbi,
1427 MULTIBOOT_TAG_TYPE_BOOTDEV);
1428 netdev = dboot_multiboot2_find_tag(mbi,
1429 MULTIBOOT_TAG_TYPE_NETWORK);
1431 if (bootdev != NULL) {
1432 DBG(bootdev->mb_biosdev);
1433 boot_device = bootdev->mb_biosdev;
1434 str[0] = (boot_device >> 4) + '0';
1435 str[1] = (boot_device & 0xf) + '0';
1436 str[2] = 0;
1437 bsetprops("bios-boot-device", str);
1439 if (netdev != NULL) {
1440 bsetprop("bootp-response", sizeof ("bootp-response"),
1441 (void *)(uintptr_t)netdev->mb_dhcpack,
1442 netdev->mb_size -
1443 sizeof (multiboot_tag_network_t));
1447 bsetprop("stdout", strlen("stdout"),
1448 &stdout_val, sizeof (stdout_val));
1451 * more conjured up values for made up things....
1453 bsetprops("mfg-name", "i86pc");
1454 bsetprops("impl-arch-name", "i86pc");
1457 * Build firmware-provided system properties
1459 build_firmware_properties(xbp);
1462 * XXPV
1464 * Find out what these are:
1465 * - cpuid_feature_ecx_include
1466 * - cpuid_feature_ecx_exclude
1467 * - cpuid_feature_edx_include
1468 * - cpuid_feature_edx_exclude
1470 * Find out what these are in multiboot:
1471 * - netdev-path
1472 * - fstype
1478 * simple description of a stack frame (args are 32 bit only currently)
1480 typedef struct bop_frame {
1481 struct bop_frame *old_frame;
1482 pc_t retaddr;
1483 long arg[1];
1484 } bop_frame_t;
1486 void
1487 bop_traceback(bop_frame_t *frame)
1489 pc_t pc;
1490 int cnt;
1491 char *ksym;
1492 ulong_t off;
1494 bop_printf(NULL, "Stack traceback:\n");
1495 for (cnt = 0; cnt < 30; ++cnt) { /* up to 30 frames */
1496 pc = frame->retaddr;
1497 if (pc == 0)
1498 break;
1499 ksym = kobj_getsymname(pc, &off);
1500 if (ksym)
1501 bop_printf(NULL, " %s+%lx", ksym, off);
1502 else
1503 bop_printf(NULL, " 0x%lx", pc);
1505 frame = frame->old_frame;
1506 if (frame == 0) {
1507 bop_printf(NULL, "\n");
1508 break;
1510 bop_printf(NULL, "\n");
1514 struct trapframe {
1515 ulong_t error_code; /* optional */
1516 ulong_t inst_ptr;
1517 ulong_t code_seg;
1518 ulong_t flags_reg;
1519 ulong_t stk_ptr;
1520 ulong_t stk_seg;
1523 void
1524 bop_trap(ulong_t *tfp)
1526 struct trapframe *tf = (struct trapframe *)tfp;
1527 bop_frame_t fakeframe;
1528 static int depth = 0;
1531 * Check for an infinite loop of traps.
1533 if (++depth > 2)
1534 bop_panic("Nested trap");
1536 bop_printf(NULL, "Unexpected trap\n");
1539 * adjust the tf for optional error_code by detecting the code selector
1541 if (tf->code_seg != B64CODE_SEL)
1542 tf = (struct trapframe *)(tfp - 1);
1543 else
1544 bop_printf(NULL, "error code 0x%lx\n",
1545 tf->error_code & 0xffffffff);
1547 bop_printf(NULL, "instruction pointer 0x%lx\n", tf->inst_ptr);
1548 bop_printf(NULL, "code segment 0x%lx\n", tf->code_seg & 0xffff);
1549 bop_printf(NULL, "flags register 0x%lx\n", tf->flags_reg);
1550 bop_printf(NULL, "return %%rsp 0x%lx\n", tf->stk_ptr);
1551 bop_printf(NULL, "return %%ss 0x%lx\n", tf->stk_seg & 0xffff);
1553 /* grab %[er]bp pushed by our code from the stack */
1554 fakeframe.old_frame = (bop_frame_t *)*(tfp - 3);
1555 fakeframe.retaddr = (pc_t)tf->inst_ptr;
1556 bop_printf(NULL, "Attempting stack backtrace:\n");
1557 bop_traceback(&fakeframe);
1558 bop_panic("unexpected trap in early boot");
1561 extern void bop_trap_handler(void);
1563 static gate_desc_t *bop_idt;
1565 static desctbr_t bop_idt_info;
1568 * Install a temporary IDT that lets us catch errors in the boot time code.
1569 * We shouldn't get any faults at all while this is installed, so we'll
1570 * just generate a traceback and exit.
1572 static void
1573 bop_idt_init(void)
1575 int t;
1577 bop_idt = (gate_desc_t *)
1578 do_bsys_alloc(NULL, NULL, MMU_PAGESIZE, MMU_PAGESIZE);
1579 bzero(bop_idt, MMU_PAGESIZE);
1580 for (t = 0; t < NIDT; ++t) {
1582 * Note that since boot runs without a TSS, the
1583 * double fault handler cannot use an alternate stack (64-bit).
1585 set_gatesegd(&bop_idt[t], &bop_trap_handler, B64CODE_SEL,
1586 SDT_SYSIGT, TRP_KPL, 0);
1588 bop_idt_info.dtr_limit = (NIDT * sizeof (gate_desc_t)) - 1;
1589 bop_idt_info.dtr_base = (uintptr_t)bop_idt;
1590 wr_idtr(&bop_idt_info);
1594 * This is where we enter the kernel. It dummies up the boot_ops and
1595 * boot_syscalls vectors and jumps off to _kobj_boot()
1597 void
1598 _start(struct xboot_info *xbp)
1600 bootops_t *bops = &bootop;
1601 extern void _kobj_boot();
1604 * 1st off - initialize the console for any error messages
1606 xbootp = xbp;
1608 if (*((uint32_t *)(FASTBOOT_SWTCH_PA + FASTBOOT_STACK_OFFSET)) ==
1609 FASTBOOT_MAGIC) {
1610 post_fastreboot = 1;
1611 *((uint32_t *)(FASTBOOT_SWTCH_PA + FASTBOOT_STACK_OFFSET)) = 0;
1614 bcons_init(xbp);
1615 have_console = 1;
1618 * enable debugging
1620 if (find_boot_prop("kbm_debug") != NULL)
1621 kbm_debug = 1;
1623 DBG_MSG("\n\n*** Entered Solaris in _start() cmdline is: ");
1624 DBG_MSG((char *)xbp->bi_cmdline);
1625 DBG_MSG("\n\n\n");
1628 * physavail is no longer used by startup
1630 bm.physinstalled = xbp->bi_phys_install;
1631 bm.pcimem = xbp->bi_pcimem;
1632 bm.rsvdmem = xbp->bi_rsvdmem;
1633 bm.physavail = NULL;
1636 * initialize the boot time allocator
1638 next_phys = xbp->bi_next_paddr;
1639 DBG(next_phys);
1640 next_virt = (uintptr_t)xbp->bi_next_vaddr;
1641 DBG(next_virt);
1642 DBG_MSG("Initializing boot time memory management...");
1643 kbm_init(xbp);
1644 DBG_MSG("done\n");
1647 * Fill in the bootops vector
1649 bops->bsys_version = BO_VERSION;
1650 bops->boot_mem = &bm;
1651 bops->bsys_alloc = do_bsys_alloc;
1652 bops->bsys_free = do_bsys_free;
1653 bops->bsys_getproplen = do_bsys_getproplen;
1654 bops->bsys_getprop = do_bsys_getprop;
1655 bops->bsys_nextprop = do_bsys_nextprop;
1656 bops->bsys_printf = bop_printf;
1657 bops->bsys_doint = do_bsys_doint;
1660 * BOP_EALLOC() is no longer needed
1662 bops->bsys_ealloc = do_bsys_ealloc;
1666 * Install an IDT to catch early pagefaults (shouldn't have any).
1667 * Also needed for kmdb.
1669 bop_idt_init();
1672 * Start building the boot properties from the command line
1674 DBG_MSG("Initializing boot properties:\n");
1675 build_boot_properties(xbp);
1677 if (find_boot_prop("prom_debug") || kbm_debug) {
1678 char *value;
1680 value = do_bsys_alloc(NULL, NULL, MMU_PAGESIZE, MMU_PAGESIZE);
1681 boot_prop_display(value);
1685 * jump into krtld...
1687 _kobj_boot(&bop_sysp, NULL, bops, NULL);
1691 /*ARGSUSED*/
1692 static caddr_t
1693 no_more_alloc(bootops_t *bop, caddr_t virthint, size_t size, int align)
1695 panic("Attempt to bsys_alloc() too late\n");
1696 return (NULL);
1699 /*ARGSUSED*/
1700 static void
1701 no_more_free(bootops_t *bop, caddr_t virt, size_t size)
1703 panic("Attempt to bsys_free() too late\n");
1706 void
1707 bop_no_more_mem(void)
1709 DBG(total_bop_alloc_scratch);
1710 DBG(total_bop_alloc_kernel);
1711 bootops->bsys_alloc = no_more_alloc;
1712 bootops->bsys_free = no_more_free;
1717 * Set ACPI firmware properties
1720 static caddr_t
1721 vmap_phys(size_t length, paddr_t pa)
1723 paddr_t start, end;
1724 caddr_t va;
1725 size_t len, page;
1727 start = P2ALIGN(pa, MMU_PAGESIZE);
1728 end = P2ROUNDUP(pa + length, MMU_PAGESIZE);
1729 len = end - start;
1730 va = (caddr_t)alloc_vaddr(len, MMU_PAGESIZE);
1731 for (page = 0; page < len; page += MMU_PAGESIZE)
1732 kbm_map((uintptr_t)va + page, start + page, 0, 0);
1733 return (va + (pa & MMU_PAGEOFFSET));
1736 static uint8_t
1737 checksum_table(uint8_t *tp, size_t len)
1739 uint8_t sum = 0;
1741 while (len-- > 0)
1742 sum += *tp++;
1744 return (sum);
1747 static int
1748 valid_rsdp(ACPI_TABLE_RSDP *rp)
1751 /* validate the V1.x checksum */
1752 if (checksum_table((uint8_t *)rp, ACPI_RSDP_CHECKSUM_LENGTH) != 0)
1753 return (0);
1755 /* If pre-ACPI 2.0, this is a valid RSDP */
1756 if (rp->Revision < 2)
1757 return (1);
1759 /* validate the V2.x checksum */
1760 if (checksum_table((uint8_t *)rp, ACPI_RSDP_XCHECKSUM_LENGTH) != 0)
1761 return (0);
1763 return (1);
1767 * Scan memory range for an RSDP;
1768 * see ACPI 3.0 Spec, 5.2.5.1
1770 static ACPI_TABLE_RSDP *
1771 scan_rsdp(paddr_t start, paddr_t end)
1773 ssize_t len = end - start;
1774 caddr_t ptr;
1776 ptr = vmap_phys(len, start);
1777 while (len > 0) {
1778 if (strncmp(ptr, ACPI_SIG_RSDP, strlen(ACPI_SIG_RSDP)) == 0 &&
1779 valid_rsdp((ACPI_TABLE_RSDP *)ptr))
1780 return ((ACPI_TABLE_RSDP *)ptr);
1782 ptr += ACPI_RSDP_SCAN_STEP;
1783 len -= ACPI_RSDP_SCAN_STEP;
1786 return (NULL);
1790 * Refer to ACPI 3.0 Spec, section 5.2.5.1 to understand this function
1792 static ACPI_TABLE_RSDP *
1793 find_rsdp()
1795 ACPI_TABLE_RSDP *rsdp;
1796 uint64_t rsdp_val = 0;
1797 uint16_t *ebda_seg;
1798 paddr_t ebda_addr;
1800 /* check for "acpi-root-tab" property */
1801 if (do_bsys_getproplen(NULL, "acpi-root-tab") == sizeof (uint64_t)) {
1802 (void) do_bsys_getprop(NULL, "acpi-root-tab", &rsdp_val);
1803 if (rsdp_val != 0) {
1804 rsdp = scan_rsdp(rsdp_val, rsdp_val + sizeof (*rsdp));
1805 if (rsdp != NULL) {
1806 if (kbm_debug) {
1807 bop_printf(NULL,
1808 "Using RSDP from bootloader: "
1809 "0x%p\n", (void *)rsdp);
1811 return (rsdp);
1817 * Get the EBDA segment and scan the first 1K
1819 ebda_seg = (uint16_t *)vmap_phys(sizeof (uint16_t),
1820 ACPI_EBDA_PTR_LOCATION);
1821 ebda_addr = *ebda_seg << 4;
1822 rsdp = scan_rsdp(ebda_addr, ebda_addr + ACPI_EBDA_WINDOW_SIZE);
1823 if (rsdp == NULL)
1824 /* if EBDA doesn't contain RSDP, look in BIOS memory */
1825 rsdp = scan_rsdp(ACPI_HI_RSDP_WINDOW_BASE,
1826 ACPI_HI_RSDP_WINDOW_BASE + ACPI_HI_RSDP_WINDOW_SIZE);
1827 return (rsdp);
1830 static ACPI_TABLE_HEADER *
1831 map_fw_table(paddr_t table_addr)
1833 ACPI_TABLE_HEADER *tp;
1834 size_t len = MAX(sizeof (*tp), MMU_PAGESIZE);
1837 * Map at least a page; if the table is larger than this, remap it
1839 tp = (ACPI_TABLE_HEADER *)vmap_phys(len, table_addr);
1840 if (tp->Length > len)
1841 tp = (ACPI_TABLE_HEADER *)vmap_phys(tp->Length, table_addr);
1842 return (tp);
1845 static ACPI_TABLE_HEADER *
1846 find_fw_table(char *signature)
1848 static int revision = 0;
1849 static ACPI_TABLE_XSDT *xsdt;
1850 static int len;
1851 paddr_t xsdt_addr;
1852 ACPI_TABLE_RSDP *rsdp;
1853 ACPI_TABLE_HEADER *tp;
1854 paddr_t table_addr;
1855 int n;
1857 if (strlen(signature) != ACPI_NAME_SIZE)
1858 return (NULL);
1861 * Reading the ACPI 3.0 Spec, section 5.2.5.3 will help
1862 * understand this code. If we haven't already found the RSDT/XSDT,
1863 * revision will be 0. Find the RSDP and check the revision
1864 * to find out whether to use the RSDT or XSDT. If revision is
1865 * 0 or 1, use the RSDT and set internal revision to 1; if it is 2,
1866 * use the XSDT. If the XSDT address is 0, though, fall back to
1867 * revision 1 and use the RSDT.
1869 if (revision == 0) {
1870 if ((rsdp = find_rsdp()) != NULL) {
1871 revision = rsdp->Revision;
1873 * ACPI 6.0 states that current revision is 2
1874 * from acpi_table_rsdp definition:
1875 * Must be (0) for ACPI 1.0 or (2) for ACPI 2.0+
1877 if (revision > 2)
1878 revision = 2;
1879 switch (revision) {
1880 case 2:
1882 * Use the XSDT unless BIOS is buggy and
1883 * claims to be rev 2 but has a null XSDT
1884 * address
1886 xsdt_addr = rsdp->XsdtPhysicalAddress;
1887 if (xsdt_addr != 0)
1888 break;
1889 /* FALLTHROUGH */
1890 case 0:
1891 /* treat RSDP rev 0 as revision 1 internally */
1892 revision = 1;
1893 /* FALLTHROUGH */
1894 case 1:
1895 /* use the RSDT for rev 0/1 */
1896 xsdt_addr = rsdp->RsdtPhysicalAddress;
1897 break;
1898 default:
1899 /* unknown revision */
1900 revision = 0;
1901 break;
1904 if (revision == 0)
1905 return (NULL);
1907 /* cache the XSDT info */
1908 xsdt = (ACPI_TABLE_XSDT *)map_fw_table(xsdt_addr);
1909 len = (xsdt->Header.Length - sizeof (xsdt->Header)) /
1910 ((revision == 1) ? sizeof (uint32_t) : sizeof (uint64_t));
1914 * Scan the table headers looking for a signature match
1916 for (n = 0; n < len; n++) {
1917 ACPI_TABLE_RSDT *rsdt = (ACPI_TABLE_RSDT *)xsdt;
1918 table_addr = (revision == 1) ? rsdt->TableOffsetEntry[n] :
1919 xsdt->TableOffsetEntry[n];
1921 if (table_addr == 0)
1922 continue;
1923 tp = map_fw_table(table_addr);
1924 if (strncmp(tp->Signature, signature, ACPI_NAME_SIZE) == 0) {
1925 return (tp);
1928 return (NULL);
1931 static void
1932 process_mcfg(ACPI_TABLE_MCFG *tp)
1934 ACPI_MCFG_ALLOCATION *cfg_baap;
1935 char *cfg_baa_endp;
1936 int64_t ecfginfo[4];
1938 cfg_baap = (ACPI_MCFG_ALLOCATION *)((uintptr_t)tp + sizeof (*tp));
1939 cfg_baa_endp = ((char *)tp) + tp->Header.Length;
1940 while ((char *)cfg_baap < cfg_baa_endp) {
1941 if (cfg_baap->Address != 0 && cfg_baap->PciSegment == 0) {
1942 ecfginfo[0] = cfg_baap->Address;
1943 ecfginfo[1] = cfg_baap->PciSegment;
1944 ecfginfo[2] = cfg_baap->StartBusNumber;
1945 ecfginfo[3] = cfg_baap->EndBusNumber;
1946 bsetprop(MCFG_PROPNAME, strlen(MCFG_PROPNAME),
1947 ecfginfo, sizeof (ecfginfo));
1948 break;
1950 cfg_baap++;
1954 static void
1955 process_madt_entries(ACPI_TABLE_MADT *tp, uint32_t *cpu_countp,
1956 uint32_t *cpu_possible_countp, uint32_t *cpu_apicid_array)
1958 ACPI_SUBTABLE_HEADER *item, *end;
1959 uint32_t cpu_count = 0;
1960 uint32_t cpu_possible_count = 0;
1963 * Determine number of CPUs and keep track of "final" APIC ID
1964 * for each CPU by walking through ACPI MADT processor list
1966 end = (ACPI_SUBTABLE_HEADER *)(tp->Header.Length + (uintptr_t)tp);
1967 item = (ACPI_SUBTABLE_HEADER *)((uintptr_t)tp + sizeof (*tp));
1969 while (item < end) {
1970 switch (item->Type) {
1971 case ACPI_MADT_TYPE_LOCAL_APIC: {
1972 ACPI_MADT_LOCAL_APIC *cpu =
1973 (ACPI_MADT_LOCAL_APIC *) item;
1975 if (cpu->LapicFlags & ACPI_MADT_ENABLED) {
1976 if (cpu_apicid_array != NULL)
1977 cpu_apicid_array[cpu_count] = cpu->Id;
1978 cpu_count++;
1980 cpu_possible_count++;
1981 break;
1983 case ACPI_MADT_TYPE_LOCAL_X2APIC: {
1984 ACPI_MADT_LOCAL_X2APIC *cpu =
1985 (ACPI_MADT_LOCAL_X2APIC *) item;
1987 if (cpu->LapicFlags & ACPI_MADT_ENABLED) {
1988 if (cpu_apicid_array != NULL)
1989 cpu_apicid_array[cpu_count] =
1990 cpu->LocalApicId;
1991 cpu_count++;
1993 cpu_possible_count++;
1994 break;
1996 default:
1997 if (kbm_debug)
1998 bop_printf(NULL, "MADT type %d\n", item->Type);
1999 break;
2002 item = (ACPI_SUBTABLE_HEADER *)((uintptr_t)item + item->Length);
2004 if (cpu_countp)
2005 *cpu_countp = cpu_count;
2006 if (cpu_possible_countp)
2007 *cpu_possible_countp = cpu_possible_count;
2010 static void
2011 process_madt(ACPI_TABLE_MADT *tp)
2013 uint32_t cpu_count = 0;
2014 uint32_t cpu_possible_count = 0;
2015 uint32_t *cpu_apicid_array; /* x2APIC ID is 32bit! */
2017 if (tp != NULL) {
2018 /* count cpu's */
2019 process_madt_entries(tp, &cpu_count, &cpu_possible_count, NULL);
2021 cpu_apicid_array = (uint32_t *)do_bsys_alloc(NULL, NULL,
2022 cpu_count * sizeof (*cpu_apicid_array), MMU_PAGESIZE);
2023 if (cpu_apicid_array == NULL)
2024 bop_panic("Not enough memory for APIC ID array");
2026 /* copy IDs */
2027 process_madt_entries(tp, NULL, NULL, cpu_apicid_array);
2030 * Make boot property for array of "final" APIC IDs for each
2031 * CPU
2033 bsetprop(BP_CPU_APICID_ARRAY, strlen(BP_CPU_APICID_ARRAY),
2034 cpu_apicid_array, cpu_count * sizeof (*cpu_apicid_array));
2038 * Check whether property plat-max-ncpus is already set.
2040 if (do_bsys_getproplen(NULL, PLAT_MAX_NCPUS_NAME) < 0) {
2042 * Set plat-max-ncpus to number of maximum possible CPUs given
2043 * in MADT if it hasn't been set.
2044 * There's no formal way to detect max possible CPUs supported
2045 * by platform according to ACPI spec3.0b. So current CPU
2046 * hotplug implementation expects that all possible CPUs will
2047 * have an entry in MADT table and set plat-max-ncpus to number
2048 * of entries in MADT.
2049 * With introducing of ACPI4.0, Maximum System Capability Table
2050 * (MSCT) provides maximum number of CPUs supported by platform.
2051 * If MSCT is unavailable, fall back to old way.
2053 if (tp != NULL)
2054 bsetpropsi(PLAT_MAX_NCPUS_NAME, cpu_possible_count);
2058 * Set boot property boot-max-ncpus to number of CPUs existing at
2059 * boot time. boot-max-ncpus is mainly used for optimization.
2061 if (tp != NULL)
2062 bsetpropsi(BOOT_MAX_NCPUS_NAME, cpu_count);
2065 * User-set boot-ncpus overrides firmware count
2067 if (do_bsys_getproplen(NULL, BOOT_NCPUS_NAME) >= 0)
2068 return;
2071 * Set boot property boot-ncpus to number of active CPUs given in MADT
2072 * if it hasn't been set yet.
2074 if (tp != NULL)
2075 bsetpropsi(BOOT_NCPUS_NAME, cpu_count);
2078 static void
2079 process_srat(ACPI_TABLE_SRAT *tp)
2081 ACPI_SUBTABLE_HEADER *item, *end;
2082 int i;
2083 int proc_num, mem_num;
2084 #pragma pack(1)
2085 struct {
2086 uint32_t domain;
2087 uint32_t apic_id;
2088 uint32_t sapic_id;
2089 } processor;
2090 struct {
2091 uint32_t domain;
2092 uint32_t x2apic_id;
2093 } x2apic;
2094 struct {
2095 uint32_t domain;
2096 uint64_t addr;
2097 uint64_t length;
2098 uint32_t flags;
2099 } memory;
2100 #pragma pack()
2101 char prop_name[30];
2102 uint64_t maxmem = 0;
2104 if (tp == NULL)
2105 return;
2107 proc_num = mem_num = 0;
2108 end = (ACPI_SUBTABLE_HEADER *)(tp->Header.Length + (uintptr_t)tp);
2109 item = (ACPI_SUBTABLE_HEADER *)((uintptr_t)tp + sizeof (*tp));
2110 while (item < end) {
2111 switch (item->Type) {
2112 case ACPI_SRAT_TYPE_CPU_AFFINITY: {
2113 ACPI_SRAT_CPU_AFFINITY *cpu =
2114 (ACPI_SRAT_CPU_AFFINITY *) item;
2116 if (!(cpu->Flags & ACPI_SRAT_CPU_ENABLED))
2117 break;
2118 processor.domain = cpu->ProximityDomainLo;
2119 for (i = 0; i < 3; i++)
2120 processor.domain +=
2121 cpu->ProximityDomainHi[i] << ((i + 1) * 8);
2122 processor.apic_id = cpu->ApicId;
2123 processor.sapic_id = cpu->LocalSapicEid;
2124 (void) snprintf(prop_name, 30, "acpi-srat-processor-%d",
2125 proc_num);
2126 bsetprop(prop_name, strlen(prop_name), &processor,
2127 sizeof (processor));
2128 proc_num++;
2129 break;
2131 case ACPI_SRAT_TYPE_MEMORY_AFFINITY: {
2132 ACPI_SRAT_MEM_AFFINITY *mem =
2133 (ACPI_SRAT_MEM_AFFINITY *)item;
2135 if (!(mem->Flags & ACPI_SRAT_MEM_ENABLED))
2136 break;
2137 memory.domain = mem->ProximityDomain;
2138 memory.addr = mem->BaseAddress;
2139 memory.length = mem->Length;
2140 memory.flags = mem->Flags;
2141 (void) snprintf(prop_name, 30, "acpi-srat-memory-%d",
2142 mem_num);
2143 bsetprop(prop_name, strlen(prop_name), &memory,
2144 sizeof (memory));
2145 if ((mem->Flags & ACPI_SRAT_MEM_HOT_PLUGGABLE) &&
2146 (memory.addr + memory.length > maxmem)) {
2147 maxmem = memory.addr + memory.length;
2149 mem_num++;
2150 break;
2152 case ACPI_SRAT_TYPE_X2APIC_CPU_AFFINITY: {
2153 ACPI_SRAT_X2APIC_CPU_AFFINITY *x2cpu =
2154 (ACPI_SRAT_X2APIC_CPU_AFFINITY *) item;
2156 if (!(x2cpu->Flags & ACPI_SRAT_CPU_ENABLED))
2157 break;
2158 x2apic.domain = x2cpu->ProximityDomain;
2159 x2apic.x2apic_id = x2cpu->ApicId;
2160 (void) snprintf(prop_name, 30, "acpi-srat-processor-%d",
2161 proc_num);
2162 bsetprop(prop_name, strlen(prop_name), &x2apic,
2163 sizeof (x2apic));
2164 proc_num++;
2165 break;
2167 default:
2168 if (kbm_debug)
2169 bop_printf(NULL, "SRAT type %d\n", item->Type);
2170 break;
2173 item = (ACPI_SUBTABLE_HEADER *)
2174 (item->Length + (uintptr_t)item);
2178 * The maximum physical address calculated from the SRAT table is more
2179 * accurate than that calculated from the MSCT table.
2181 if (maxmem != 0) {
2182 plat_dr_physmax = btop(maxmem);
2186 static void
2187 process_slit(ACPI_TABLE_SLIT *tp)
2191 * Check the number of localities; if it's too huge, we just
2192 * return and locality enumeration code will handle this later,
2193 * if possible.
2195 * Note that the size of the table is the square of the
2196 * number of localities; if the number of localities exceeds
2197 * UINT16_MAX, the table size may overflow an int when being
2198 * passed to bsetprop() below.
2200 if (tp->LocalityCount >= SLIT_LOCALITIES_MAX)
2201 return;
2203 bsetprop(SLIT_NUM_PROPNAME, strlen(SLIT_NUM_PROPNAME),
2204 &tp->LocalityCount, sizeof (tp->LocalityCount));
2205 bsetprop(SLIT_PROPNAME, strlen(SLIT_PROPNAME), &tp->Entry,
2206 tp->LocalityCount * tp->LocalityCount);
2209 static ACPI_TABLE_MSCT *
2210 process_msct(ACPI_TABLE_MSCT *tp)
2212 int last_seen = 0;
2213 int proc_num = 0;
2214 ACPI_MSCT_PROXIMITY *item, *end;
2215 extern uint64_t plat_dr_options;
2217 ASSERT(tp != NULL);
2219 end = (ACPI_MSCT_PROXIMITY *)(tp->Header.Length + (uintptr_t)tp);
2220 for (item = (void *)((uintptr_t)tp + tp->ProximityOffset);
2221 item < end;
2222 item = (void *)(item->Length + (uintptr_t)item)) {
2224 * Sanity check according to section 5.2.19.1 of ACPI 4.0.
2225 * Revision 1
2226 * Length 22
2228 if (item->Revision != 1 || item->Length != 22) {
2229 cmn_err(CE_CONT,
2230 "?boot: unknown proximity domain structure in MSCT "
2231 "with Revision(%d), Length(%d).\n",
2232 (int)item->Revision, (int)item->Length);
2233 return (NULL);
2234 } else if (item->RangeStart > item->RangeEnd) {
2235 cmn_err(CE_CONT,
2236 "?boot: invalid proximity domain structure in MSCT "
2237 "with RangeStart(%u), RangeEnd(%u).\n",
2238 item->RangeStart, item->RangeEnd);
2239 return (NULL);
2240 } else if (item->RangeStart != last_seen) {
2242 * Items must be organized in ascending order of the
2243 * proximity domain enumerations.
2245 cmn_err(CE_CONT,
2246 "?boot: invalid proximity domain structure in MSCT,"
2247 " items are not orginized in ascending order.\n");
2248 return (NULL);
2252 * If ProcessorCapacity is 0 then there would be no CPUs in this
2253 * domain.
2255 if (item->ProcessorCapacity != 0) {
2256 proc_num += (item->RangeEnd - item->RangeStart + 1) *
2257 item->ProcessorCapacity;
2260 last_seen = item->RangeEnd - item->RangeStart + 1;
2262 * Break out if all proximity domains have been processed.
2263 * Some BIOSes may have unused items at the end of MSCT table.
2265 if (last_seen > tp->MaxProximityDomains) {
2266 break;
2269 if (last_seen != tp->MaxProximityDomains + 1) {
2270 cmn_err(CE_CONT,
2271 "?boot: invalid proximity domain structure in MSCT, "
2272 "proximity domain count doesn't match.\n");
2273 return (NULL);
2277 * Set plat-max-ncpus property if it hasn't been set yet.
2279 if (do_bsys_getproplen(NULL, PLAT_MAX_NCPUS_NAME) < 0) {
2280 if (proc_num != 0) {
2281 bsetpropsi(PLAT_MAX_NCPUS_NAME, proc_num);
2286 * Use Maximum Physical Address from the MSCT table as upper limit for
2287 * memory hot-adding by default. It may be overridden by value from
2288 * the SRAT table or the "plat-dr-physmax" boot option.
2290 plat_dr_physmax = btop(tp->MaxAddress + 1);
2293 * Existence of MSCT implies CPU/memory hotplug-capability for the
2294 * platform.
2296 plat_dr_options |= PLAT_DR_FEATURE_CPU;
2297 plat_dr_options |= PLAT_DR_FEATURE_MEMORY;
2299 return (tp);
2303 /*ARGSUSED*/
2304 static void
2305 build_firmware_properties(struct xboot_info *xbp)
2307 ACPI_TABLE_HEADER *tp = NULL;
2309 if (xbp->bi_uefi_arch == XBI_UEFI_ARCH_64) {
2310 bsetprops("efi-systype", "64");
2311 bsetprop64("efi-systab",
2312 (uint64_t)(uintptr_t)xbp->bi_uefi_systab);
2313 if (kbm_debug)
2314 bop_printf(NULL, "64-bit UEFI detected.\n");
2315 } else if (xbp->bi_uefi_arch == XBI_UEFI_ARCH_32) {
2316 bsetprops("efi-systype", "32");
2317 bsetprop64("efi-systab",
2318 (uint64_t)(uintptr_t)xbp->bi_uefi_systab);
2319 if (kbm_debug)
2320 bop_printf(NULL, "32-bit UEFI detected.\n");
2323 if (xbp->bi_acpi_rsdp != NULL) {
2324 bsetprop64("acpi-root-tab",
2325 (uint64_t)(uintptr_t)xbp->bi_acpi_rsdp);
2328 if (xbp->bi_smbios != NULL) {
2329 bsetprop64("smbios-address",
2330 (uint64_t)(uintptr_t)xbp->bi_smbios);
2333 if ((tp = find_fw_table(ACPI_SIG_MSCT)) != NULL)
2334 msct_ptr = process_msct((ACPI_TABLE_MSCT *)tp);
2335 else
2336 msct_ptr = NULL;
2338 if ((tp = find_fw_table(ACPI_SIG_MADT)) != NULL)
2339 process_madt((ACPI_TABLE_MADT *)tp);
2341 if ((srat_ptr = (ACPI_TABLE_SRAT *)
2342 find_fw_table(ACPI_SIG_SRAT)) != NULL)
2343 process_srat(srat_ptr);
2345 if (slit_ptr = (ACPI_TABLE_SLIT *)find_fw_table(ACPI_SIG_SLIT))
2346 process_slit(slit_ptr);
2348 tp = find_fw_table(ACPI_SIG_MCFG);
2349 if (tp != NULL)
2350 process_mcfg((ACPI_TABLE_MCFG *)tp);
2354 * fake up a boot property for deferred early console output
2355 * this is used by both graphical boot and the (developer only)
2356 * USB serial console
2358 void *
2359 defcons_init(size_t size)
2361 static char *p = NULL;
2363 p = do_bsys_alloc(NULL, NULL, size, MMU_PAGESIZE);
2364 *p = 0;
2365 bsetprop("deferred-console-buf", strlen("deferred-console-buf") + 1,
2366 &p, sizeof (p));
2367 return (p);
2370 /*ARGSUSED*/
2372 boot_compinfo(int fd, struct compinfo *cbp)
2374 cbp->iscmp = 0;
2375 cbp->blksize = MAXBSIZE;
2376 return (0);
2379 #define BP_MAX_STRLEN 32
2382 * Get value for given boot property
2385 bootprop_getval(const char *prop_name, u_longlong_t *prop_value)
2387 int boot_prop_len;
2388 char str[BP_MAX_STRLEN];
2389 u_longlong_t value;
2391 boot_prop_len = BOP_GETPROPLEN(bootops, prop_name);
2392 if (boot_prop_len < 0 || boot_prop_len > sizeof (str) ||
2393 BOP_GETPROP(bootops, prop_name, str) < 0 ||
2394 kobj_getvalue(str, &value) == -1)
2395 return (-1);
2397 if (prop_value)
2398 *prop_value = value;
2400 return (0);