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