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