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