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