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