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