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