xref: /onnv-gate/usr/src/uts/i86pc/os/fakebop.c (revision 12004:93f274d4a367)
13446Smrj /*
23446Smrj  * CDDL HEADER START
33446Smrj  *
43446Smrj  * The contents of this file are subject to the terms of the
53446Smrj  * Common Development and Distribution License (the "License").
63446Smrj  * You may not use this file except in compliance with the License.
73446Smrj  *
83446Smrj  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
93446Smrj  * or http://www.opensolaris.org/os/licensing.
103446Smrj  * See the License for the specific language governing permissions
113446Smrj  * and limitations under the License.
123446Smrj  *
133446Smrj  * When distributing Covered Code, include this CDDL HEADER in each
143446Smrj  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
153446Smrj  * If applicable, add the following below this CDDL HEADER, with the
163446Smrj  * fields enclosed by brackets "[]" replaced with your own identifying
173446Smrj  * information: Portions Copyright [yyyy] [name of copyright owner]
183446Smrj  *
193446Smrj  * CDDL HEADER END
203446Smrj  */
213446Smrj 
223446Smrj /*
2311474SJonathan.Adams@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
243446Smrj  * Use is subject to license terms.
253446Smrj  */
26*12004Sjiang.liu@intel.com /*
27*12004Sjiang.liu@intel.com  * Copyright (c) 2010, Intel Corporation.
28*12004Sjiang.liu@intel.com  * All rights reserved.
29*12004Sjiang.liu@intel.com  */
303446Smrj 
313446Smrj /*
323446Smrj  * This file contains the functionality that mimics the boot operations
333446Smrj  * on SPARC systems or the old boot.bin/multiboot programs on x86 systems.
343446Smrj  * The x86 kernel now does everything on its own.
353446Smrj  */
363446Smrj 
373446Smrj #include <sys/types.h>
383446Smrj #include <sys/bootconf.h>
393446Smrj #include <sys/bootsvcs.h>
403446Smrj #include <sys/bootinfo.h>
413446Smrj #include <sys/multiboot.h>
423446Smrj #include <sys/bootvfs.h>
433446Smrj #include <sys/bootprops.h>
443446Smrj #include <sys/varargs.h>
453446Smrj #include <sys/param.h>
463446Smrj #include <sys/machparam.h>
47*12004Sjiang.liu@intel.com #include <sys/machsystm.h>
483446Smrj #include <sys/archsystm.h>
493446Smrj #include <sys/boot_console.h>
503446Smrj #include <sys/cmn_err.h>
513446Smrj #include <sys/systm.h>
523446Smrj #include <sys/promif.h>
533446Smrj #include <sys/archsystm.h>
543446Smrj #include <sys/x86_archext.h>
553446Smrj #include <sys/kobj.h>
563446Smrj #include <sys/privregs.h>
573446Smrj #include <sys/sysmacros.h>
583446Smrj #include <sys/ctype.h>
597656SSherry.Moore@Sun.COM #include <sys/fastboot.h>
605084Sjohnlev #ifdef __xpv
615084Sjohnlev #include <sys/hypervisor.h>
625084Sjohnlev #include <net/if.h>
635084Sjohnlev #endif
643446Smrj #include <vm/kboot_mmu.h>
653446Smrj #include <vm/hat_pte.h>
669053Sjonathan.chew@sun.com #include <sys/kobj.h>
679053Sjonathan.chew@sun.com #include <sys/kobj_lex.h>
6811245SZhijun.Fu@Sun.COM #include <sys/pci_cfgspace_impl.h>
693446Smrj #include "acpi_fw.h"
703446Smrj 
713446Smrj static int have_console = 0;	/* set once primitive console is initialized */
723446Smrj static char *boot_args = "";
733446Smrj 
743446Smrj /*
753446Smrj  * Debugging macros
763446Smrj  */
773446Smrj static uint_t kbm_debug = 0;
783446Smrj #define	DBG_MSG(s)	{ if (kbm_debug) bop_printf(NULL, "%s", s); }
793446Smrj #define	DBG(x)		{ if (kbm_debug)			\
803446Smrj 	bop_printf(NULL, "%s is %" PRIx64 "\n", #x, (uint64_t)(x));	\
813446Smrj 	}
823446Smrj 
833446Smrj #define	PUT_STRING(s) {				\
843446Smrj 	char *cp;				\
853446Smrj 	for (cp = (s); *cp; ++cp)		\
863446Smrj 		bcons_putchar(*cp);		\
873446Smrj 	}
883446Smrj 
893446Smrj struct xboot_info *xbootp;	/* boot info from "glue" code in low memory */
903446Smrj bootops_t bootop;	/* simple bootops we'll pass on to kernel */
913446Smrj struct bsys_mem bm;
923446Smrj 
933446Smrj static uintptr_t next_virt;	/* next available virtual address */
943446Smrj static paddr_t next_phys;	/* next available physical address from dboot */
953446Smrj static paddr_t high_phys = -(paddr_t)1;	/* last used physical address */
963446Smrj 
973446Smrj /*
983446Smrj  * buffer for vsnprintf for console I/O
993446Smrj  */
1003446Smrj #define	BUFFERSIZE	256
1013446Smrj static char buffer[BUFFERSIZE];
1023446Smrj /*
1033446Smrj  * stuff to store/report/manipulate boot property settings.
1043446Smrj  */
1053446Smrj typedef struct bootprop {
1063446Smrj 	struct bootprop *bp_next;
1073446Smrj 	char *bp_name;
1083446Smrj 	uint_t bp_vlen;
1093446Smrj 	char *bp_value;
1103446Smrj } bootprop_t;
1113446Smrj 
1123446Smrj static bootprop_t *bprops = NULL;
1133446Smrj static char *curr_page = NULL;		/* ptr to avail bprop memory */
1143446Smrj static int curr_space = 0;		/* amount of memory at curr_page */
1153446Smrj 
1165084Sjohnlev #ifdef __xpv
1175084Sjohnlev start_info_t *xen_info;
1185084Sjohnlev shared_info_t *HYPERVISOR_shared_info;
1195084Sjohnlev #endif
1205084Sjohnlev 
1213446Smrj /*
1223446Smrj  * some allocator statistics
1233446Smrj  */
1243446Smrj static ulong_t total_bop_alloc_scratch = 0;
1253446Smrj static ulong_t total_bop_alloc_kernel = 0;
1263446Smrj 
1273446Smrj static void build_firmware_properties(void);
1283446Smrj 
1294004Sjosephb static int early_allocation = 1;
1304004Sjosephb 
1319160SSherry.Moore@Sun.COM int force_fastreboot = 0;
13210559SSherry.Moore@Sun.COM volatile int fastreboot_onpanic = 0;
1339160SSherry.Moore@Sun.COM int post_fastreboot = 0;
1347656SSherry.Moore@Sun.COM #ifdef	__xpv
13511686SKonstantin.Ananyev@Sun.COM volatile int fastreboot_capable = 0;
1367656SSherry.Moore@Sun.COM #else
13711686SKonstantin.Ananyev@Sun.COM volatile int fastreboot_capable = 1;
1387656SSherry.Moore@Sun.COM #endif
1397656SSherry.Moore@Sun.COM 
1407656SSherry.Moore@Sun.COM /*
1417656SSherry.Moore@Sun.COM  * Information saved from current boot for fast reboot.
1427656SSherry.Moore@Sun.COM  * If the information size exceeds what we have allocated, fast reboot
1437656SSherry.Moore@Sun.COM  * will not be supported.
1447656SSherry.Moore@Sun.COM  */
1457656SSherry.Moore@Sun.COM multiboot_info_t saved_mbi;
1467656SSherry.Moore@Sun.COM mb_memory_map_t saved_mmap[FASTBOOT_SAVED_MMAP_COUNT];
14710525SKonstantin.Ananyev@Sun.COM uint8_t saved_drives[FASTBOOT_SAVED_DRIVES_SIZE];
1487656SSherry.Moore@Sun.COM char saved_cmdline[FASTBOOT_SAVED_CMDLINE_LEN];
1497656SSherry.Moore@Sun.COM int saved_cmdline_len = 0;
1509160SSherry.Moore@Sun.COM size_t saved_file_size[FASTBOOT_MAX_FILES_MAP];
1519160SSherry.Moore@Sun.COM 
1529160SSherry.Moore@Sun.COM /*
1539160SSherry.Moore@Sun.COM  * Turn off fastreboot_onpanic to avoid panic loop.
1549160SSherry.Moore@Sun.COM  */
1559160SSherry.Moore@Sun.COM char fastreboot_onpanic_cmdline[FASTBOOT_SAVED_CMDLINE_LEN];
1569160SSherry.Moore@Sun.COM static const char fastreboot_onpanic_args[] = " -B fastreboot_onpanic=0";
1577656SSherry.Moore@Sun.COM 
1583446Smrj /*
159*12004Sjiang.liu@intel.com  * Pointers to where System Resource Affinity Table (SRAT), System Locality
160*12004Sjiang.liu@intel.com  * Information Table (SLIT) and Maximum System Capability Table (MSCT)
161*12004Sjiang.liu@intel.com  * are mapped into virtual memory
1626445Sjjc  */
1636445Sjjc struct srat	*srat_ptr = NULL;
1646445Sjjc struct slit	*slit_ptr = NULL;
165*12004Sjiang.liu@intel.com struct msct	*msct_ptr = NULL;
1666445Sjjc 
1676445Sjjc /*
1683446Smrj  * Allocate aligned physical memory at boot time. This allocator allocates
1693446Smrj  * from the highest possible addresses. This avoids exhausting memory that
1703446Smrj  * would be useful for DMA buffers.
1713446Smrj  */
1723446Smrj paddr_t
do_bop_phys_alloc(uint64_t size,uint64_t align)1733446Smrj do_bop_phys_alloc(uint64_t size, uint64_t align)
1743446Smrj {
1753446Smrj 	paddr_t	pa = 0;
1763446Smrj 	paddr_t	start;
1773446Smrj 	paddr_t	end;
1783446Smrj 	struct memlist	*ml = (struct memlist *)xbootp->bi_phys_install;
1793446Smrj 
1803446Smrj 	/*
1813446Smrj 	 * Be careful if high memory usage is limited in startup.c
1823446Smrj 	 * Since there are holes in the low part of the physical address
1833446Smrj 	 * space we can treat physmem as a pfn (not just a pgcnt) and
1843446Smrj 	 * get a conservative upper limit.
1853446Smrj 	 */
1863446Smrj 	if (physmem != 0 && high_phys > pfn_to_pa(physmem))
1873446Smrj 		high_phys = pfn_to_pa(physmem);
1883446Smrj 
1893446Smrj 	/*
1904004Sjosephb 	 * find the lowest or highest available memory in physinstalled
1915084Sjohnlev 	 * On 32 bit avoid physmem above 4Gig if PAE isn't enabled
1925084Sjohnlev 	 */
1935084Sjohnlev #if defined(__i386)
1945084Sjohnlev 	if (xbootp->bi_use_pae == 0 && high_phys > FOUR_GIG)
1955084Sjohnlev 		high_phys = FOUR_GIG;
1965084Sjohnlev #endif
1975084Sjohnlev 
1985084Sjohnlev 	/*
1995084Sjohnlev 	 * find the highest available memory in physinstalled
2003446Smrj 	 */
2013446Smrj 	size = P2ROUNDUP(size, align);
20211474SJonathan.Adams@Sun.COM 	for (; ml; ml = ml->ml_next) {
20311474SJonathan.Adams@Sun.COM 		start = P2ROUNDUP(ml->ml_address, align);
20411474SJonathan.Adams@Sun.COM 		end = P2ALIGN(ml->ml_address + ml->ml_size, align);
2053446Smrj 		if (start < next_phys)
2064004Sjosephb 			start = P2ROUNDUP(next_phys, align);
2073446Smrj 		if (end > high_phys)
2083446Smrj 			end = P2ALIGN(high_phys, align);
2093446Smrj 
2103446Smrj 		if (end <= start)
2113446Smrj 			continue;
2123446Smrj 		if (end - start < size)
2133446Smrj 			continue;
2143446Smrj 
2154004Sjosephb 		/*
2164004Sjosephb 		 * Early allocations need to use low memory, since
2174004Sjosephb 		 * physmem might be further limited by bootenv.rc
2184004Sjosephb 		 */
2194004Sjosephb 		if (early_allocation) {
2204004Sjosephb 			if (pa == 0 || start < pa)
2214004Sjosephb 				pa = start;
2224004Sjosephb 		} else {
2234004Sjosephb 			if (end - size > pa)
2244004Sjosephb 				pa = end - size;
2254004Sjosephb 		}
2263446Smrj 	}
2273446Smrj 	if (pa != 0) {
2284004Sjosephb 		if (early_allocation)
2294004Sjosephb 			next_phys = pa + size;
2304004Sjosephb 		else
2314004Sjosephb 			high_phys = pa;
2323446Smrj 		return (pa);
2333446Smrj 	}
2346336Sbholler 	bop_panic("do_bop_phys_alloc(0x%" PRIx64 ", 0x%" PRIx64
2356336Sbholler 	    ") Out of memory\n", size, align);
2363446Smrj 	/*NOTREACHED*/
2373446Smrj }
2383446Smrj 
23911245SZhijun.Fu@Sun.COM uintptr_t
alloc_vaddr(size_t size,paddr_t align)2403446Smrj alloc_vaddr(size_t size, paddr_t align)
2413446Smrj {
2423446Smrj 	uintptr_t rv;
2433446Smrj 
2443446Smrj 	next_virt = P2ROUNDUP(next_virt, (uintptr_t)align);
2453446Smrj 	rv = (uintptr_t)next_virt;
2463446Smrj 	next_virt += size;
2473446Smrj 	return (rv);
2483446Smrj }
2493446Smrj 
2503446Smrj /*
2513446Smrj  * Allocate virtual memory. The size is always rounded up to a multiple
2523446Smrj  * of base pagesize.
2533446Smrj  */
2543446Smrj 
2553446Smrj /*ARGSUSED*/
2563446Smrj static caddr_t
do_bsys_alloc(bootops_t * bop,caddr_t virthint,size_t size,int align)2573446Smrj do_bsys_alloc(bootops_t *bop, caddr_t virthint, size_t size, int align)
2583446Smrj {
2593446Smrj 	paddr_t a = align;	/* same type as pa for masking */
2603446Smrj 	uint_t pgsize;
2613446Smrj 	paddr_t pa;
2623446Smrj 	uintptr_t va;
2633446Smrj 	ssize_t s;		/* the aligned size */
2643446Smrj 	uint_t level;
2653446Smrj 	uint_t is_kernel = (virthint != 0);
2663446Smrj 
2673446Smrj 	if (a < MMU_PAGESIZE)
2683446Smrj 		a = MMU_PAGESIZE;
2693446Smrj 	else if (!ISP2(a))
2703446Smrj 		prom_panic("do_bsys_alloc() incorrect alignment");
2713446Smrj 	size = P2ROUNDUP(size, MMU_PAGESIZE);
2723446Smrj 
2733446Smrj 	/*
2743446Smrj 	 * Use the next aligned virtual address if we weren't given one.
2753446Smrj 	 */
2763446Smrj 	if (virthint == NULL) {
2773446Smrj 		virthint = (caddr_t)alloc_vaddr(size, a);
2783446Smrj 		total_bop_alloc_scratch += size;
2793446Smrj 	} else {
2803446Smrj 		total_bop_alloc_kernel += size;
2813446Smrj 	}
2823446Smrj 
2833446Smrj 	/*
2843446Smrj 	 * allocate the physical memory
2853446Smrj 	 */
2863446Smrj 	pa = do_bop_phys_alloc(size, a);
2873446Smrj 
2883446Smrj 	/*
2893446Smrj 	 * Add the mappings to the page tables, try large pages first.
2903446Smrj 	 */
2913446Smrj 	va = (uintptr_t)virthint;
2923446Smrj 	s = size;
2933446Smrj 	level = 1;
2943446Smrj 	pgsize = xbootp->bi_use_pae ? TWO_MEG : FOUR_MEG;
2953446Smrj 	if (xbootp->bi_use_largepage && a == pgsize) {
2963446Smrj 		while (IS_P2ALIGNED(pa, pgsize) && IS_P2ALIGNED(va, pgsize) &&
2973446Smrj 		    s >= pgsize) {
2983446Smrj 			kbm_map(va, pa, level, is_kernel);
2993446Smrj 			va += pgsize;
3003446Smrj 			pa += pgsize;
3013446Smrj 			s -= pgsize;
3023446Smrj 		}
3033446Smrj 	}
3043446Smrj 
3053446Smrj 	/*
3063446Smrj 	 * Map remaining pages use small mappings
3073446Smrj 	 */
3083446Smrj 	level = 0;
3093446Smrj 	pgsize = MMU_PAGESIZE;
3103446Smrj 	while (s > 0) {
3113446Smrj 		kbm_map(va, pa, level, is_kernel);
3123446Smrj 		va += pgsize;
3133446Smrj 		pa += pgsize;
3143446Smrj 		s -= pgsize;
3153446Smrj 	}
3163446Smrj 	return (virthint);
3173446Smrj }
3183446Smrj 
3193446Smrj /*
3203446Smrj  * Free virtual memory - we'll just ignore these.
3213446Smrj  */
3223446Smrj /*ARGSUSED*/
3233446Smrj static void
do_bsys_free(bootops_t * bop,caddr_t virt,size_t size)3243446Smrj do_bsys_free(bootops_t *bop, caddr_t virt, size_t size)
3253446Smrj {
3263446Smrj 	bop_printf(NULL, "do_bsys_free(virt=0x%p, size=0x%lx) ignored\n",
3273446Smrj 	    (void *)virt, size);
3283446Smrj }
3293446Smrj 
3303446Smrj /*
3313446Smrj  * Old interface
3323446Smrj  */
3333446Smrj /*ARGSUSED*/
3343446Smrj static caddr_t
do_bsys_ealloc(bootops_t * bop,caddr_t virthint,size_t size,int align,int flags)3353446Smrj do_bsys_ealloc(
3363446Smrj 	bootops_t *bop,
3373446Smrj 	caddr_t virthint,
3383446Smrj 	size_t size,
3393446Smrj 	int align,
3403446Smrj 	int flags)
3413446Smrj {
3423446Smrj 	prom_panic("unsupported call to BOP_EALLOC()\n");
3433446Smrj 	return (0);
3443446Smrj }
3453446Smrj 
3463446Smrj 
3473446Smrj static void
bsetprop(char * name,int nlen,void * value,int vlen)3483446Smrj bsetprop(char *name, int nlen, void *value, int vlen)
3493446Smrj {
3503446Smrj 	uint_t size;
3513446Smrj 	uint_t need_size;
3523446Smrj 	bootprop_t *b;
3533446Smrj 
3543446Smrj 	/*
3553446Smrj 	 * align the size to 16 byte boundary
3563446Smrj 	 */
3573446Smrj 	size = sizeof (bootprop_t) + nlen + 1 + vlen;
3583446Smrj 	size = (size + 0xf) & ~0xf;
3593446Smrj 	if (size > curr_space) {
3603446Smrj 		need_size = (size + (MMU_PAGEOFFSET)) & MMU_PAGEMASK;
3613446Smrj 		curr_page = do_bsys_alloc(NULL, 0, need_size, MMU_PAGESIZE);
3623446Smrj 		curr_space = need_size;
3633446Smrj 	}
3643446Smrj 
3653446Smrj 	/*
3663446Smrj 	 * use a bootprop_t at curr_page and link into list
3673446Smrj 	 */
3683446Smrj 	b = (bootprop_t *)curr_page;
3693446Smrj 	curr_page += sizeof (bootprop_t);
3703446Smrj 	curr_space -=  sizeof (bootprop_t);
3713446Smrj 	b->bp_next = bprops;
3723446Smrj 	bprops = b;
3733446Smrj 
3743446Smrj 	/*
3753446Smrj 	 * follow by name and ending zero byte
3763446Smrj 	 */
3773446Smrj 	b->bp_name = curr_page;
3783446Smrj 	bcopy(name, curr_page, nlen);
3793446Smrj 	curr_page += nlen;
3803446Smrj 	*curr_page++ = 0;
3813446Smrj 	curr_space -= nlen + 1;
3823446Smrj 
3833446Smrj 	/*
3843446Smrj 	 * copy in value, but no ending zero byte
3853446Smrj 	 */
3863446Smrj 	b->bp_value = curr_page;
3873446Smrj 	b->bp_vlen = vlen;
3883446Smrj 	if (vlen > 0) {
3893446Smrj 		bcopy(value, curr_page, vlen);
3903446Smrj 		curr_page += vlen;
3913446Smrj 		curr_space -= vlen;
3923446Smrj 	}
3933446Smrj 
3943446Smrj 	/*
3953446Smrj 	 * align new values of curr_page, curr_space
3963446Smrj 	 */
3973446Smrj 	while (curr_space & 0xf) {
3983446Smrj 		++curr_page;
3993446Smrj 		--curr_space;
4003446Smrj 	}
4013446Smrj }
4023446Smrj 
4033446Smrj static void
bsetprops(char * name,char * value)4043446Smrj bsetprops(char *name, char *value)
4053446Smrj {
4063446Smrj 	bsetprop(name, strlen(name), value, strlen(value) + 1);
4073446Smrj }
4083446Smrj 
4093446Smrj static void
bsetprop64(char * name,uint64_t value)4103446Smrj bsetprop64(char *name, uint64_t value)
4113446Smrj {
4123446Smrj 	bsetprop(name, strlen(name), (void *)&value, sizeof (value));
4133446Smrj }
4143446Smrj 
4153446Smrj static void
bsetpropsi(char * name,int value)4163446Smrj bsetpropsi(char *name, int value)
4173446Smrj {
4183446Smrj 	char prop_val[32];
4193446Smrj 
4203446Smrj 	(void) snprintf(prop_val, sizeof (prop_val), "%d", value);
4213446Smrj 	bsetprops(name, prop_val);
4223446Smrj }
4233446Smrj 
4243446Smrj /*
4253446Smrj  * to find the size of the buffer to allocate
4263446Smrj  */
4273446Smrj /*ARGSUSED*/
4284088Srscott int
do_bsys_getproplen(bootops_t * bop,const char * name)4295648Ssetje do_bsys_getproplen(bootops_t *bop, const char *name)
4303446Smrj {
4313446Smrj 	bootprop_t *b;
4323446Smrj 
4333446Smrj 	for (b = bprops; b; b = b->bp_next) {
4343446Smrj 		if (strcmp(name, b->bp_name) != 0)
4353446Smrj 			continue;
4363446Smrj 		return (b->bp_vlen);
4373446Smrj 	}
4383446Smrj 	return (-1);
4393446Smrj }
4403446Smrj 
4413446Smrj /*
4423446Smrj  * get the value associated with this name
4433446Smrj  */
4443446Smrj /*ARGSUSED*/
4454088Srscott int
do_bsys_getprop(bootops_t * bop,const char * name,void * value)4465648Ssetje do_bsys_getprop(bootops_t *bop, const char *name, void *value)
4473446Smrj {
4483446Smrj 	bootprop_t *b;
4493446Smrj 
4503446Smrj 	for (b = bprops; b; b = b->bp_next) {
4513446Smrj 		if (strcmp(name, b->bp_name) != 0)
4523446Smrj 			continue;
4533446Smrj 		bcopy(b->bp_value, value, b->bp_vlen);
4543446Smrj 		return (0);
4553446Smrj 	}
4563446Smrj 	return (-1);
4573446Smrj }
4583446Smrj 
4593446Smrj /*
4603446Smrj  * get the name of the next property in succession from the standalone
4613446Smrj  */
4623446Smrj /*ARGSUSED*/
4633446Smrj static char *
do_bsys_nextprop(bootops_t * bop,char * name)4643446Smrj do_bsys_nextprop(bootops_t *bop, char *name)
4653446Smrj {
4663446Smrj 	bootprop_t *b;
4673446Smrj 
4683446Smrj 	/*
4693446Smrj 	 * A null name is a special signal for the 1st boot property
4703446Smrj 	 */
4713446Smrj 	if (name == NULL || strlen(name) == 0) {
4723446Smrj 		if (bprops == NULL)
4733446Smrj 			return (NULL);
4743446Smrj 		return (bprops->bp_name);
4753446Smrj 	}
4763446Smrj 
4773446Smrj 	for (b = bprops; b; b = b->bp_next) {
4783446Smrj 		if (name != b->bp_name)
4793446Smrj 			continue;
4803446Smrj 		b = b->bp_next;
4813446Smrj 		if (b == NULL)
4823446Smrj 			return (NULL);
4833446Smrj 		return (b->bp_name);
4843446Smrj 	}
4853446Smrj 	return (NULL);
4863446Smrj }
4873446Smrj 
4883446Smrj /*
4894004Sjosephb  * Parse numeric value from a string. Understands decimal, hex, octal, - and ~
4904004Sjosephb  */
4914004Sjosephb static int
parse_value(char * p,uint64_t * retval)4924004Sjosephb parse_value(char *p, uint64_t *retval)
4934004Sjosephb {
4944004Sjosephb 	int adjust = 0;
4954004Sjosephb 	uint64_t tmp = 0;
4964004Sjosephb 	int digit;
4974004Sjosephb 	int radix = 10;
4984004Sjosephb 
4994004Sjosephb 	*retval = 0;
5004004Sjosephb 	if (*p == '-' || *p == '~')
5014004Sjosephb 		adjust = *p++;
5024004Sjosephb 
5034004Sjosephb 	if (*p == '0') {
5044004Sjosephb 		++p;
5054004Sjosephb 		if (*p == 0)
5064004Sjosephb 			return (0);
5074004Sjosephb 		if (*p == 'x' || *p == 'X') {
5084004Sjosephb 			radix = 16;
5094004Sjosephb 			++p;
5104004Sjosephb 		} else {
5114004Sjosephb 			radix = 8;
5124004Sjosephb 			++p;
5134004Sjosephb 		}
5144004Sjosephb 	}
5154004Sjosephb 	while (*p) {
5164004Sjosephb 		if ('0' <= *p && *p <= '9')
5174004Sjosephb 			digit = *p - '0';
5184004Sjosephb 		else if ('a' <= *p && *p <= 'f')
5194004Sjosephb 			digit = 10 + *p - 'a';
5204004Sjosephb 		else if ('A' <= *p && *p <= 'F')
5214004Sjosephb 			digit = 10 + *p - 'A';
5224004Sjosephb 		else
5234004Sjosephb 			return (-1);
5244004Sjosephb 		if (digit >= radix)
5254004Sjosephb 			return (-1);
5264004Sjosephb 		tmp = tmp * radix + digit;
5274004Sjosephb 		++p;
5284004Sjosephb 	}
5294004Sjosephb 	if (adjust == '-')
5304004Sjosephb 		tmp = -tmp;
5314004Sjosephb 	else if (adjust == '~')
5324004Sjosephb 		tmp = ~tmp;
5334004Sjosephb 	*retval = tmp;
5344004Sjosephb 	return (0);
5354004Sjosephb }
5364004Sjosephb 
5374004Sjosephb /*
5383446Smrj  * 2nd part of building the table of boot properties. This includes:
5393446Smrj  * - values from /boot/solaris/bootenv.rc (ie. eeprom(1m) values)
5403446Smrj  *
5413446Smrj  * lines look like one of:
5423446Smrj  * ^$
5433446Smrj  * ^# comment till end of line
5443446Smrj  * setprop name 'value'
5453446Smrj  * setprop name value
5463446Smrj  * setprop name "value"
5473446Smrj  *
5483446Smrj  * we do single character I/O since this is really just looking at memory
5493446Smrj  */
5503446Smrj void
boot_prop_finish(void)5513446Smrj boot_prop_finish(void)
5523446Smrj {
5533446Smrj 	int fd;
5543446Smrj 	char *line;
5553446Smrj 	int c;
5563446Smrj 	int bytes_read;
5573446Smrj 	char *name;
5583446Smrj 	int n_len;
5593446Smrj 	char *value;
5603446Smrj 	int v_len;
5615084Sjohnlev 	char *inputdev;	/* these override the command line if serial ports */
5623446Smrj 	char *outputdev;
5633446Smrj 	char *consoledev;
5644004Sjosephb 	uint64_t lvalue;
5655084Sjohnlev 	int use_xencons = 0;
5665084Sjohnlev 
5675084Sjohnlev #ifdef __xpv
5685084Sjohnlev 	if (!DOMAIN_IS_INITDOMAIN(xen_info))
5695084Sjohnlev 		use_xencons = 1;
5705084Sjohnlev #endif /* __xpv */
5713446Smrj 
5723446Smrj 	DBG_MSG("Opening /boot/solaris/bootenv.rc\n");
5733446Smrj 	fd = BRD_OPEN(bfs_ops, "/boot/solaris/bootenv.rc", 0);
5743446Smrj 	DBG(fd);
5753446Smrj 
5763446Smrj 	line = do_bsys_alloc(NULL, NULL, MMU_PAGESIZE, MMU_PAGESIZE);
5773446Smrj 	while (fd >= 0) {
5783446Smrj 
5793446Smrj 		/*
5803446Smrj 		 * get a line
5813446Smrj 		 */
5823446Smrj 		for (c = 0; ; ++c) {
5833446Smrj 			bytes_read = BRD_READ(bfs_ops, fd, line + c, 1);
5843446Smrj 			if (bytes_read == 0) {
5853446Smrj 				if (c == 0)
5863446Smrj 					goto done;
5873446Smrj 				break;
5883446Smrj 			}
5893446Smrj 			if (line[c] == '\n')
5903446Smrj 				break;
5913446Smrj 		}
5923446Smrj 		line[c] = 0;
5933446Smrj 
5943446Smrj 		/*
5953446Smrj 		 * ignore comment lines
5963446Smrj 		 */
5973446Smrj 		c = 0;
5983446Smrj 		while (ISSPACE(line[c]))
5993446Smrj 			++c;
6003446Smrj 		if (line[c] == '#' || line[c] == 0)
6013446Smrj 			continue;
6023446Smrj 
6033446Smrj 		/*
6043446Smrj 		 * must have "setprop " or "setprop\t"
6053446Smrj 		 */
6063446Smrj 		if (strncmp(line + c, "setprop ", 8) != 0 &&
6073446Smrj 		    strncmp(line + c, "setprop\t", 8) != 0)
6083446Smrj 			continue;
6093446Smrj 		c += 8;
6103446Smrj 		while (ISSPACE(line[c]))
6113446Smrj 			++c;
6123446Smrj 		if (line[c] == 0)
6133446Smrj 			continue;
6143446Smrj 
6153446Smrj 		/*
6163446Smrj 		 * gather up the property name
6173446Smrj 		 */
6183446Smrj 		name = line + c;
6193446Smrj 		n_len = 0;
6203446Smrj 		while (line[c] && !ISSPACE(line[c]))
6213446Smrj 			++n_len, ++c;
6223446Smrj 
6233446Smrj 		/*
6243446Smrj 		 * gather up the value, if any
6253446Smrj 		 */
6263446Smrj 		value = "";
6273446Smrj 		v_len = 0;
6283446Smrj 		while (ISSPACE(line[c]))
6293446Smrj 			++c;
6303446Smrj 		if (line[c] != 0) {
6313446Smrj 			value = line + c;
6323446Smrj 			while (line[c] && !ISSPACE(line[c]))
6333446Smrj 				++v_len, ++c;
6343446Smrj 		}
6353446Smrj 
6363446Smrj 		if (v_len >= 2 && value[0] == value[v_len - 1] &&
6373446Smrj 		    (value[0] == '\'' || value[0] == '"')) {
6383446Smrj 			++value;
6393446Smrj 			v_len -= 2;
6403446Smrj 		}
6413446Smrj 		name[n_len] = 0;
6423446Smrj 		if (v_len > 0)
6433446Smrj 			value[v_len] = 0;
6443446Smrj 		else
6453446Smrj 			continue;
6463446Smrj 
6473446Smrj 		/*
6483446Smrj 		 * ignore "boot-file" property, it's now meaningless
6493446Smrj 		 */
6503446Smrj 		if (strcmp(name, "boot-file") == 0)
6513446Smrj 			continue;
6523446Smrj 		if (strcmp(name, "boot-args") == 0 &&
6533446Smrj 		    strlen(boot_args) > 0)
6543446Smrj 			continue;
6553446Smrj 
6563446Smrj 		/*
6574088Srscott 		 * If a property was explicitly set on the command line
6584088Srscott 		 * it will override a setting in bootenv.rc
6593446Smrj 		 */
6604088Srscott 		if (do_bsys_getproplen(NULL, name) > 0)
6613446Smrj 			continue;
6623446Smrj 
6633446Smrj 		bsetprop(name, n_len, value, v_len + 1);
6643446Smrj 	}
6653446Smrj done:
6663446Smrj 	if (fd >= 0)
6673446Smrj 		BRD_CLOSE(bfs_ops, fd);
6683446Smrj 
6693446Smrj 	/*
6704004Sjosephb 	 * Check if we have to limit the boot time allocator
6714004Sjosephb 	 */
6724004Sjosephb 	if (do_bsys_getproplen(NULL, "physmem") != -1 &&
6734004Sjosephb 	    do_bsys_getprop(NULL, "physmem", line) >= 0 &&
6744004Sjosephb 	    parse_value(line, &lvalue) != -1) {
6754004Sjosephb 		if (0 < lvalue && (lvalue < physmem || physmem == 0)) {
6764004Sjosephb 			physmem = (pgcnt_t)lvalue;
6774004Sjosephb 			DBG(physmem);
6784004Sjosephb 		}
6794004Sjosephb 	}
6804004Sjosephb 	early_allocation = 0;
6814004Sjosephb 
6824004Sjosephb 	/*
6833446Smrj 	 * check to see if we have to override the default value of the console
6843446Smrj 	 */
6855084Sjohnlev 	if (!use_xencons) {
6865084Sjohnlev 		inputdev = line;
6875084Sjohnlev 		v_len = do_bsys_getproplen(NULL, "input-device");
6885084Sjohnlev 		if (v_len > 0)
6895084Sjohnlev 			(void) do_bsys_getprop(NULL, "input-device", inputdev);
6905084Sjohnlev 		else
6915084Sjohnlev 			v_len = 0;
6925084Sjohnlev 		inputdev[v_len] = 0;
6935084Sjohnlev 
6945084Sjohnlev 		outputdev = inputdev + v_len + 1;
6955084Sjohnlev 		v_len = do_bsys_getproplen(NULL, "output-device");
6965084Sjohnlev 		if (v_len > 0)
6975084Sjohnlev 			(void) do_bsys_getprop(NULL, "output-device",
6985084Sjohnlev 			    outputdev);
6995084Sjohnlev 		else
7005084Sjohnlev 			v_len = 0;
7015084Sjohnlev 		outputdev[v_len] = 0;
7023446Smrj 
7035084Sjohnlev 		consoledev = outputdev + v_len + 1;
7045084Sjohnlev 		v_len = do_bsys_getproplen(NULL, "console");
70510574SSherry.Moore@Sun.COM 		if (v_len > 0) {
7065084Sjohnlev 			(void) do_bsys_getprop(NULL, "console", consoledev);
70710574SSherry.Moore@Sun.COM 			if (post_fastreboot &&
70810574SSherry.Moore@Sun.COM 			    strcmp(consoledev, "graphics") == 0) {
70910574SSherry.Moore@Sun.COM 				bsetprops("console", "text");
71010574SSherry.Moore@Sun.COM 				v_len = strlen("text");
71110574SSherry.Moore@Sun.COM 				bcopy("text", consoledev, v_len);
71210574SSherry.Moore@Sun.COM 			}
71310574SSherry.Moore@Sun.COM 		} else {
7145084Sjohnlev 			v_len = 0;
71510574SSherry.Moore@Sun.COM 		}
7165084Sjohnlev 		consoledev[v_len] = 0;
7175084Sjohnlev 		bcons_init2(inputdev, outputdev, consoledev);
7185084Sjohnlev 	} else {
7195084Sjohnlev 		/*
7205084Sjohnlev 		 * Ensure console property exists
7215084Sjohnlev 		 * If not create it as "hypervisor"
7225084Sjohnlev 		 */
7235084Sjohnlev 		v_len = do_bsys_getproplen(NULL, "console");
7245084Sjohnlev 		if (v_len < 0)
7255084Sjohnlev 			bsetprops("console", "hypervisor");
7265084Sjohnlev 		inputdev = outputdev = consoledev = "hypervisor";
7275084Sjohnlev 		bcons_init2(inputdev, outputdev, consoledev);
7285084Sjohnlev 	}
7293446Smrj 
7303446Smrj 	if (strstr((char *)xbootp->bi_cmdline, "prom_debug") || kbm_debug) {
7313446Smrj 		value = line;
7323446Smrj 		bop_printf(NULL, "\nBoot properties:\n");
7333446Smrj 		name = "";
7343446Smrj 		while ((name = do_bsys_nextprop(NULL, name)) != NULL) {
7353446Smrj 			bop_printf(NULL, "\t0x%p %s = ", (void *)name, name);
7363446Smrj 			(void) do_bsys_getprop(NULL, name, value);
7373446Smrj 			v_len = do_bsys_getproplen(NULL, name);
7383446Smrj 			bop_printf(NULL, "len=%d ", v_len);
7393446Smrj 			value[v_len] = 0;
7403446Smrj 			bop_printf(NULL, "%s\n", value);
7413446Smrj 		}
7423446Smrj 	}
7433446Smrj }
7443446Smrj 
7453446Smrj /*
7463446Smrj  * print formatted output
7473446Smrj  */
7483446Smrj /*PRINTFLIKE2*/
7493446Smrj /*ARGSUSED*/
7503446Smrj void
bop_printf(bootops_t * bop,const char * fmt,...)7515648Ssetje bop_printf(bootops_t *bop, const char *fmt, ...)
7523446Smrj {
7533446Smrj 	va_list	ap;
7543446Smrj 
7553446Smrj 	if (have_console == 0)
7563446Smrj 		return;
7573446Smrj 
7583446Smrj 	va_start(ap, fmt);
7593446Smrj 	(void) vsnprintf(buffer, BUFFERSIZE, fmt, ap);
7603446Smrj 	va_end(ap);
7613446Smrj 	PUT_STRING(buffer);
7623446Smrj }
7633446Smrj 
7643446Smrj /*
7653446Smrj  * Another panic() variant; this one can be used even earlier during boot than
7663446Smrj  * prom_panic().
7673446Smrj  */
7683446Smrj /*PRINTFLIKE1*/
7693446Smrj void
bop_panic(const char * fmt,...)7705648Ssetje bop_panic(const char *fmt, ...)
7713446Smrj {
7723446Smrj 	va_list ap;
7733446Smrj 
7743446Smrj 	va_start(ap, fmt);
7753446Smrj 	bop_printf(NULL, fmt, ap);
7763446Smrj 	va_end(ap);
7773446Smrj 
7783446Smrj 	bop_printf(NULL, "\nPress any key to reboot.\n");
7793446Smrj 	(void) bcons_getchar();
7803446Smrj 	bop_printf(NULL, "Resetting...\n");
7814159Sjosephb 	pc_reset();
7823446Smrj }
7833446Smrj 
7843446Smrj /*
7853446Smrj  * Do a real mode interrupt BIOS call
7863446Smrj  */
7873446Smrj typedef struct bios_regs {
7883446Smrj 	unsigned short ax, bx, cx, dx, si, di, bp, es, ds;
7893446Smrj } bios_regs_t;
7903446Smrj typedef int (*bios_func_t)(int, bios_regs_t *);
7913446Smrj 
7923446Smrj /*ARGSUSED*/
7933446Smrj static void
do_bsys_doint(bootops_t * bop,int intnum,struct bop_regs * rp)7943446Smrj do_bsys_doint(bootops_t *bop, int intnum, struct bop_regs *rp)
7953446Smrj {
7965084Sjohnlev #if defined(__xpv)
7975084Sjohnlev 	prom_panic("unsupported call to BOP_DOINT()\n");
7985084Sjohnlev #else	/* __xpv */
7993446Smrj 	static int firsttime = 1;
8003446Smrj 	bios_func_t bios_func = (bios_func_t)(void *)(uintptr_t)0x5000;
8013446Smrj 	bios_regs_t br;
8023446Smrj 
8033446Smrj 	/*
8043446Smrj 	 * The first time we do this, we have to copy the pre-packaged
8053446Smrj 	 * low memory bios call code image into place.
8063446Smrj 	 */
8073446Smrj 	if (firsttime) {
8083446Smrj 		extern char bios_image[];
8093446Smrj 		extern uint32_t bios_size;
8103446Smrj 
8113446Smrj 		bcopy(bios_image, (void *)bios_func, bios_size);
8123446Smrj 		firsttime = 0;
8133446Smrj 	}
8143446Smrj 
8153446Smrj 	br.ax = rp->eax.word.ax;
8163446Smrj 	br.bx = rp->ebx.word.bx;
8173446Smrj 	br.cx = rp->ecx.word.cx;
8183446Smrj 	br.dx = rp->edx.word.dx;
8193446Smrj 	br.bp = rp->ebp.word.bp;
8203446Smrj 	br.si = rp->esi.word.si;
8213446Smrj 	br.di = rp->edi.word.di;
8223446Smrj 	br.ds = rp->ds;
8233446Smrj 	br.es = rp->es;
8243446Smrj 
8253446Smrj 	DBG_MSG("Doing BIOS call...");
8267656SSherry.Moore@Sun.COM 	DBG(br.ax);
8277656SSherry.Moore@Sun.COM 	DBG(br.bx);
8287656SSherry.Moore@Sun.COM 	DBG(br.dx);
8293446Smrj 	rp->eflags = bios_func(intnum, &br);
8303446Smrj 	DBG_MSG("done\n");
8313446Smrj 
8323446Smrj 	rp->eax.word.ax = br.ax;
8333446Smrj 	rp->ebx.word.bx = br.bx;
8343446Smrj 	rp->ecx.word.cx = br.cx;
8353446Smrj 	rp->edx.word.dx = br.dx;
8363446Smrj 	rp->ebp.word.bp = br.bp;
8373446Smrj 	rp->esi.word.si = br.si;
8383446Smrj 	rp->edi.word.di = br.di;
8393446Smrj 	rp->ds = br.ds;
8403446Smrj 	rp->es = br.es;
8415084Sjohnlev #endif /* __xpv */
8423446Smrj }
8433446Smrj 
8443446Smrj static struct boot_syscalls bop_sysp = {
8453446Smrj 	bcons_getchar,
8463446Smrj 	bcons_putchar,
8473446Smrj 	bcons_ischar,
8483446Smrj };
8493446Smrj 
8503446Smrj static char *whoami;
8513446Smrj 
8523446Smrj #define	BUFLEN	64
8533446Smrj 
8545084Sjohnlev #if defined(__xpv)
8555084Sjohnlev 
8565084Sjohnlev static char namebuf[32];
8575084Sjohnlev 
8585084Sjohnlev static void
xen_parse_props(char * s,char * prop_map[],int n_prop)8595084Sjohnlev xen_parse_props(char *s, char *prop_map[], int n_prop)
8605084Sjohnlev {
8615084Sjohnlev 	char **prop_name = prop_map;
8625084Sjohnlev 	char *cp = s, *scp;
8635084Sjohnlev 
8645084Sjohnlev 	do {
8655084Sjohnlev 		scp = cp;
8665084Sjohnlev 		while ((*cp != NULL) && (*cp != ':'))
8675084Sjohnlev 			cp++;
8685084Sjohnlev 
8695084Sjohnlev 		if ((scp != cp) && (*prop_name != NULL)) {
8705084Sjohnlev 			*cp = NULL;
8715084Sjohnlev 			bsetprops(*prop_name, scp);
8725084Sjohnlev 		}
8735084Sjohnlev 
8745084Sjohnlev 		cp++;
8755084Sjohnlev 		prop_name++;
8765084Sjohnlev 		n_prop--;
8775084Sjohnlev 	} while (n_prop > 0);
8785084Sjohnlev }
8795084Sjohnlev 
8805084Sjohnlev #define	VBDPATHLEN	64
8815084Sjohnlev 
8825084Sjohnlev /*
8835084Sjohnlev  * parse the 'xpv-root' property to create properties used by
8845084Sjohnlev  * ufs_mountroot.
8855084Sjohnlev  */
8865084Sjohnlev static void
xen_vbdroot_props(char * s)8875084Sjohnlev xen_vbdroot_props(char *s)
8885084Sjohnlev {
8895084Sjohnlev 	char vbdpath[VBDPATHLEN] = "/xpvd/xdf@";
8905084Sjohnlev 	const char lnamefix[] = "/dev/dsk/c0d";
8915084Sjohnlev 	char *pnp;
8925084Sjohnlev 	char *prop_p;
8935084Sjohnlev 	char mi;
8945084Sjohnlev 	short minor;
8955084Sjohnlev 	long addr = 0;
8965084Sjohnlev 
8975084Sjohnlev 	pnp = vbdpath + strlen(vbdpath);
8985084Sjohnlev 	prop_p = s + strlen(lnamefix);
8995084Sjohnlev 	while ((*prop_p != '\0') && (*prop_p != 's') && (*prop_p != 'p'))
9005084Sjohnlev 		addr = addr * 10 + *prop_p++ - '0';
9015084Sjohnlev 	(void) snprintf(pnp, VBDPATHLEN, "%lx", addr);
9025084Sjohnlev 	pnp = vbdpath + strlen(vbdpath);
9035084Sjohnlev 	if (*prop_p == 's')
9045084Sjohnlev 		mi = 'a';
9055084Sjohnlev 	else if (*prop_p == 'p')
9065084Sjohnlev 		mi = 'q';
9075084Sjohnlev 	else
9085084Sjohnlev 		ASSERT(0); /* shouldn't be here */
9095084Sjohnlev 	prop_p++;
9105084Sjohnlev 	ASSERT(*prop_p != '\0');
9115084Sjohnlev 	if (ISDIGIT(*prop_p)) {
9125084Sjohnlev 		minor = *prop_p - '0';
9135084Sjohnlev 		prop_p++;
9145084Sjohnlev 		if (ISDIGIT(*prop_p)) {
9155084Sjohnlev 			minor = minor * 10 + *prop_p - '0';
9165084Sjohnlev 		}
9175084Sjohnlev 	} else {
9185084Sjohnlev 		/* malformed root path, use 0 as default */
9195084Sjohnlev 		minor = 0;
9205084Sjohnlev 	}
9215084Sjohnlev 	ASSERT(minor < 16); /* at most 16 partitions */
9225084Sjohnlev 	mi += minor;
9235084Sjohnlev 	*pnp++ = ':';
9245084Sjohnlev 	*pnp++ = mi;
9255084Sjohnlev 	*pnp++ = '\0';
9265084Sjohnlev 	bsetprops("fstype", "ufs");
9275084Sjohnlev 	bsetprops("bootpath", vbdpath);
9285084Sjohnlev 
9295084Sjohnlev 	DBG_MSG("VBD bootpath set to ");
9305084Sjohnlev 	DBG_MSG(vbdpath);
9315084Sjohnlev 	DBG_MSG("\n");
9325084Sjohnlev }
9335084Sjohnlev 
9345084Sjohnlev /*
9355084Sjohnlev  * parse the xpv-nfsroot property to create properties used by
9365084Sjohnlev  * nfs_mountroot.
9375084Sjohnlev  */
9385084Sjohnlev static void
xen_nfsroot_props(char * s)9395084Sjohnlev xen_nfsroot_props(char *s)
9405084Sjohnlev {
9415084Sjohnlev 	char *prop_map[] = {
9425084Sjohnlev 		BP_SERVER_IP,	/* server IP address */
9435084Sjohnlev 		BP_SERVER_NAME,	/* server hostname */
9445084Sjohnlev 		BP_SERVER_PATH,	/* root path */
9455084Sjohnlev 	};
9465084Sjohnlev 	int n_prop = sizeof (prop_map) / sizeof (prop_map[0]);
9475084Sjohnlev 
9487439SPavel.Filipensky@Sun.COM 	bsetprop("fstype", 6, "nfs", 4);
9495084Sjohnlev 
9505084Sjohnlev 	xen_parse_props(s, prop_map, n_prop);
9515084Sjohnlev 
9525084Sjohnlev 	/*
9535084Sjohnlev 	 * If a server name wasn't specified, use a default.
9545084Sjohnlev 	 */
9555084Sjohnlev 	if (do_bsys_getproplen(NULL, BP_SERVER_NAME) == -1)
9565084Sjohnlev 		bsetprops(BP_SERVER_NAME, "unknown");
9575084Sjohnlev }
9585084Sjohnlev 
9595084Sjohnlev /*
9605084Sjohnlev  * Extract our IP address, etc. from the "xpv-ip" property.
9615084Sjohnlev  */
9625084Sjohnlev static void
xen_ip_props(char * s)9635084Sjohnlev xen_ip_props(char *s)
9645084Sjohnlev {
9655084Sjohnlev 	char *prop_map[] = {
9665084Sjohnlev 		BP_HOST_IP,		/* IP address */
9675084Sjohnlev 		NULL,			/* NFS server IP address (ignored in */
9685084Sjohnlev 					/* favour of xpv-nfsroot) */
9695084Sjohnlev 		BP_ROUTER_IP,		/* IP gateway */
9705084Sjohnlev 		BP_SUBNET_MASK,		/* IP subnet mask */
9715084Sjohnlev 		"xpv-hostname",		/* hostname (ignored) */
9725084Sjohnlev 		BP_NETWORK_INTERFACE,	/* interface name */
9735084Sjohnlev 		"xpv-hcp",		/* host configuration protocol */
9745084Sjohnlev 	};
9755084Sjohnlev 	int n_prop = sizeof (prop_map) / sizeof (prop_map[0]);
9765084Sjohnlev 	char ifname[IFNAMSIZ];
9775084Sjohnlev 
9785084Sjohnlev 	xen_parse_props(s, prop_map, n_prop);
9795084Sjohnlev 
9805084Sjohnlev 	/*
9815084Sjohnlev 	 * A Linux dom0 administrator expects all interfaces to be
9825084Sjohnlev 	 * called "ethX", which is not the case here.
9835084Sjohnlev 	 *
9845084Sjohnlev 	 * If the interface name specified is "eth0", presume that
9855084Sjohnlev 	 * this is really intended to be "xnf0" (the first domU ->
9865084Sjohnlev 	 * dom0 interface for this domain).
9875084Sjohnlev 	 */
9885084Sjohnlev 	if ((do_bsys_getprop(NULL, BP_NETWORK_INTERFACE, ifname) == 0) &&
9895084Sjohnlev 	    (strcmp("eth0", ifname) == 0)) {
9905084Sjohnlev 		bsetprops(BP_NETWORK_INTERFACE, "xnf0");
9915084Sjohnlev 		bop_printf(NULL,
9925084Sjohnlev 		    "network interface name 'eth0' replaced with 'xnf0'\n");
9935084Sjohnlev 	}
9945084Sjohnlev }
9955084Sjohnlev 
9965084Sjohnlev #else	/* __xpv */
9975084Sjohnlev 
9983446Smrj static void
setup_rarp_props(struct sol_netinfo * sip)9993446Smrj setup_rarp_props(struct sol_netinfo *sip)
10003446Smrj {
10013446Smrj 	char buf[BUFLEN];	/* to hold ip/mac addrs */
10023446Smrj 	uint8_t *val;
10033446Smrj 
10043446Smrj 	val = (uint8_t *)&sip->sn_ciaddr;
10053446Smrj 	(void) snprintf(buf, BUFLEN, "%d.%d.%d.%d",
10063446Smrj 	    val[0], val[1], val[2], val[3]);
10073446Smrj 	bsetprops(BP_HOST_IP, buf);
10083446Smrj 
10093446Smrj 	val = (uint8_t *)&sip->sn_siaddr;
10103446Smrj 	(void) snprintf(buf, BUFLEN, "%d.%d.%d.%d",
10113446Smrj 	    val[0], val[1], val[2], val[3]);
10123446Smrj 	bsetprops(BP_SERVER_IP, buf);
10133446Smrj 
10143446Smrj 	if (sip->sn_giaddr != 0) {
10153446Smrj 		val = (uint8_t *)&sip->sn_giaddr;
10163446Smrj 		(void) snprintf(buf, BUFLEN, "%d.%d.%d.%d",
10173446Smrj 		    val[0], val[1], val[2], val[3]);
10183446Smrj 		bsetprops(BP_ROUTER_IP, buf);
10193446Smrj 	}
10203446Smrj 
10213446Smrj 	if (sip->sn_netmask != 0) {
10223446Smrj 		val = (uint8_t *)&sip->sn_netmask;
10233446Smrj 		(void) snprintf(buf, BUFLEN, "%d.%d.%d.%d",
10243446Smrj 		    val[0], val[1], val[2], val[3]);
10253446Smrj 		bsetprops(BP_SUBNET_MASK, buf);
10263446Smrj 	}
10273446Smrj 
10283446Smrj 	if (sip->sn_mactype != 4 || sip->sn_maclen != 6) {
10293446Smrj 		bop_printf(NULL, "unsupported mac type %d, mac len %d\n",
10303446Smrj 		    sip->sn_mactype, sip->sn_maclen);
10313446Smrj 	} else {
10323446Smrj 		val = sip->sn_macaddr;
10333446Smrj 		(void) snprintf(buf, BUFLEN, "%x:%x:%x:%x:%x:%x",
10343446Smrj 		    val[0], val[1], val[2], val[3], val[4], val[5]);
10353446Smrj 		bsetprops(BP_BOOT_MAC, buf);
10363446Smrj 	}
10373446Smrj }
10383446Smrj 
10395084Sjohnlev #endif	/* __xpv */
10405084Sjohnlev 
10419160SSherry.Moore@Sun.COM static void
build_panic_cmdline(const char * cmd,int cmdlen)10429160SSherry.Moore@Sun.COM build_panic_cmdline(const char *cmd, int cmdlen)
10439160SSherry.Moore@Sun.COM {
10449160SSherry.Moore@Sun.COM 	int proplen;
10459160SSherry.Moore@Sun.COM 	size_t arglen;
10469160SSherry.Moore@Sun.COM 
10479160SSherry.Moore@Sun.COM 	arglen = sizeof (fastreboot_onpanic_args);
10489160SSherry.Moore@Sun.COM 	/*
10499160SSherry.Moore@Sun.COM 	 * If we allready have fastreboot-onpanic set to zero,
10509160SSherry.Moore@Sun.COM 	 * don't add them again.
10519160SSherry.Moore@Sun.COM 	 */
10529160SSherry.Moore@Sun.COM 	if ((proplen = do_bsys_getproplen(NULL, FASTREBOOT_ONPANIC)) > 0 &&
10539160SSherry.Moore@Sun.COM 	    proplen <=  sizeof (fastreboot_onpanic_cmdline)) {
10549160SSherry.Moore@Sun.COM 		(void) do_bsys_getprop(NULL, FASTREBOOT_ONPANIC,
10559160SSherry.Moore@Sun.COM 		    fastreboot_onpanic_cmdline);
10569160SSherry.Moore@Sun.COM 		if (FASTREBOOT_ONPANIC_NOTSET(fastreboot_onpanic_cmdline))
10579160SSherry.Moore@Sun.COM 			arglen = 1;
10589160SSherry.Moore@Sun.COM 	}
10599160SSherry.Moore@Sun.COM 
10609160SSherry.Moore@Sun.COM 	/*
10619160SSherry.Moore@Sun.COM 	 * construct fastreboot_onpanic_cmdline
10629160SSherry.Moore@Sun.COM 	 */
10639160SSherry.Moore@Sun.COM 	if (cmdlen + arglen > sizeof (fastreboot_onpanic_cmdline)) {
10649160SSherry.Moore@Sun.COM 		DBG_MSG("Command line too long: clearing "
10659160SSherry.Moore@Sun.COM 		    FASTREBOOT_ONPANIC "\n");
10669160SSherry.Moore@Sun.COM 		fastreboot_onpanic = 0;
10679160SSherry.Moore@Sun.COM 	} else {
10689160SSherry.Moore@Sun.COM 		bcopy(cmd, fastreboot_onpanic_cmdline, cmdlen);
10699160SSherry.Moore@Sun.COM 		if (arglen != 1)
10709160SSherry.Moore@Sun.COM 			bcopy(fastreboot_onpanic_args,
10719160SSherry.Moore@Sun.COM 			    fastreboot_onpanic_cmdline + cmdlen, arglen);
10729160SSherry.Moore@Sun.COM 		else
10739160SSherry.Moore@Sun.COM 			fastreboot_onpanic_cmdline[cmdlen] = 0;
10749160SSherry.Moore@Sun.COM 	}
10759160SSherry.Moore@Sun.COM }
10769160SSherry.Moore@Sun.COM 
10779160SSherry.Moore@Sun.COM 
10789160SSherry.Moore@Sun.COM #ifndef	__xpv
10799160SSherry.Moore@Sun.COM /*
10809160SSherry.Moore@Sun.COM  * Construct boot command line for Fast Reboot
10819160SSherry.Moore@Sun.COM  */
10829160SSherry.Moore@Sun.COM static void
build_fastboot_cmdline(void)10839160SSherry.Moore@Sun.COM build_fastboot_cmdline(void)
10849160SSherry.Moore@Sun.COM {
10859160SSherry.Moore@Sun.COM 	saved_cmdline_len =  strlen(xbootp->bi_cmdline) + 1;
10869160SSherry.Moore@Sun.COM 	if (saved_cmdline_len > FASTBOOT_SAVED_CMDLINE_LEN) {
10879160SSherry.Moore@Sun.COM 		DBG(saved_cmdline_len);
10889160SSherry.Moore@Sun.COM 		DBG_MSG("Command line too long: clearing fastreboot_capable\n");
10899160SSherry.Moore@Sun.COM 		fastreboot_capable = 0;
10909160SSherry.Moore@Sun.COM 	} else {
10919160SSherry.Moore@Sun.COM 		bcopy((void *)(xbootp->bi_cmdline), (void *)saved_cmdline,
10929160SSherry.Moore@Sun.COM 		    saved_cmdline_len);
10939160SSherry.Moore@Sun.COM 		saved_cmdline[saved_cmdline_len - 1] = '\0';
10949160SSherry.Moore@Sun.COM 		build_panic_cmdline(saved_cmdline, saved_cmdline_len - 1);
10959160SSherry.Moore@Sun.COM 	}
10969160SSherry.Moore@Sun.COM }
10979160SSherry.Moore@Sun.COM 
10989160SSherry.Moore@Sun.COM /*
10999160SSherry.Moore@Sun.COM  * Save memory layout, disk drive information, unix and boot archive sizes for
11009160SSherry.Moore@Sun.COM  * Fast Reboot.
11019160SSherry.Moore@Sun.COM  */
11029160SSherry.Moore@Sun.COM static void
save_boot_info(multiboot_info_t * mbi,struct xboot_info * xbi)110310304SSeth.Goldberg@Sun.COM save_boot_info(multiboot_info_t *mbi, struct xboot_info *xbi)
11049160SSherry.Moore@Sun.COM {
110510304SSeth.Goldberg@Sun.COM 	struct boot_modules *modp;
11069160SSherry.Moore@Sun.COM 	int i;
11079160SSherry.Moore@Sun.COM 
11089160SSherry.Moore@Sun.COM 	bcopy(mbi, &saved_mbi, sizeof (multiboot_info_t));
11099160SSherry.Moore@Sun.COM 	if (mbi->mmap_length > sizeof (saved_mmap)) {
11109160SSherry.Moore@Sun.COM 		DBG_MSG("mbi->mmap_length too big: clearing "
11119160SSherry.Moore@Sun.COM 		    "fastreboot_capable\n");
11129160SSherry.Moore@Sun.COM 		fastreboot_capable = 0;
11139160SSherry.Moore@Sun.COM 	} else {
11149160SSherry.Moore@Sun.COM 		bcopy((void *)(uintptr_t)mbi->mmap_addr, (void *)saved_mmap,
11159160SSherry.Moore@Sun.COM 		    mbi->mmap_length);
11169160SSherry.Moore@Sun.COM 	}
11179160SSherry.Moore@Sun.COM 
111810525SKonstantin.Ananyev@Sun.COM 	if ((mbi->flags & MB_INFO_DRIVE_INFO) != 0) {
111910525SKonstantin.Ananyev@Sun.COM 		if (mbi->drives_length > sizeof (saved_drives)) {
112010525SKonstantin.Ananyev@Sun.COM 			DBG(mbi->drives_length);
112110525SKonstantin.Ananyev@Sun.COM 			DBG_MSG("mbi->drives_length too big: clearing "
112210525SKonstantin.Ananyev@Sun.COM 			    "fastreboot_capable\n");
112310525SKonstantin.Ananyev@Sun.COM 			fastreboot_capable = 0;
112410525SKonstantin.Ananyev@Sun.COM 		} else {
112510525SKonstantin.Ananyev@Sun.COM 			bcopy((void *)(uintptr_t)mbi->drives_addr,
112610525SKonstantin.Ananyev@Sun.COM 			    (void *)saved_drives, mbi->drives_length);
112710525SKonstantin.Ananyev@Sun.COM 		}
11289160SSherry.Moore@Sun.COM 	} else {
112910525SKonstantin.Ananyev@Sun.COM 		saved_mbi.drives_length = 0;
113010525SKonstantin.Ananyev@Sun.COM 		saved_mbi.drives_addr = NULL;
11319160SSherry.Moore@Sun.COM 	}
11329160SSherry.Moore@Sun.COM 
11339160SSherry.Moore@Sun.COM 	/*
11349160SSherry.Moore@Sun.COM 	 * Current file sizes.  Used by fastboot.c to figure out how much
11359160SSherry.Moore@Sun.COM 	 * memory to reserve for panic reboot.
113610304SSeth.Goldberg@Sun.COM 	 * Use the module list from the dboot-constructed xboot_info
113710304SSeth.Goldberg@Sun.COM 	 * instead of the list referenced by the multiboot structure
113810304SSeth.Goldberg@Sun.COM 	 * because that structure may not be addressable now.
11399160SSherry.Moore@Sun.COM 	 */
11409160SSherry.Moore@Sun.COM 	saved_file_size[FASTBOOT_NAME_UNIX] = FOUR_MEG - PAGESIZE;
114110304SSeth.Goldberg@Sun.COM 	for (i = 0, modp = (struct boot_modules *)(uintptr_t)xbi->bi_modules;
114210304SSeth.Goldberg@Sun.COM 	    i < xbi->bi_module_cnt; i++, modp++) {
114310304SSeth.Goldberg@Sun.COM 		saved_file_size[FASTBOOT_NAME_BOOTARCHIVE] += modp->bm_size;
11449160SSherry.Moore@Sun.COM 	}
11459160SSherry.Moore@Sun.COM }
11469160SSherry.Moore@Sun.COM #endif	/* __xpv */
11479160SSherry.Moore@Sun.COM 
11489160SSherry.Moore@Sun.COM 
11493446Smrj /*
11503446Smrj  * 1st pass at building the table of boot properties. This includes:
11513446Smrj  * - values set on the command line: -B a=x,b=y,c=z ....
11523446Smrj  * - known values we just compute (ie. from xbootp)
11533446Smrj  * - values from /boot/solaris/bootenv.rc (ie. eeprom(1m) values)
11543446Smrj  *
11553446Smrj  * the grub command line looked like:
11563446Smrj  * kernel boot-file [-B prop=value[,prop=value]...] [boot-args]
11573446Smrj  *
11583446Smrj  * whoami is the same as boot-file
11593446Smrj  */
11603446Smrj static void
build_boot_properties(void)11613446Smrj build_boot_properties(void)
11623446Smrj {
11633446Smrj 	char *name;
11643446Smrj 	int name_len;
11653446Smrj 	char *value;
11663446Smrj 	int value_len;
11673446Smrj 	struct boot_modules *bm;
11683446Smrj 	char *propbuf;
11693446Smrj 	int quoted = 0;
11703446Smrj 	int boot_arg_len;
11715084Sjohnlev #ifndef __xpv
11725084Sjohnlev 	static int stdout_val = 0;
11733446Smrj 	uchar_t boot_device;
11743446Smrj 	char str[3];
11753446Smrj 	multiboot_info_t *mbi;
11763446Smrj 	int netboot;
11773446Smrj 	struct sol_netinfo *sip;
11785084Sjohnlev #endif
11793446Smrj 
11803446Smrj 	/*
11813446Smrj 	 * These have to be done first, so that kobj_mount_root() works
11823446Smrj 	 */
11833446Smrj 	DBG_MSG("Building boot properties\n");
11843446Smrj 	propbuf = do_bsys_alloc(NULL, NULL, MMU_PAGESIZE, 0);
11853446Smrj 	DBG((uintptr_t)propbuf);
11863446Smrj 	if (xbootp->bi_module_cnt > 0) {
11873446Smrj 		bm = xbootp->bi_modules;
11883446Smrj 		bsetprop64("ramdisk_start", (uint64_t)(uintptr_t)bm->bm_addr);
11893446Smrj 		bsetprop64("ramdisk_end", (uint64_t)(uintptr_t)bm->bm_addr +
11903446Smrj 		    bm->bm_size);
11913446Smrj 	}
11923446Smrj 
11933446Smrj 	DBG_MSG("Parsing command line for boot properties\n");
11943446Smrj 	value = xbootp->bi_cmdline;
11953446Smrj 
11963446Smrj 	/*
11973446Smrj 	 * allocate memory to collect boot_args into
11983446Smrj 	 */
11993446Smrj 	boot_arg_len = strlen(xbootp->bi_cmdline) + 1;
12003446Smrj 	boot_args = do_bsys_alloc(NULL, NULL, boot_arg_len, MMU_PAGESIZE);
12013446Smrj 	boot_args[0] = 0;
12023446Smrj 	boot_arg_len = 0;
12033446Smrj 
12045084Sjohnlev #ifdef __xpv
12055084Sjohnlev 	/*
12065084Sjohnlev 	 * Xen puts a lot of device information in front of the kernel name
12075084Sjohnlev 	 * let's grab them and make them boot properties.  The first
12085084Sjohnlev 	 * string w/o an "=" in it will be the boot-file property.
12095084Sjohnlev 	 */
12105084Sjohnlev 	(void) strcpy(namebuf, "xpv-");
12115084Sjohnlev 	for (;;) {
12125084Sjohnlev 		/*
12135084Sjohnlev 		 * get to next property
12145084Sjohnlev 		 */
12155084Sjohnlev 		while (ISSPACE(*value))
12165084Sjohnlev 			++value;
12175084Sjohnlev 		name = value;
12185084Sjohnlev 		/*
12195084Sjohnlev 		 * look for an "="
12205084Sjohnlev 		 */
12215084Sjohnlev 		while (*value && !ISSPACE(*value) && *value != '=') {
12225084Sjohnlev 			value++;
12235084Sjohnlev 		}
12245084Sjohnlev 		if (*value != '=') { /* no "=" in the property */
12255084Sjohnlev 			value = name;
12265084Sjohnlev 			break;
12275084Sjohnlev 		}
12285084Sjohnlev 		name_len = value - name;
12295084Sjohnlev 		value_len = 0;
12305084Sjohnlev 		/*
12315084Sjohnlev 		 * skip over the "="
12325084Sjohnlev 		 */
12335084Sjohnlev 		value++;
12345084Sjohnlev 		while (value[value_len] && !ISSPACE(value[value_len])) {
12355084Sjohnlev 			++value_len;
12365084Sjohnlev 		}
12375084Sjohnlev 		/*
12385084Sjohnlev 		 * build property name with "xpv-" prefix
12395084Sjohnlev 		 */
12405084Sjohnlev 		if (name_len + 4 > 32) { /* skip if name too long */
12415084Sjohnlev 			value += value_len;
12425084Sjohnlev 			continue;
12435084Sjohnlev 		}
12445084Sjohnlev 		bcopy(name, &namebuf[4], name_len);
12455084Sjohnlev 		name_len += 4;
12465084Sjohnlev 		namebuf[name_len] = 0;
12475084Sjohnlev 		bcopy(value, propbuf, value_len);
12485084Sjohnlev 		propbuf[value_len] = 0;
12495084Sjohnlev 		bsetprops(namebuf, propbuf);
12505084Sjohnlev 
12515084Sjohnlev 		/*
12525084Sjohnlev 		 * xpv-root is set to the logical disk name of the xen
12535084Sjohnlev 		 * VBD when booting from a disk-based filesystem.
12545084Sjohnlev 		 */
12555084Sjohnlev 		if (strcmp(namebuf, "xpv-root") == 0)
12565084Sjohnlev 			xen_vbdroot_props(propbuf);
12575084Sjohnlev 		/*
12585084Sjohnlev 		 * While we're here, if we have a "xpv-nfsroot" property
12597439SPavel.Filipensky@Sun.COM 		 * then we need to set "fstype" to "nfs" so we mount
12605084Sjohnlev 		 * our root from the nfs server.  Also parse the xpv-nfsroot
12615084Sjohnlev 		 * property to create the properties that nfs_mountroot will
12625084Sjohnlev 		 * need to find the root and mount it.
12635084Sjohnlev 		 */
12645084Sjohnlev 		if (strcmp(namebuf, "xpv-nfsroot") == 0)
12655084Sjohnlev 			xen_nfsroot_props(propbuf);
12665084Sjohnlev 
12675084Sjohnlev 		if (strcmp(namebuf, "xpv-ip") == 0)
12685084Sjohnlev 			xen_ip_props(propbuf);
12695084Sjohnlev 		value += value_len;
12705084Sjohnlev 	}
12715084Sjohnlev #endif
12725084Sjohnlev 
12733446Smrj 	while (ISSPACE(*value))
12743446Smrj 		++value;
12753446Smrj 	/*
12763446Smrj 	 * value now points at the boot-file
12773446Smrj 	 */
12783446Smrj 	value_len = 0;
12793446Smrj 	while (value[value_len] && !ISSPACE(value[value_len]))
12803446Smrj 		++value_len;
12813446Smrj 	if (value_len > 0) {
12823446Smrj 		whoami = propbuf;
12833446Smrj 		bcopy(value, whoami, value_len);
12843446Smrj 		whoami[value_len] = 0;
12853446Smrj 		bsetprops("boot-file", whoami);
12863446Smrj 		/*
12873446Smrj 		 * strip leading path stuff from whoami, so running from
12883446Smrj 		 * PXE/miniroot makes sense.
12893446Smrj 		 */
12903446Smrj 		if (strstr(whoami, "/platform/") != NULL)
12913446Smrj 			whoami = strstr(whoami, "/platform/");
12923446Smrj 		bsetprops("whoami", whoami);
12933446Smrj 	}
12943446Smrj 
12953446Smrj 	/*
12964004Sjosephb 	 * Values forcibly set boot properties on the command line via -B.
12973446Smrj 	 * Allow use of quotes in values. Other stuff goes on kernel
12983446Smrj 	 * command line.
12993446Smrj 	 */
13003446Smrj 	name = value + value_len;
13013446Smrj 	while (*name != 0) {
13023446Smrj 		/*
13033446Smrj 		 * anything not " -B" is copied to the command line
13043446Smrj 		 */
13053446Smrj 		if (!ISSPACE(name[0]) || name[1] != '-' || name[2] != 'B') {
13063446Smrj 			boot_args[boot_arg_len++] = *name;
13073446Smrj 			boot_args[boot_arg_len] = 0;
13083446Smrj 			++name;
13093446Smrj 			continue;
13103446Smrj 		}
13113446Smrj 
13123446Smrj 		/*
13133446Smrj 		 * skip the " -B" and following white space
13143446Smrj 		 */
13153446Smrj 		name += 3;
13163446Smrj 		while (ISSPACE(*name))
13173446Smrj 			++name;
13183446Smrj 		while (*name && !ISSPACE(*name)) {
13193446Smrj 			value = strstr(name, "=");
13203446Smrj 			if (value == NULL)
13213446Smrj 				break;
13223446Smrj 			name_len = value - name;
13233446Smrj 			++value;
13243446Smrj 			value_len = 0;
13253446Smrj 			quoted = 0;
13263446Smrj 			for (; ; ++value_len) {
13273446Smrj 				if (!value[value_len])
13283446Smrj 					break;
13293446Smrj 
13303446Smrj 				/*
13313446Smrj 				 * is this value quoted?
13323446Smrj 				 */
13333446Smrj 				if (value_len == 0 &&
13343446Smrj 				    (value[0] == '\'' || value[0] == '"')) {
13353446Smrj 					quoted = value[0];
13363446Smrj 					++value_len;
13373446Smrj 				}
13383446Smrj 
13393446Smrj 				/*
13403446Smrj 				 * In the quote accept any character,
13413446Smrj 				 * but look for ending quote.
13423446Smrj 				 */
13433446Smrj 				if (quoted) {
13443446Smrj 					if (value[value_len] == quoted)
13453446Smrj 						quoted = 0;
13463446Smrj 					continue;
13473446Smrj 				}
13483446Smrj 
13493446Smrj 				/*
13503446Smrj 				 * a comma or white space ends the value
13513446Smrj 				 */
13523446Smrj 				if (value[value_len] == ',' ||
13533446Smrj 				    ISSPACE(value[value_len]))
13543446Smrj 					break;
13553446Smrj 			}
13563446Smrj 
13573446Smrj 			if (value_len == 0) {
13583446Smrj 				bsetprop(name, name_len, "true", 5);
13593446Smrj 			} else {
13603446Smrj 				char *v = value;
13613446Smrj 				int l = value_len;
13623446Smrj 				if (v[0] == v[l - 1] &&
13633446Smrj 				    (v[0] == '\'' || v[0] == '"')) {
13643446Smrj 					++v;
13653446Smrj 					l -= 2;
13663446Smrj 				}
13673446Smrj 				bcopy(v, propbuf, l);
13683446Smrj 				propbuf[l] = '\0';
13693446Smrj 				bsetprop(name, name_len, propbuf,
13703446Smrj 				    l + 1);
13713446Smrj 			}
13723446Smrj 			name = value + value_len;
13733446Smrj 			while (*name == ',')
13743446Smrj 				++name;
13753446Smrj 		}
13763446Smrj 	}
13773446Smrj 
13783446Smrj 	/*
13793446Smrj 	 * set boot-args property
13805648Ssetje 	 * 1275 name is bootargs, so set
13815648Ssetje 	 * that too
13823446Smrj 	 */
13833446Smrj 	bsetprops("boot-args", boot_args);
13845648Ssetje 	bsetprops("bootargs", boot_args);
13853446Smrj 
13865084Sjohnlev #ifndef __xpv
13873446Smrj 	/*
13883446Smrj 	 * set the BIOS boot device from GRUB
13893446Smrj 	 */
13903446Smrj 	netboot = 0;
13913446Smrj 	mbi = xbootp->bi_mb_info;
13927656SSherry.Moore@Sun.COM 
13939160SSherry.Moore@Sun.COM 	/*
13949160SSherry.Moore@Sun.COM 	 * Build boot command line for Fast Reboot
13959160SSherry.Moore@Sun.COM 	 */
13969160SSherry.Moore@Sun.COM 	build_fastboot_cmdline();
13979160SSherry.Moore@Sun.COM 
13989160SSherry.Moore@Sun.COM 	/*
13999160SSherry.Moore@Sun.COM 	 * Save various boot information for Fast Reboot
14009160SSherry.Moore@Sun.COM 	 */
140110304SSeth.Goldberg@Sun.COM 	save_boot_info(mbi, xbootp);
14027656SSherry.Moore@Sun.COM 
140310525SKonstantin.Ananyev@Sun.COM 	if (mbi != NULL && mbi->flags & MB_INFO_BOOTDEV) {
14043446Smrj 		boot_device = mbi->boot_device >> 24;
14053446Smrj 		if (boot_device == 0x20)
14063446Smrj 			netboot++;
14073446Smrj 		str[0] = (boot_device >> 4) + '0';
14083446Smrj 		str[1] = (boot_device & 0xf) + '0';
14093446Smrj 		str[2] = 0;
14103446Smrj 		bsetprops("bios-boot-device", str);
14113446Smrj 	} else {
14123446Smrj 		netboot = 1;
14133446Smrj 	}
14143446Smrj 
14153446Smrj 	/*
14163446Smrj 	 * In the netboot case, drives_info is overloaded with the dhcp ack.
14173446Smrj 	 * This is not multiboot compliant and requires special pxegrub!
14183446Smrj 	 */
14193446Smrj 	if (netboot && mbi->drives_length != 0) {
14203446Smrj 		sip = (struct sol_netinfo *)(uintptr_t)mbi->drives_addr;
14213446Smrj 		if (sip->sn_infotype == SN_TYPE_BOOTP)
14223446Smrj 			bsetprop("bootp-response", sizeof ("bootp-response"),
14233446Smrj 			    (void *)(uintptr_t)mbi->drives_addr,
14243446Smrj 			    mbi->drives_length);
14255210Sdme 		else if (sip->sn_infotype == SN_TYPE_RARP)
14263446Smrj 			setup_rarp_props(sip);
14273446Smrj 	}
14283446Smrj 	bsetprop("stdout", strlen("stdout"),
14293446Smrj 	    &stdout_val, sizeof (stdout_val));
14305084Sjohnlev #endif /* __xpv */
14313446Smrj 
14323446Smrj 	/*
14333446Smrj 	 * more conjured up values for made up things....
14343446Smrj 	 */
14355084Sjohnlev #if defined(__xpv)
14365084Sjohnlev 	bsetprops("mfg-name", "i86xpv");
14375084Sjohnlev 	bsetprops("impl-arch-name", "i86xpv");
14385084Sjohnlev #else
14393446Smrj 	bsetprops("mfg-name", "i86pc");
14403446Smrj 	bsetprops("impl-arch-name", "i86pc");
14415084Sjohnlev #endif
14423446Smrj 
14433446Smrj 	/*
14443446Smrj 	 * Build firmware-provided system properties
14453446Smrj 	 */
14463446Smrj 	build_firmware_properties();
14473446Smrj 
14483446Smrj 	/*
14495084Sjohnlev 	 * XXPV
14505084Sjohnlev 	 *
14513446Smrj 	 * Find out what these are:
14523446Smrj 	 * - cpuid_feature_ecx_include
14533446Smrj 	 * - cpuid_feature_ecx_exclude
14543446Smrj 	 * - cpuid_feature_edx_include
14553446Smrj 	 * - cpuid_feature_edx_exclude
14563446Smrj 	 *
14573446Smrj 	 * Find out what these are in multiboot:
14583446Smrj 	 * - netdev-path
14593446Smrj 	 * - fstype
14603446Smrj 	 */
14613446Smrj }
14623446Smrj 
14635084Sjohnlev #ifdef __xpv
14645084Sjohnlev /*
14655084Sjohnlev  * Under the Hypervisor, memory usable for DMA may be scarce. One
14665084Sjohnlev  * very likely large pool of DMA friendly memory is occupied by
14675084Sjohnlev  * the boot_archive, as it was loaded by grub into low MFNs.
14685084Sjohnlev  *
14695084Sjohnlev  * Here we free up that memory by copying the boot archive to what are
14705084Sjohnlev  * likely higher MFN pages and then swapping the mfn/pfn mappings.
14715084Sjohnlev  */
14725084Sjohnlev #define	PFN_2GIG	0x80000
14735084Sjohnlev static void
relocate_boot_archive(void)14745084Sjohnlev relocate_boot_archive(void)
14755084Sjohnlev {
14765084Sjohnlev 	mfn_t max_mfn = HYPERVISOR_memory_op(XENMEM_maximum_ram_page, NULL);
14775084Sjohnlev 	struct boot_modules *bm = xbootp->bi_modules;
14785084Sjohnlev 	uintptr_t va;
14795084Sjohnlev 	pfn_t va_pfn;
14805084Sjohnlev 	mfn_t va_mfn;
14815084Sjohnlev 	caddr_t copy;
14825084Sjohnlev 	pfn_t copy_pfn;
14835084Sjohnlev 	mfn_t copy_mfn;
14845084Sjohnlev 	size_t	len;
14855084Sjohnlev 	int slop;
14865084Sjohnlev 	int total = 0;
14875084Sjohnlev 	int relocated = 0;
14885084Sjohnlev 	int mmu_update_return;
14895084Sjohnlev 	mmu_update_t t[2];
14905084Sjohnlev 	x86pte_t pte;
14915084Sjohnlev 
14925084Sjohnlev 	/*
14935084Sjohnlev 	 * If all MFN's are below 2Gig, don't bother doing this.
14945084Sjohnlev 	 */
14955084Sjohnlev 	if (max_mfn < PFN_2GIG)
14965084Sjohnlev 		return;
14975084Sjohnlev 	if (xbootp->bi_module_cnt < 1) {
14985084Sjohnlev 		DBG_MSG("no boot_archive!");
14995084Sjohnlev 		return;
15005084Sjohnlev 	}
15015084Sjohnlev 
15025084Sjohnlev 	DBG_MSG("moving boot_archive to high MFN memory\n");
15035084Sjohnlev 	va = (uintptr_t)bm->bm_addr;
15045084Sjohnlev 	len = bm->bm_size;
15055084Sjohnlev 	slop = va & MMU_PAGEOFFSET;
15065084Sjohnlev 	if (slop) {
15075084Sjohnlev 		va += MMU_PAGESIZE - slop;
15085084Sjohnlev 		len -= MMU_PAGESIZE - slop;
15095084Sjohnlev 	}
15105084Sjohnlev 	len = P2ALIGN(len, MMU_PAGESIZE);
15115084Sjohnlev 
15125084Sjohnlev 	/*
15135084Sjohnlev 	 * Go through all boot_archive pages, swapping any low MFN pages
15145084Sjohnlev 	 * with memory at next_phys.
15155084Sjohnlev 	 */
15165084Sjohnlev 	while (len != 0) {
15175084Sjohnlev 		++total;
15185084Sjohnlev 		va_pfn = mmu_btop(va - ONE_GIG);
15195084Sjohnlev 		va_mfn = mfn_list[va_pfn];
15205084Sjohnlev 		if (mfn_list[va_pfn] < PFN_2GIG) {
15215084Sjohnlev 			copy = kbm_remap_window(next_phys, 1);
15225084Sjohnlev 			bcopy((void *)va, copy, MMU_PAGESIZE);
15235084Sjohnlev 			copy_pfn = mmu_btop(next_phys);
15245084Sjohnlev 			copy_mfn = mfn_list[copy_pfn];
15255084Sjohnlev 
15265084Sjohnlev 			pte = mfn_to_ma(copy_mfn) | PT_NOCONSIST | PT_VALID;
15275084Sjohnlev 			if (HYPERVISOR_update_va_mapping(va, pte,
15285084Sjohnlev 			    UVMF_INVLPG | UVMF_LOCAL))
15295084Sjohnlev 				bop_panic("relocate_boot_archive():  "
15305084Sjohnlev 				    "HYPERVISOR_update_va_mapping() failed");
15315084Sjohnlev 
15325084Sjohnlev 			mfn_list[va_pfn] = copy_mfn;
15335084Sjohnlev 			mfn_list[copy_pfn] = va_mfn;
15345084Sjohnlev 
15355084Sjohnlev 			t[0].ptr = mfn_to_ma(copy_mfn) | MMU_MACHPHYS_UPDATE;
15365084Sjohnlev 			t[0].val = va_pfn;
15375084Sjohnlev 			t[1].ptr = mfn_to_ma(va_mfn) | MMU_MACHPHYS_UPDATE;
15385084Sjohnlev 			t[1].val = copy_pfn;
15395084Sjohnlev 			if (HYPERVISOR_mmu_update(t, 2, &mmu_update_return,
15405084Sjohnlev 			    DOMID_SELF) != 0 || mmu_update_return != 2)
15415084Sjohnlev 				bop_panic("relocate_boot_archive():  "
15425084Sjohnlev 				    "HYPERVISOR_mmu_update() failed");
15435084Sjohnlev 
15445084Sjohnlev 			next_phys += MMU_PAGESIZE;
15455084Sjohnlev 			++relocated;
15465084Sjohnlev 		}
15475084Sjohnlev 		len -= MMU_PAGESIZE;
15485084Sjohnlev 		va += MMU_PAGESIZE;
15495084Sjohnlev 	}
15505084Sjohnlev 	DBG_MSG("Relocated pages:\n");
15515084Sjohnlev 	DBG(relocated);
15525084Sjohnlev 	DBG_MSG("Out of total pages:\n");
15535084Sjohnlev 	DBG(total);
15545084Sjohnlev }
15555084Sjohnlev #endif /* __xpv */
15565084Sjohnlev 
15575084Sjohnlev #if !defined(__xpv)
15583446Smrj /*
15593446Smrj  * Install a temporary IDT that lets us catch errors in the boot time code.
15603446Smrj  * We shouldn't get any faults at all while this is installed, so we'll
15613446Smrj  * just generate a traceback and exit.
15623446Smrj  */
15633446Smrj #ifdef __amd64
15643446Smrj static const int bcode_sel = B64CODE_SEL;
15653446Smrj #else
15663446Smrj static const int bcode_sel = B32CODE_SEL;
15673446Smrj #endif
15683446Smrj 
15693446Smrj /*
15703446Smrj  * simple description of a stack frame (args are 32 bit only currently)
15713446Smrj  */
15723446Smrj typedef struct bop_frame {
15733446Smrj 	struct bop_frame *old_frame;
15743446Smrj 	pc_t retaddr;
15753446Smrj 	long arg[1];
15763446Smrj } bop_frame_t;
15773446Smrj 
15783446Smrj void
bop_traceback(bop_frame_t * frame)15793446Smrj bop_traceback(bop_frame_t *frame)
15803446Smrj {
15813446Smrj 	pc_t pc;
15823446Smrj 	int cnt;
15833446Smrj 	char *ksym;
15843446Smrj 	ulong_t off;
158510994SDan.Mick@Sun.COM #if defined(__i386)
158610994SDan.Mick@Sun.COM 	int a;
158710994SDan.Mick@Sun.COM #endif
15883446Smrj 
15893446Smrj 	bop_printf(NULL, "Stack traceback:\n");
15903446Smrj 	for (cnt = 0; cnt < 30; ++cnt) {	/* up to 30 frames */
15913446Smrj 		pc = frame->retaddr;
15923446Smrj 		if (pc == 0)
15933446Smrj 			break;
15943446Smrj 		ksym = kobj_getsymname(pc, &off);
15953446Smrj 		if (ksym)
15963446Smrj 			bop_printf(NULL, "  %s+%lx", ksym, off);
15973446Smrj 		else
15983446Smrj 			bop_printf(NULL, "  0x%lx", pc);
15993446Smrj 
16003446Smrj 		frame = frame->old_frame;
16013446Smrj 		if (frame == 0) {
16023446Smrj 			bop_printf(NULL, "\n");
16033446Smrj 			break;
16043446Smrj 		}
160510993SDan.Mick@Sun.COM #if defined(__i386)
16063446Smrj 		for (a = 0; a < 6; ++a) {	/* try for 6 args */
16073446Smrj 			if ((void *)&frame->arg[a] == (void *)frame->old_frame)
16083446Smrj 				break;
16093446Smrj 			if (a == 0)
16103446Smrj 				bop_printf(NULL, "(");
16113446Smrj 			else
16123446Smrj 				bop_printf(NULL, ",");
16133446Smrj 			bop_printf(NULL, "0x%lx", frame->arg[a]);
161410993SDan.Mick@Sun.COM 		}
161510993SDan.Mick@Sun.COM 		bop_printf(NULL, ")");
16163446Smrj #endif
161710993SDan.Mick@Sun.COM 		bop_printf(NULL, "\n");
16183446Smrj 	}
16193446Smrj }
16203446Smrj 
16213446Smrj struct trapframe {
16223446Smrj 	ulong_t error_code;	/* optional */
16233446Smrj 	ulong_t inst_ptr;
16243446Smrj 	ulong_t code_seg;
16253446Smrj 	ulong_t flags_reg;
16263446Smrj #ifdef __amd64
16273446Smrj 	ulong_t stk_ptr;
16283446Smrj 	ulong_t stk_seg;
16293446Smrj #endif
16303446Smrj };
16313446Smrj 
16323446Smrj void
bop_trap(ulong_t * tfp)163310993SDan.Mick@Sun.COM bop_trap(ulong_t *tfp)
16343446Smrj {
163510993SDan.Mick@Sun.COM 	struct trapframe *tf = (struct trapframe *)tfp;
16363446Smrj 	bop_frame_t fakeframe;
16373446Smrj 	static int depth = 0;
16383446Smrj 
16393446Smrj 	/*
16404159Sjosephb 	 * Check for an infinite loop of traps.
16413446Smrj 	 */
16424159Sjosephb 	if (++depth > 2)
16434159Sjosephb 		bop_panic("Nested trap");
16443446Smrj 
164510993SDan.Mick@Sun.COM 	bop_printf(NULL, "Unexpected trap\n");
164610993SDan.Mick@Sun.COM 
16473446Smrj 	/*
16483446Smrj 	 * adjust the tf for optional error_code by detecting the code selector
16493446Smrj 	 */
16503446Smrj 	if (tf->code_seg != bcode_sel)
165110993SDan.Mick@Sun.COM 		tf = (struct trapframe *)(tfp - 1);
165210993SDan.Mick@Sun.COM 	else
165310993SDan.Mick@Sun.COM 		bop_printf(NULL, "error code           0x%lx\n",
165410993SDan.Mick@Sun.COM 		    tf->error_code & 0xffffffff);
16553446Smrj 
16563446Smrj 	bop_printf(NULL, "instruction pointer  0x%lx\n", tf->inst_ptr);
16573446Smrj 	bop_printf(NULL, "code segment         0x%lx\n", tf->code_seg & 0xffff);
16583446Smrj 	bop_printf(NULL, "flags register       0x%lx\n", tf->flags_reg);
16593446Smrj #ifdef __amd64
166010993SDan.Mick@Sun.COM 	bop_printf(NULL, "return %%rsp          0x%lx\n", tf->stk_ptr);
166110993SDan.Mick@Sun.COM 	bop_printf(NULL, "return %%ss           0x%lx\n", tf->stk_seg & 0xffff);
16623446Smrj #endif
166310993SDan.Mick@Sun.COM 
166410993SDan.Mick@Sun.COM 	/* grab %[er]bp pushed by our code from the stack */
166510993SDan.Mick@Sun.COM 	fakeframe.old_frame = (bop_frame_t *)*(tfp - 3);
16663446Smrj 	fakeframe.retaddr = (pc_t)tf->inst_ptr;
16673446Smrj 	bop_printf(NULL, "Attempting stack backtrace:\n");
16683446Smrj 	bop_traceback(&fakeframe);
16693446Smrj 	bop_panic("unexpected trap in early boot");
16703446Smrj }
16713446Smrj 
16723446Smrj extern void bop_trap_handler(void);
16733446Smrj 
16745460Sjosephb static gate_desc_t *bop_idt;
16753446Smrj 
16763446Smrj static desctbr_t bop_idt_info;
16773446Smrj 
16783446Smrj static void
bop_idt_init(void)16793446Smrj bop_idt_init(void)
16803446Smrj {
16813446Smrj 	int t;
16823446Smrj 
16835460Sjosephb 	bop_idt = (gate_desc_t *)
16845460Sjosephb 	    do_bsys_alloc(NULL, NULL, MMU_PAGESIZE, MMU_PAGESIZE);
16855460Sjosephb 	bzero(bop_idt, MMU_PAGESIZE);
16863446Smrj 	for (t = 0; t < NIDT; ++t) {
16878679SSeth.Goldberg@Sun.COM 		/*
16888679SSeth.Goldberg@Sun.COM 		 * Note that since boot runs without a TSS, the
16898679SSeth.Goldberg@Sun.COM 		 * double fault handler cannot use an alternate stack
16908679SSeth.Goldberg@Sun.COM 		 * (64-bit) or a task gate (32-bit).
16918679SSeth.Goldberg@Sun.COM 		 */
16923446Smrj 		set_gatesegd(&bop_idt[t], &bop_trap_handler, bcode_sel,
16938679SSeth.Goldberg@Sun.COM 		    SDT_SYSIGT, TRP_KPL, 0);
16943446Smrj 	}
16955460Sjosephb 	bop_idt_info.dtr_limit = (NIDT * sizeof (gate_desc_t)) - 1;
16965460Sjosephb 	bop_idt_info.dtr_base = (uintptr_t)bop_idt;
16973446Smrj 	wr_idtr(&bop_idt_info);
16983446Smrj }
16995460Sjosephb #endif	/* !defined(__xpv) */
17003446Smrj 
17013446Smrj /*
17023446Smrj  * This is where we enter the kernel. It dummies up the boot_ops and
17033446Smrj  * boot_syscalls vectors and jumps off to _kobj_boot()
17043446Smrj  */
17053446Smrj void
_start(struct xboot_info * xbp)17063446Smrj _start(struct xboot_info *xbp)
17073446Smrj {
17083446Smrj 	bootops_t *bops = &bootop;
17093446Smrj 	extern void _kobj_boot();
17103446Smrj 
17113446Smrj 	/*
17123446Smrj 	 * 1st off - initialize the console for any error messages
17133446Smrj 	 */
17143446Smrj 	xbootp = xbp;
17155084Sjohnlev #ifdef __xpv
17165084Sjohnlev 	HYPERVISOR_shared_info = (void *)xbootp->bi_shared_info;
17175084Sjohnlev 	xen_info = xbootp->bi_xen_start_info;
17185084Sjohnlev #endif
17193446Smrj 
17207673SSherry.Moore@Sun.COM #ifndef __xpv
17217656SSherry.Moore@Sun.COM 	if (*((uint32_t *)(FASTBOOT_SWTCH_PA + FASTBOOT_STACK_OFFSET)) ==
17227656SSherry.Moore@Sun.COM 	    FASTBOOT_MAGIC) {
17237656SSherry.Moore@Sun.COM 		post_fastreboot = 1;
17247656SSherry.Moore@Sun.COM 		*((uint32_t *)(FASTBOOT_SWTCH_PA + FASTBOOT_STACK_OFFSET)) = 0;
17257656SSherry.Moore@Sun.COM 	}
17267673SSherry.Moore@Sun.COM #endif
17277656SSherry.Moore@Sun.COM 
172810574SSherry.Moore@Sun.COM 	bcons_init((void *)xbootp->bi_cmdline);
172910574SSherry.Moore@Sun.COM 	have_console = 1;
173010574SSherry.Moore@Sun.COM 
17313446Smrj 	/*
17323446Smrj 	 * enable debugging
17333446Smrj 	 */
17343446Smrj 	if (strstr((char *)xbootp->bi_cmdline, "kbm_debug"))
17353446Smrj 		kbm_debug = 1;
17363446Smrj 
17373446Smrj 	DBG_MSG("\n\n*** Entered Solaris in _start() cmdline is: ");
17383446Smrj 	DBG_MSG((char *)xbootp->bi_cmdline);
17393446Smrj 	DBG_MSG("\n\n\n");
17403446Smrj 
17413446Smrj 	/*
17423489Sjosephb 	 * physavail is no longer used by startup
17433446Smrj 	 */
17443446Smrj 	bm.physinstalled = xbp->bi_phys_install;
17453489Sjosephb 	bm.pcimem = xbp->bi_pcimem;
17469940SVikram.Hegde@Sun.COM 	bm.rsvdmem = xbp->bi_rsvdmem;
17473446Smrj 	bm.physavail = NULL;
17483446Smrj 
17493446Smrj 	/*
17503446Smrj 	 * initialize the boot time allocator
17513446Smrj 	 */
17523446Smrj 	next_phys = xbootp->bi_next_paddr;
17533446Smrj 	DBG(next_phys);
17543446Smrj 	next_virt = (uintptr_t)xbootp->bi_next_vaddr;
17553446Smrj 	DBG(next_virt);
17563446Smrj 	DBG_MSG("Initializing boot time memory management...");
17575084Sjohnlev #ifdef __xpv
17585084Sjohnlev 	{
17595084Sjohnlev 		xen_platform_parameters_t p;
17605084Sjohnlev 
17615084Sjohnlev 		/* This call shouldn't fail, dboot already did it once. */
17625084Sjohnlev 		(void) HYPERVISOR_xen_version(XENVER_platform_parameters, &p);
17635084Sjohnlev 		mfn_to_pfn_mapping = (pfn_t *)(xen_virt_start = p.virt_start);
17645084Sjohnlev 		DBG(xen_virt_start);
17655084Sjohnlev 	}
17665084Sjohnlev #endif
17673446Smrj 	kbm_init(xbootp);
17683446Smrj 	DBG_MSG("done\n");
17693446Smrj 
17703446Smrj 	/*
17713446Smrj 	 * Fill in the bootops vector
17723446Smrj 	 */
17733446Smrj 	bops->bsys_version = BO_VERSION;
17743446Smrj 	bops->boot_mem = &bm;
17753446Smrj 	bops->bsys_alloc = do_bsys_alloc;
17763446Smrj 	bops->bsys_free = do_bsys_free;
17773446Smrj 	bops->bsys_getproplen = do_bsys_getproplen;
17783446Smrj 	bops->bsys_getprop = do_bsys_getprop;
17793446Smrj 	bops->bsys_nextprop = do_bsys_nextprop;
17803446Smrj 	bops->bsys_printf = bop_printf;
17813446Smrj 	bops->bsys_doint = do_bsys_doint;
17823446Smrj 
17833446Smrj 	/*
17843446Smrj 	 * BOP_EALLOC() is no longer needed
17853446Smrj 	 */
17863446Smrj 	bops->bsys_ealloc = do_bsys_ealloc;
17873446Smrj 
17885084Sjohnlev #ifdef __xpv
17895084Sjohnlev 	/*
17905084Sjohnlev 	 * On domain 0 we need to free up some physical memory that is
17915084Sjohnlev 	 * usable for DMA. Since GRUB loaded the boot_archive, it is
17925084Sjohnlev 	 * sitting in low MFN memory. We'll relocated the boot archive
17935084Sjohnlev 	 * pages to high PFN memory.
17945084Sjohnlev 	 */
17955084Sjohnlev 	if (DOMAIN_IS_INITDOMAIN(xen_info))
17965084Sjohnlev 		relocate_boot_archive();
17975084Sjohnlev #endif
17985084Sjohnlev 
17995460Sjosephb #ifndef __xpv
18003446Smrj 	/*
18015460Sjosephb 	 * Install an IDT to catch early pagefaults (shouldn't have any).
18025460Sjosephb 	 * Also needed for kmdb.
18035460Sjosephb 	 */
18045460Sjosephb 	bop_idt_init();
18055460Sjosephb #endif
18065460Sjosephb 
18075460Sjosephb 	/*
18085460Sjosephb 	 * Start building the boot properties from the command line
18093446Smrj 	 */
18103446Smrj 	DBG_MSG("Initializing boot properties:\n");
18113446Smrj 	build_boot_properties();
18123446Smrj 
18133446Smrj 	if (strstr((char *)xbootp->bi_cmdline, "prom_debug") || kbm_debug) {
18143446Smrj 		char *name;
18153446Smrj 		char *value;
18165084Sjohnlev 		char *cp;
18173446Smrj 		int len;
18183446Smrj 
18193446Smrj 		value = do_bsys_alloc(NULL, NULL, MMU_PAGESIZE, MMU_PAGESIZE);
18203446Smrj 		bop_printf(NULL, "\nBoot properties:\n");
18213446Smrj 		name = "";
18223446Smrj 		while ((name = do_bsys_nextprop(NULL, name)) != NULL) {
18233446Smrj 			bop_printf(NULL, "\t0x%p %s = ", (void *)name, name);
18243446Smrj 			(void) do_bsys_getprop(NULL, name, value);
18253446Smrj 			len = do_bsys_getproplen(NULL, name);
18263446Smrj 			bop_printf(NULL, "len=%d ", len);
18273446Smrj 			value[len] = 0;
18285084Sjohnlev 			for (cp = value; *cp; ++cp) {
18295084Sjohnlev 				if (' ' <= *cp && *cp <= '~')
18305084Sjohnlev 					bop_printf(NULL, "%c", *cp);
18315084Sjohnlev 				else
18325084Sjohnlev 					bop_printf(NULL, "-0x%x-", *cp);
18335084Sjohnlev 			}
18345084Sjohnlev 			bop_printf(NULL, "\n");
18353446Smrj 		}
18363446Smrj 	}
18373446Smrj 
18383446Smrj 	/*
18393446Smrj 	 * jump into krtld...
18403446Smrj 	 */
18413446Smrj 	_kobj_boot(&bop_sysp, NULL, bops, NULL);
18423446Smrj }
18433446Smrj 
18443446Smrj 
18453446Smrj /*ARGSUSED*/
18463446Smrj static caddr_t
no_more_alloc(bootops_t * bop,caddr_t virthint,size_t size,int align)18473446Smrj no_more_alloc(bootops_t *bop, caddr_t virthint, size_t size, int align)
18483446Smrj {
18493446Smrj 	panic("Attempt to bsys_alloc() too late\n");
18503446Smrj 	return (NULL);
18513446Smrj }
18523446Smrj 
18533446Smrj /*ARGSUSED*/
18543446Smrj static void
no_more_free(bootops_t * bop,caddr_t virt,size_t size)18553446Smrj no_more_free(bootops_t *bop, caddr_t virt, size_t size)
18563446Smrj {
18573446Smrj 	panic("Attempt to bsys_free() too late\n");
18583446Smrj }
18593446Smrj 
18603446Smrj void
bop_no_more_mem(void)18613446Smrj bop_no_more_mem(void)
18623446Smrj {
18633446Smrj 	DBG(total_bop_alloc_scratch);
18643446Smrj 	DBG(total_bop_alloc_kernel);
18653446Smrj 	bootops->bsys_alloc = no_more_alloc;
18663446Smrj 	bootops->bsys_free = no_more_free;
18673446Smrj }
18683446Smrj 
18693446Smrj 
18703446Smrj /*
18713446Smrj  * Set ACPI firmware properties
18723446Smrj  */
18733446Smrj 
18743446Smrj static caddr_t
vmap_phys(size_t length,paddr_t pa)18753446Smrj vmap_phys(size_t length, paddr_t pa)
18763446Smrj {
18773446Smrj 	paddr_t	start, end;
18783446Smrj 	caddr_t	va;
18793446Smrj 	size_t	len, page;
18803446Smrj 
188111245SZhijun.Fu@Sun.COM #ifdef __xpv
188211245SZhijun.Fu@Sun.COM 	pa = pfn_to_pa(xen_assign_pfn(mmu_btop(pa))) | (pa & MMU_PAGEOFFSET);
188311245SZhijun.Fu@Sun.COM #endif
18843446Smrj 	start = P2ALIGN(pa, MMU_PAGESIZE);
18853446Smrj 	end = P2ROUNDUP(pa + length, MMU_PAGESIZE);
18863446Smrj 	len = end - start;
18873446Smrj 	va = (caddr_t)alloc_vaddr(len, MMU_PAGESIZE);
18883446Smrj 	for (page = 0; page < len; page += MMU_PAGESIZE)
18893446Smrj 		kbm_map((uintptr_t)va + page, start + page, 0, 0);
18903446Smrj 	return (va + (pa & MMU_PAGEOFFSET));
18913446Smrj }
18923446Smrj 
18933446Smrj static uint8_t
checksum_table(uint8_t * tp,size_t len)18943446Smrj checksum_table(uint8_t *tp, size_t len)
18953446Smrj {
18963446Smrj 	uint8_t sum = 0;
18973446Smrj 
18983446Smrj 	while (len-- > 0)
18993446Smrj 		sum += *tp++;
19003446Smrj 
19013446Smrj 	return (sum);
19023446Smrj }
19033446Smrj 
19043446Smrj static int
valid_rsdp(struct rsdp * rp)19053446Smrj valid_rsdp(struct rsdp *rp)
19063446Smrj {
19073446Smrj 
19083446Smrj 	/* validate the V1.x checksum */
19093446Smrj 	if (checksum_table((uint8_t *)&rp->v1, sizeof (struct rsdp_v1)) != 0)
19103446Smrj 		return (0);
19113446Smrj 
19123446Smrj 	/* If pre-ACPI 2.0, this is a valid RSDP */
19133446Smrj 	if (rp->v1.revision < 2)
19143446Smrj 		return (1);
19153446Smrj 
19163446Smrj 	/* validate the V2.x checksum */
19173446Smrj 	if (checksum_table((uint8_t *)rp, sizeof (struct rsdp)) != 0)
19183446Smrj 		return (0);
19193446Smrj 
19203446Smrj 	return (1);
19213446Smrj }
19223446Smrj 
19233446Smrj /*
19243446Smrj  * Scan memory range for an RSDP;
19253446Smrj  * see ACPI 3.0 Spec, 5.2.5.1
19263446Smrj  */
19273446Smrj static struct rsdp *
scan_rsdp(paddr_t start,paddr_t end)19283446Smrj scan_rsdp(paddr_t start, paddr_t end)
19293446Smrj {
19303446Smrj 	size_t len  = end - start + 1;
19313446Smrj 	caddr_t ptr;
19323446Smrj 
19333446Smrj 	ptr = vmap_phys(len, start);
19343446Smrj 	while (len > 0) {
19353446Smrj 		if (strncmp(ptr, ACPI_RSDP_SIG, ACPI_RSDP_SIG_LEN) == 0)
19363446Smrj 			if (valid_rsdp((struct rsdp *)ptr))
19373446Smrj 				return ((struct rsdp *)ptr);
19383446Smrj 		ptr += 16;
19393446Smrj 		len -= 16;
19403446Smrj 	}
19413446Smrj 
19423446Smrj 	return (NULL);
19433446Smrj }
19443446Smrj 
19453446Smrj /*
19463446Smrj  * Refer to ACPI 3.0 Spec, section 5.2.5.1 to understand this function
19473446Smrj  */
19483446Smrj static struct rsdp *
find_rsdp()19493446Smrj find_rsdp() {
19503446Smrj 	struct rsdp *rsdp;
19513446Smrj 	uint16_t *ebda_seg;
19523446Smrj 	paddr_t  ebda_addr;
19533446Smrj 
19543446Smrj 	/*
19553446Smrj 	 * Get the EBDA segment and scan the first 1K
19563446Smrj 	 */
19573446Smrj 	ebda_seg = (uint16_t *)vmap_phys(sizeof (uint16_t), ACPI_EBDA_SEG_ADDR);
19583446Smrj 	ebda_addr = *ebda_seg << 4;
19593446Smrj 	rsdp = scan_rsdp(ebda_addr, ebda_addr + ACPI_EBDA_LEN - 1);
19603446Smrj 	if (rsdp == NULL)
19613446Smrj 		/* if EBDA doesn't contain RSDP, look in BIOS memory */
19623446Smrj 		rsdp = scan_rsdp(0xe0000, 0xfffff);
19633446Smrj 	return (rsdp);
19643446Smrj }
19653446Smrj 
19663446Smrj static struct table_header *
map_fw_table(paddr_t table_addr)19673446Smrj map_fw_table(paddr_t table_addr)
19683446Smrj {
19693446Smrj 	struct table_header *tp;
19703446Smrj 	size_t len = MAX(sizeof (struct table_header), MMU_PAGESIZE);
19713446Smrj 
19723446Smrj 	/*
19733446Smrj 	 * Map at least a page; if the table is larger than this, remap it
19743446Smrj 	 */
19753446Smrj 	tp = (struct table_header *)vmap_phys(len, table_addr);
19763446Smrj 	if (tp->len > len)
19773446Smrj 		tp = (struct table_header *)vmap_phys(tp->len, table_addr);
19783446Smrj 	return (tp);
19793446Smrj }
19803446Smrj 
19813446Smrj static struct table_header *
find_fw_table(char * signature)19823446Smrj find_fw_table(char *signature)
19833446Smrj {
19843446Smrj 	static int revision = 0;
19853446Smrj 	static struct xsdt *xsdt;
19863446Smrj 	static int len;
19873446Smrj 	paddr_t xsdt_addr;
19883446Smrj 	struct rsdp *rsdp;
19893446Smrj 	struct table_header *tp;
19903446Smrj 	paddr_t table_addr;
19913446Smrj 	int	n;
19923446Smrj 
19933446Smrj 	if (strlen(signature) != ACPI_TABLE_SIG_LEN)
19943446Smrj 		return (NULL);
19953446Smrj 
19963446Smrj 	/*
19973446Smrj 	 * Reading the ACPI 3.0 Spec, section 5.2.5.3 will help
19983446Smrj 	 * understand this code.  If we haven't already found the RSDT/XSDT,
19993446Smrj 	 * revision will be 0. Find the RSDP and check the revision
20003446Smrj 	 * to find out whether to use the RSDT or XSDT.  If revision is
20013446Smrj 	 * 0 or 1, use the RSDT and set internal revision to 1; if it is 2,
20023446Smrj 	 * use the XSDT.  If the XSDT address is 0, though, fall back to
20033446Smrj 	 * revision 1 and use the RSDT.
20043446Smrj 	 */
20053446Smrj 	if (revision == 0) {
20063446Smrj 		if ((rsdp = (struct rsdp *)find_rsdp()) != NULL) {
20073446Smrj 			revision = rsdp->v1.revision;
20083446Smrj 			switch (revision) {
20093446Smrj 			case 2:
20103446Smrj 				/*
20113446Smrj 				 * Use the XSDT unless BIOS is buggy and
20123446Smrj 				 * claims to be rev 2 but has a null XSDT
20133446Smrj 				 * address
20143446Smrj 				 */
20153446Smrj 				xsdt_addr = rsdp->xsdt;
20163446Smrj 				if (xsdt_addr != 0)
20173446Smrj 					break;
20183446Smrj 				/* FALLTHROUGH */
20193446Smrj 			case 0:
20203446Smrj 				/* treat RSDP rev 0 as revision 1 internally */
20213446Smrj 				revision = 1;
20223446Smrj 				/* FALLTHROUGH */
20233446Smrj 			case 1:
20243446Smrj 				/* use the RSDT for rev 0/1 */
20253446Smrj 				xsdt_addr = rsdp->v1.rsdt;
20263446Smrj 				break;
20273446Smrj 			default:
20283446Smrj 				/* unknown revision */
20293446Smrj 				revision = 0;
20303446Smrj 				break;
20313446Smrj 			}
20323446Smrj 		}
20333446Smrj 		if (revision == 0)
20343446Smrj 			return (NULL);
20353446Smrj 
20363446Smrj 		/* cache the XSDT info */
20373446Smrj 		xsdt = (struct xsdt *)map_fw_table(xsdt_addr);
20383446Smrj 		len = (xsdt->hdr.len - sizeof (xsdt->hdr)) /
20393446Smrj 		    ((revision == 1) ? sizeof (uint32_t) : sizeof (uint64_t));
20403446Smrj 	}
20413446Smrj 
20423446Smrj 	/*
20433446Smrj 	 * Scan the table headers looking for a signature match
20443446Smrj 	 */
20453446Smrj 	for (n = 0; n < len; n++) {
20463446Smrj 		table_addr = (revision == 1) ? xsdt->p.r[n] : xsdt->p.x[n];
20473446Smrj 		if (table_addr == 0)
20483446Smrj 			continue;
20493446Smrj 		tp = map_fw_table(table_addr);
20503446Smrj 		if (strncmp(tp->sig, signature, ACPI_TABLE_SIG_LEN) == 0) {
20513446Smrj 			return (tp);
20523446Smrj 		}
20533446Smrj 	}
20543446Smrj 	return (NULL);
20553446Smrj }
20563446Smrj 
20573446Smrj static void
process_mcfg(struct mcfg * tp)205811245SZhijun.Fu@Sun.COM process_mcfg(struct mcfg *tp)
205911245SZhijun.Fu@Sun.COM {
206011245SZhijun.Fu@Sun.COM 	struct cfg_base_addr_alloc *cfg_baap;
206111245SZhijun.Fu@Sun.COM 	char *cfg_baa_endp;
206211245SZhijun.Fu@Sun.COM 	int64_t ecfginfo[4];
206311245SZhijun.Fu@Sun.COM 
206411245SZhijun.Fu@Sun.COM 	cfg_baap = tp->CfgBaseAddrAllocList;
206511245SZhijun.Fu@Sun.COM 	cfg_baa_endp = ((char *)tp) + tp->Length;
206611245SZhijun.Fu@Sun.COM 	while ((char *)cfg_baap < cfg_baa_endp) {
206711245SZhijun.Fu@Sun.COM 		if (cfg_baap->base_addr != 0 && cfg_baap->segment == 0) {
206811245SZhijun.Fu@Sun.COM 			ecfginfo[0] = cfg_baap->base_addr;
206911245SZhijun.Fu@Sun.COM 			ecfginfo[1] = cfg_baap->segment;
207011245SZhijun.Fu@Sun.COM 			ecfginfo[2] = cfg_baap->start_bno;
207111245SZhijun.Fu@Sun.COM 			ecfginfo[3] = cfg_baap->end_bno;
207211245SZhijun.Fu@Sun.COM 			bsetprop(MCFG_PROPNAME, strlen(MCFG_PROPNAME),
207311245SZhijun.Fu@Sun.COM 			    ecfginfo, sizeof (ecfginfo));
207411245SZhijun.Fu@Sun.COM 			break;
207511245SZhijun.Fu@Sun.COM 		}
207611245SZhijun.Fu@Sun.COM 		cfg_baap++;
207711245SZhijun.Fu@Sun.COM 	}
207811245SZhijun.Fu@Sun.COM }
207911245SZhijun.Fu@Sun.COM 
208011245SZhijun.Fu@Sun.COM #ifndef __xpv
208111245SZhijun.Fu@Sun.COM static void
process_madt(struct madt * tp)20823446Smrj process_madt(struct madt *tp)
20833446Smrj {
20843446Smrj 	struct madt_processor *cpu, *end;
20853446Smrj 	uint32_t cpu_count = 0;
2086*12004Sjiang.liu@intel.com 	uint32_t cpu_possible_count = 0;
20876671Sjjc 	uint8_t cpu_apicid_array[UINT8_MAX + 1];
20886671Sjjc 
20896671Sjjc 	if (tp != NULL) {
20906671Sjjc 		/*
20916671Sjjc 		 * Determine number of CPUs and keep track of "final" APIC ID
20926671Sjjc 		 * for each CPU by walking through ACPI MADT processor list
20936671Sjjc 		 */
20946671Sjjc 		end = (struct madt_processor *)(tp->hdr.len + (uintptr_t)tp);
20956671Sjjc 		cpu = tp->list;
20966671Sjjc 		while (cpu < end) {
20976671Sjjc 			if (cpu->type == MADT_PROCESSOR) {
20986671Sjjc 				if (cpu->flags & 1) {
20996671Sjjc 					if (cpu_count < UINT8_MAX)
21006671Sjjc 						cpu_apicid_array[cpu_count] =
21016671Sjjc 						    cpu->apic_id;
21026671Sjjc 					cpu_count++;
21036671Sjjc 				}
2104*12004Sjiang.liu@intel.com 				cpu_possible_count++;
21056671Sjjc 			}
21066671Sjjc 
21076671Sjjc 			cpu = (struct madt_processor *)
21086671Sjjc 			    (cpu->len + (uintptr_t)cpu);
21096671Sjjc 		}
21106671Sjjc 
21116671Sjjc 		/*
21126671Sjjc 		 * Make boot property for array of "final" APIC IDs for each
21136671Sjjc 		 * CPU
21146671Sjjc 		 */
21156671Sjjc 		bsetprop(BP_CPU_APICID_ARRAY, strlen(BP_CPU_APICID_ARRAY),
21166671Sjjc 		    cpu_apicid_array, cpu_count * sizeof (uint8_t));
21176671Sjjc 	}
21183446Smrj 
21193446Smrj 	/*
2120*12004Sjiang.liu@intel.com 	 * Check whehter property plat-max-ncpus is already set.
2121*12004Sjiang.liu@intel.com 	 */
2122*12004Sjiang.liu@intel.com 	if (do_bsys_getproplen(NULL, PLAT_MAX_NCPUS_NAME) < 0) {
2123*12004Sjiang.liu@intel.com 		/*
2124*12004Sjiang.liu@intel.com 		 * Set plat-max-ncpus to number of maximum possible CPUs given
2125*12004Sjiang.liu@intel.com 		 * in MADT if it hasn't been set.
2126*12004Sjiang.liu@intel.com 		 * There's no formal way to detect max possible CPUs supported
2127*12004Sjiang.liu@intel.com 		 * by platform according to ACPI spec3.0b. So current CPU
2128*12004Sjiang.liu@intel.com 		 * hotplug implementation expects that all possible CPUs will
2129*12004Sjiang.liu@intel.com 		 * have an entry in MADT table and set plat-max-ncpus to number
2130*12004Sjiang.liu@intel.com 		 * of entries in MADT.
2131*12004Sjiang.liu@intel.com 		 * With introducing of ACPI4.0, Maximum System Capability Table
2132*12004Sjiang.liu@intel.com 		 * (MSCT) provides maximum number of CPUs supported by platform.
2133*12004Sjiang.liu@intel.com 		 * If MSCT is unavailable, fall back to old way.
2134*12004Sjiang.liu@intel.com 		 */
2135*12004Sjiang.liu@intel.com 		if (tp != NULL)
2136*12004Sjiang.liu@intel.com 			bsetpropsi(PLAT_MAX_NCPUS_NAME, cpu_possible_count);
2137*12004Sjiang.liu@intel.com 	}
2138*12004Sjiang.liu@intel.com 
2139*12004Sjiang.liu@intel.com 	/*
2140*12004Sjiang.liu@intel.com 	 * Set boot property boot-max-ncpus to number of CPUs existing at
2141*12004Sjiang.liu@intel.com 	 * boot time. boot-max-ncpus is mainly used for optimization.
2142*12004Sjiang.liu@intel.com 	 */
2143*12004Sjiang.liu@intel.com 	if (tp != NULL)
2144*12004Sjiang.liu@intel.com 		bsetpropsi(BOOT_MAX_NCPUS_NAME, cpu_count);
2145*12004Sjiang.liu@intel.com 
2146*12004Sjiang.liu@intel.com 	/*
21473446Smrj 	 * User-set boot-ncpus overrides firmware count
21483446Smrj 	 */
2149*12004Sjiang.liu@intel.com 	if (do_bsys_getproplen(NULL, BOOT_NCPUS_NAME) >= 0)
21503446Smrj 		return;
21513446Smrj 
21526671Sjjc 	/*
2153*12004Sjiang.liu@intel.com 	 * Set boot property boot-ncpus to number of active CPUs given in MADT
2154*12004Sjiang.liu@intel.com 	 * if it hasn't been set yet.
21556671Sjjc 	 */
21566671Sjjc 	if (tp != NULL)
2157*12004Sjiang.liu@intel.com 		bsetpropsi(BOOT_NCPUS_NAME, cpu_count);
21583446Smrj }
21593446Smrj 
21603446Smrj static void
process_srat(struct srat * tp)21613446Smrj process_srat(struct srat *tp)
21623446Smrj {
21633446Smrj 	struct srat_item *item, *end;
21643446Smrj 	int i;
21653446Smrj 	int proc_num, mem_num;
21663446Smrj #pragma pack(1)
21673446Smrj 	struct {
21683446Smrj 		uint32_t domain;
21693446Smrj 		uint32_t apic_id;
21703446Smrj 		uint32_t sapic_id;
21713446Smrj 	} processor;
21723446Smrj 	struct {
21733446Smrj 		uint32_t domain;
21747282Smishra 		uint32_t x2apic_id;
21757282Smishra 	} x2apic;
21767282Smishra 	struct {
21777282Smishra 		uint32_t domain;
21783446Smrj 		uint64_t addr;
21793446Smrj 		uint64_t length;
21803446Smrj 		uint32_t flags;
21813446Smrj 	} memory;
21823446Smrj #pragma pack()
21833446Smrj 	char prop_name[30];
2184*12004Sjiang.liu@intel.com 	uint64_t maxmem = 0;
21853446Smrj 
21863446Smrj 	if (tp == NULL)
21873446Smrj 		return;
21883446Smrj 
21893446Smrj 	proc_num = mem_num = 0;
21903446Smrj 	end = (struct srat_item *)(tp->hdr.len + (uintptr_t)tp);
21913446Smrj 	item = tp->list;
21923446Smrj 	while (item < end) {
21933446Smrj 		switch (item->type) {
21943446Smrj 		case SRAT_PROCESSOR:
21953446Smrj 			if (!(item->i.p.flags & SRAT_ENABLED))
21963446Smrj 				break;
21973446Smrj 			processor.domain = item->i.p.domain1;
21983446Smrj 			for (i = 0; i < 3; i++)
21993446Smrj 				processor.domain +=
22003446Smrj 				    item->i.p.domain2[i] << ((i + 1) * 8);
22013446Smrj 			processor.apic_id = item->i.p.apic_id;
22023446Smrj 			processor.sapic_id = item->i.p.local_sapic_eid;
22033446Smrj 			(void) snprintf(prop_name, 30, "acpi-srat-processor-%d",
22043446Smrj 			    proc_num);
22053446Smrj 			bsetprop(prop_name, strlen(prop_name), &processor,
22063446Smrj 			    sizeof (processor));
22073446Smrj 			proc_num++;
22083446Smrj 			break;
22093446Smrj 		case SRAT_MEMORY:
22103446Smrj 			if (!(item->i.m.flags & SRAT_ENABLED))
22113446Smrj 				break;
22123446Smrj 			memory.domain = item->i.m.domain;
22133446Smrj 			memory.addr = item->i.m.base_addr;
22143446Smrj 			memory.length = item->i.m.len;
22153446Smrj 			memory.flags = item->i.m.flags;
22163446Smrj 			(void) snprintf(prop_name, 30, "acpi-srat-memory-%d",
22173446Smrj 			    mem_num);
22183446Smrj 			bsetprop(prop_name, strlen(prop_name), &memory,
22193446Smrj 			    sizeof (memory));
2220*12004Sjiang.liu@intel.com 			if ((item->i.m.flags & SRAT_HOT_PLUG) &&
2221*12004Sjiang.liu@intel.com 			    (memory.addr + memory.length > maxmem)) {
2222*12004Sjiang.liu@intel.com 				maxmem = memory.addr + memory.length;
2223*12004Sjiang.liu@intel.com 			}
22243446Smrj 			mem_num++;
22253446Smrj 			break;
22267282Smishra 		case SRAT_X2APIC:
22277282Smishra 			if (!(item->i.xp.flags & SRAT_ENABLED))
22287282Smishra 				break;
22297282Smishra 			x2apic.domain = item->i.xp.domain;
22307282Smishra 			x2apic.x2apic_id = item->i.xp.x2apic_id;
22317282Smishra 			(void) snprintf(prop_name, 30, "acpi-srat-processor-%d",
22327282Smishra 			    proc_num);
22337282Smishra 			bsetprop(prop_name, strlen(prop_name), &x2apic,
22347282Smishra 			    sizeof (x2apic));
22357282Smishra 			proc_num++;
22367282Smishra 			break;
22373446Smrj 		}
22383446Smrj 
22393446Smrj 		item = (struct srat_item *)
22403446Smrj 		    (item->len + (caddr_t)item);
22413446Smrj 	}
2242*12004Sjiang.liu@intel.com 
2243*12004Sjiang.liu@intel.com 	/*
2244*12004Sjiang.liu@intel.com 	 * The maximum physical address calculated from the SRAT table is more
2245*12004Sjiang.liu@intel.com 	 * accurate than that calculated from the MSCT table.
2246*12004Sjiang.liu@intel.com 	 */
2247*12004Sjiang.liu@intel.com 	if (maxmem != 0) {
2248*12004Sjiang.liu@intel.com 		plat_dr_physmax = btop(maxmem);
2249*12004Sjiang.liu@intel.com 	}
22503446Smrj }
22513446Smrj 
22523446Smrj static void
process_slit(struct slit * tp)22533606Smyers process_slit(struct slit *tp)
22543606Smyers {
22553606Smyers 
22563606Smyers 	/*
22573606Smyers 	 * Check the number of localities; if it's too huge, we just
22583606Smyers 	 * return and locality enumeration code will handle this later,
22593606Smyers 	 * if possible.
22603606Smyers 	 *
22613606Smyers 	 * Note that the size of the table is the square of the
22623606Smyers 	 * number of localities; if the number of localities exceeds
22633606Smyers 	 * UINT16_MAX, the table size may overflow an int when being
22643606Smyers 	 * passed to bsetprop() below.
22653606Smyers 	 */
22663606Smyers 	if (tp->number >= SLIT_LOCALITIES_MAX)
22673606Smyers 		return;
22683606Smyers 
22693606Smyers 	bsetprop(SLIT_NUM_PROPNAME, strlen(SLIT_NUM_PROPNAME), &tp->number,
22703606Smyers 	    sizeof (tp->number));
22713606Smyers 	bsetprop(SLIT_PROPNAME, strlen(SLIT_PROPNAME), &tp->entry,
22723606Smyers 	    tp->number * tp->number);
22733606Smyers }
22747589SVikram.Hegde@Sun.COM 
2275*12004Sjiang.liu@intel.com static struct msct *
process_msct(struct msct * tp)2276*12004Sjiang.liu@intel.com process_msct(struct msct *tp)
2277*12004Sjiang.liu@intel.com {
2278*12004Sjiang.liu@intel.com 	int last_seen = 0;
2279*12004Sjiang.liu@intel.com 	int proc_num = 0;
2280*12004Sjiang.liu@intel.com 	struct msct_proximity_domain *item, *end;
2281*12004Sjiang.liu@intel.com 	extern uint64_t plat_dr_options;
2282*12004Sjiang.liu@intel.com 
2283*12004Sjiang.liu@intel.com 	ASSERT(tp != NULL);
2284*12004Sjiang.liu@intel.com 
2285*12004Sjiang.liu@intel.com 	end = (void *)(tp->hdr.len + (uintptr_t)tp);
2286*12004Sjiang.liu@intel.com 	for (item = (void *)((uintptr_t)tp + tp->proximity_domain_offset);
2287*12004Sjiang.liu@intel.com 	    item < end;
2288*12004Sjiang.liu@intel.com 	    item = (void *)(item->length + (uintptr_t)item)) {
2289*12004Sjiang.liu@intel.com 		/*
2290*12004Sjiang.liu@intel.com 		 * Sanity check according to section 5.2.19.1 of ACPI 4.0.
2291*12004Sjiang.liu@intel.com 		 * Revision 	1
2292*12004Sjiang.liu@intel.com 		 * Length	22
2293*12004Sjiang.liu@intel.com 		 */
2294*12004Sjiang.liu@intel.com 		if (item->revision != 1 || item->length != 22) {
2295*12004Sjiang.liu@intel.com 			cmn_err(CE_CONT,
2296*12004Sjiang.liu@intel.com 			    "?boot: unknown proximity domain structure in MSCT "
2297*12004Sjiang.liu@intel.com 			    "with rev(%d), len(%d).\n",
2298*12004Sjiang.liu@intel.com 			    (int)item->revision, (int)item->length);
2299*12004Sjiang.liu@intel.com 			return (NULL);
2300*12004Sjiang.liu@intel.com 		} else if (item->domain_min > item->domain_max) {
2301*12004Sjiang.liu@intel.com 			cmn_err(CE_CONT,
2302*12004Sjiang.liu@intel.com 			    "?boot: invalid proximity domain structure in MSCT "
2303*12004Sjiang.liu@intel.com 			    "with domain_min(%u), domain_max(%u).\n",
2304*12004Sjiang.liu@intel.com 			    item->domain_min, item->domain_max);
2305*12004Sjiang.liu@intel.com 			return (NULL);
2306*12004Sjiang.liu@intel.com 		} else if (item->domain_min != last_seen) {
2307*12004Sjiang.liu@intel.com 			/*
2308*12004Sjiang.liu@intel.com 			 * Items must be organized in ascending order of the
2309*12004Sjiang.liu@intel.com 			 * proximity domain enumerations.
2310*12004Sjiang.liu@intel.com 			 */
2311*12004Sjiang.liu@intel.com 			cmn_err(CE_CONT,
2312*12004Sjiang.liu@intel.com 			    "?boot: invalid proximity domain structure in MSCT,"
2313*12004Sjiang.liu@intel.com 			    " items are not orginized in ascending order.\n");
2314*12004Sjiang.liu@intel.com 			return (NULL);
2315*12004Sjiang.liu@intel.com 		}
2316*12004Sjiang.liu@intel.com 
2317*12004Sjiang.liu@intel.com 		/*
2318*12004Sjiang.liu@intel.com 		 * If processor_max is 0 then there would be no CPUs in this
2319*12004Sjiang.liu@intel.com 		 * domain.
2320*12004Sjiang.liu@intel.com 		 */
2321*12004Sjiang.liu@intel.com 		if (item->processor_max != 0) {
2322*12004Sjiang.liu@intel.com 			proc_num += (item->domain_max - item->domain_min + 1) *
2323*12004Sjiang.liu@intel.com 			    item->processor_max;
2324*12004Sjiang.liu@intel.com 		}
2325*12004Sjiang.liu@intel.com 
2326*12004Sjiang.liu@intel.com 		last_seen = item->domain_max - item->domain_min + 1;
2327*12004Sjiang.liu@intel.com 		/*
2328*12004Sjiang.liu@intel.com 		 * Break out if all proximity domains have been processed.
2329*12004Sjiang.liu@intel.com 		 * Some BIOSes may have unused items at the end of MSCT table.
2330*12004Sjiang.liu@intel.com 		 */
2331*12004Sjiang.liu@intel.com 		if (last_seen > tp->maximum_proximity_domains) {
2332*12004Sjiang.liu@intel.com 			break;
2333*12004Sjiang.liu@intel.com 		}
2334*12004Sjiang.liu@intel.com 	}
2335*12004Sjiang.liu@intel.com 	if (last_seen != tp->maximum_proximity_domains + 1) {
2336*12004Sjiang.liu@intel.com 		cmn_err(CE_CONT,
2337*12004Sjiang.liu@intel.com 		    "?boot: invalid proximity domain structure in MSCT, "
2338*12004Sjiang.liu@intel.com 		    "proximity domain count doesn't match.\n");
2339*12004Sjiang.liu@intel.com 		return (NULL);
2340*12004Sjiang.liu@intel.com 	}
2341*12004Sjiang.liu@intel.com 
2342*12004Sjiang.liu@intel.com 	/*
2343*12004Sjiang.liu@intel.com 	 * Set plat-max-ncpus property if it hasn't been set yet.
2344*12004Sjiang.liu@intel.com 	 */
2345*12004Sjiang.liu@intel.com 	if (do_bsys_getproplen(NULL, PLAT_MAX_NCPUS_NAME) < 0) {
2346*12004Sjiang.liu@intel.com 		if (proc_num != 0) {
2347*12004Sjiang.liu@intel.com 			bsetpropsi(PLAT_MAX_NCPUS_NAME, proc_num);
2348*12004Sjiang.liu@intel.com 		}
2349*12004Sjiang.liu@intel.com 	}
2350*12004Sjiang.liu@intel.com 
2351*12004Sjiang.liu@intel.com 	/*
2352*12004Sjiang.liu@intel.com 	 * Use Maximum Physical Address from the MSCT table as upper limit for
2353*12004Sjiang.liu@intel.com 	 * memory hot-adding by default. It may be overridden by value from
2354*12004Sjiang.liu@intel.com 	 * the SRAT table or the "plat-dr-physmax" boot option.
2355*12004Sjiang.liu@intel.com 	 */
2356*12004Sjiang.liu@intel.com 	plat_dr_physmax = btop(tp->maximum_physical_address + 1);
2357*12004Sjiang.liu@intel.com 
2358*12004Sjiang.liu@intel.com 	/*
2359*12004Sjiang.liu@intel.com 	 * Existence of MSCT implies CPU/memory hotplug-capability for the
2360*12004Sjiang.liu@intel.com 	 * platform.
2361*12004Sjiang.liu@intel.com 	 */
2362*12004Sjiang.liu@intel.com 	plat_dr_options |= PLAT_DR_FEATURE_CPU;
2363*12004Sjiang.liu@intel.com 	plat_dr_options |= PLAT_DR_FEATURE_MEMORY;
2364*12004Sjiang.liu@intel.com 
2365*12004Sjiang.liu@intel.com 	return (tp);
2366*12004Sjiang.liu@intel.com }
2367*12004Sjiang.liu@intel.com 
23685084Sjohnlev #else /* __xpv */
23695084Sjohnlev static void
enumerate_xen_cpus()23705084Sjohnlev enumerate_xen_cpus()
23715084Sjohnlev {
23725084Sjohnlev 	processorid_t	id, max_id;
23735084Sjohnlev 
23745084Sjohnlev 	/*
23755084Sjohnlev 	 * User-set boot-ncpus overrides enumeration
23765084Sjohnlev 	 */
2377*12004Sjiang.liu@intel.com 	if (do_bsys_getproplen(NULL, BOOT_NCPUS_NAME) >= 0)
23785084Sjohnlev 		return;
23795084Sjohnlev 
23805084Sjohnlev 	/*
23815084Sjohnlev 	 * Probe every possible virtual CPU id and remember the
23825084Sjohnlev 	 * highest id present; the count of CPUs is one greater
23835084Sjohnlev 	 * than this.  This tacitly assumes at least cpu 0 is present.
23845084Sjohnlev 	 */
23855084Sjohnlev 	max_id = 0;
23865084Sjohnlev 	for (id = 0; id < MAX_VIRT_CPUS; id++)
23875084Sjohnlev 		if (HYPERVISOR_vcpu_op(VCPUOP_is_up, id, NULL) == 0)
23885084Sjohnlev 			max_id = id;
23895084Sjohnlev 
2390*12004Sjiang.liu@intel.com 	bsetpropsi(BOOT_NCPUS_NAME, max_id+1);
23915084Sjohnlev 
23925084Sjohnlev }
23935084Sjohnlev #endif /* __xpv */
23943606Smyers 
23953606Smyers static void
build_firmware_properties(void)23963446Smrj build_firmware_properties(void)
23973446Smrj {
239811245SZhijun.Fu@Sun.COM 	struct table_header *tp = NULL;
239911245SZhijun.Fu@Sun.COM 
24005084Sjohnlev #ifndef __xpv
2401*12004Sjiang.liu@intel.com 	if ((msct_ptr = (struct msct *)find_fw_table("MSCT")) != NULL)
2402*12004Sjiang.liu@intel.com 		msct_ptr = process_msct(msct_ptr);
2403*12004Sjiang.liu@intel.com 
24045084Sjohnlev 	if ((tp = find_fw_table("APIC")) != NULL)
24053446Smrj 		process_madt((struct madt *)tp);
24063446Smrj 
24076445Sjjc 	if ((srat_ptr = (struct srat *)find_fw_table("SRAT")) != NULL)
24086445Sjjc 		process_srat(srat_ptr);
24093606Smyers 
24106445Sjjc 	if (slit_ptr = (struct slit *)find_fw_table("SLIT"))
24116445Sjjc 		process_slit(slit_ptr);
24127589SVikram.Hegde@Sun.COM 
241311245SZhijun.Fu@Sun.COM 	tp = find_fw_table("MCFG");
24145084Sjohnlev #else /* __xpv */
24155084Sjohnlev 	enumerate_xen_cpus();
241611245SZhijun.Fu@Sun.COM 	if (DOMAIN_IS_INITDOMAIN(xen_info))
241711245SZhijun.Fu@Sun.COM 		tp = find_fw_table("MCFG");
24185084Sjohnlev #endif /* __xpv */
241911245SZhijun.Fu@Sun.COM 	if (tp != NULL)
242011245SZhijun.Fu@Sun.COM 		process_mcfg((struct mcfg *)tp);
24213446Smrj }
24223446Smrj 
24233446Smrj /*
24248960SJan.Setje-Eilers@Sun.COM  * fake up a boot property for deferred early console output
24258960SJan.Setje-Eilers@Sun.COM  * this is used by both graphical boot and the (developer only)
24268960SJan.Setje-Eilers@Sun.COM  * USB serial console
24273446Smrj  */
24283446Smrj void *
defcons_init(size_t size)24298960SJan.Setje-Eilers@Sun.COM defcons_init(size_t size)
24303446Smrj {
24313446Smrj 	static char *p = NULL;
24323446Smrj 
24333446Smrj 	p = do_bsys_alloc(NULL, NULL, size, MMU_PAGESIZE);
24343446Smrj 	*p = 0;
24358960SJan.Setje-Eilers@Sun.COM 	bsetprop("deferred-console-buf", strlen("deferred-console-buf") + 1,
24363446Smrj 	    &p, sizeof (p));
24373446Smrj 	return (p);
24383446Smrj }
24395648Ssetje 
24405648Ssetje /*ARGSUSED*/
24415648Ssetje int
boot_compinfo(int fd,struct compinfo * cbp)24425648Ssetje boot_compinfo(int fd, struct compinfo *cbp)
24435648Ssetje {
24445648Ssetje 	cbp->iscmp = 0;
24455648Ssetje 	cbp->blksize = MAXBSIZE;
24465648Ssetje 	return (0);
24475648Ssetje }
24489053Sjonathan.chew@sun.com 
24499053Sjonathan.chew@sun.com #define	BP_MAX_STRLEN	32
24509053Sjonathan.chew@sun.com 
24519053Sjonathan.chew@sun.com /*
24529053Sjonathan.chew@sun.com  * Get value for given boot property
24539053Sjonathan.chew@sun.com  */
24549053Sjonathan.chew@sun.com int
bootprop_getval(const char * prop_name,u_longlong_t * prop_value)24559053Sjonathan.chew@sun.com bootprop_getval(const char *prop_name, u_longlong_t *prop_value)
24569053Sjonathan.chew@sun.com {
24579053Sjonathan.chew@sun.com 	int		boot_prop_len;
24589053Sjonathan.chew@sun.com 	char		str[BP_MAX_STRLEN];
24599053Sjonathan.chew@sun.com 	u_longlong_t	value;
24609053Sjonathan.chew@sun.com 
24619053Sjonathan.chew@sun.com 	boot_prop_len = BOP_GETPROPLEN(bootops, prop_name);
24629053Sjonathan.chew@sun.com 	if (boot_prop_len < 0 || boot_prop_len > sizeof (str) ||
24639053Sjonathan.chew@sun.com 	    BOP_GETPROP(bootops, prop_name, str) < 0 ||
24649053Sjonathan.chew@sun.com 	    kobj_getvalue(str, &value) == -1)
24659053Sjonathan.chew@sun.com 		return (-1);
24669053Sjonathan.chew@sun.com 
24679053Sjonathan.chew@sun.com 	if (prop_value)
24689053Sjonathan.chew@sun.com 		*prop_value = value;
24699053Sjonathan.chew@sun.com 
24709053Sjonathan.chew@sun.com 	return (0);
24719053Sjonathan.chew@sun.com }
2472