fakebop.c revision 753a6d457b330b1b29b2d3eefcd0831116ce950d
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* This file contains the functionality that mimics the boot operations
* The x86 kernel now does everything on its own.
*/
#include <sys/bootconf.h>
#include <sys/bootsvcs.h>
#include <sys/bootinfo.h>
#include <sys/multiboot.h>
#include <sys/bootprops.h>
#include <sys/machparam.h>
#include <sys/archsystm.h>
#include <sys/boot_console.h>
#include <sys/archsystm.h>
#include <sys/x86_archext.h>
#include <sys/privregs.h>
#include <sys/sysmacros.h>
#include <sys/fastboot.h>
#ifdef __xpv
#include <sys/hypervisor.h>
#endif
#include <vm/kboot_mmu.h>
#include <sys/dmar_acpi.h>
#include <sys/kobj_lex.h>
#include "acpi_fw.h"
static int have_console = 0; /* set once primitive console is initialized */
static char *boot_args = "";
/*
* Debugging macros
*/
}
#define PUT_STRING(s) { \
char *cp; \
bcons_putchar(*cp); \
}
/*
* buffer for vsnprintf for console I/O
*/
#define BUFFERSIZE 256
static char buffer[BUFFERSIZE];
/*
* stuff to store/report/manipulate boot property settings.
*/
typedef struct bootprop {
char *bp_name;
char *bp_value;
} bootprop_t;
static int curr_space = 0; /* amount of memory at curr_page */
#ifdef __xpv
#endif
/*
* some allocator statistics
*/
static ulong_t total_bop_alloc_scratch = 0;
static ulong_t total_bop_alloc_kernel = 0;
static void build_firmware_properties(void);
static int early_allocation = 1;
int force_fastreboot = 0;
int fastreboot_onpanic = 0;
int post_fastreboot = 0;
#ifdef __xpv
int fastreboot_capable = 0;
#else
int fastreboot_capable = 1;
#endif
/*
* Information saved from current boot for fast reboot.
* If the information size exceeds what we have allocated, fast reboot
* will not be supported.
*/
int saved_cmdline_len = 0;
/*
* Turn off fastreboot_onpanic to avoid panic loop.
*/
static const char fastreboot_onpanic_args[] = " -B fastreboot_onpanic=0";
/*
* Pointers to where System Resource Affinity Table (SRAT) and
* System Locality Information Table (SLIT) are mapped into virtual memory
*/
/*
* Allocate aligned physical memory at boot time. This allocator allocates
* from the highest possible addresses. This avoids exhausting memory that
* would be useful for DMA buffers.
*/
{
/*
* Be careful if high memory usage is limited in startup.c
* Since there are holes in the low part of the physical address
* space we can treat physmem as a pfn (not just a pgcnt) and
* get a conservative upper limit.
*/
/*
* find the lowest or highest available memory in physinstalled
* On 32 bit avoid physmem above 4Gig if PAE isn't enabled
*/
#if defined(__i386)
#endif
/*
* find the highest available memory in physinstalled
*/
continue;
continue;
/*
* Early allocations need to use low memory, since
* physmem might be further limited by bootenv.rc
*/
if (early_allocation) {
} else {
}
}
if (pa != 0) {
if (early_allocation)
else
return (pa);
}
/*NOTREACHED*/
}
static uintptr_t
{
return (rv);
}
/*
* Allocate virtual memory. The size is always rounded up to a multiple
* of base pagesize.
*/
/*ARGSUSED*/
static caddr_t
{
ssize_t s; /* the aligned size */
if (a < MMU_PAGESIZE)
a = MMU_PAGESIZE;
else if (!ISP2(a))
prom_panic("do_bsys_alloc() incorrect alignment");
/*
* Use the next aligned virtual address if we weren't given one.
*/
} else {
}
/*
* allocate the physical memory
*/
/*
* Add the mappings to the page tables, try large pages first.
*/
s = size;
level = 1;
s >= pgsize) {
s -= pgsize;
}
}
/*
* Map remaining pages use small mappings
*/
level = 0;
while (s > 0) {
s -= pgsize;
}
return (virthint);
}
/*
* Free virtual memory - we'll just ignore these.
*/
/*ARGSUSED*/
static void
{
}
/*
* Old interface
*/
/*ARGSUSED*/
static caddr_t
int align,
int flags)
{
prom_panic("unsupported call to BOP_EALLOC()\n");
return (0);
}
static void
{
bootprop_t *b;
/*
* align the size to 16 byte boundary
*/
if (size > curr_space) {
}
/*
* use a bootprop_t at curr_page and link into list
*/
b = (bootprop_t *)curr_page;
curr_page += sizeof (bootprop_t);
curr_space -= sizeof (bootprop_t);
bprops = b;
/*
* follow by name and ending zero byte
*/
*curr_page++ = 0;
/*
* copy in value, but no ending zero byte
*/
if (vlen > 0) {
curr_space -= vlen;
}
/*
* align new values of curr_page, curr_space
*/
while (curr_space & 0xf) {
++curr_page;
--curr_space;
}
}
static void
{
}
static void
{
}
static void
{
char prop_val[32];
}
/*
* to find the size of the buffer to allocate
*/
/*ARGSUSED*/
int
{
bootprop_t *b;
continue;
return (b->bp_vlen);
}
return (-1);
}
/*
* get the value associated with this name
*/
/*ARGSUSED*/
int
{
bootprop_t *b;
continue;
return (0);
}
return (-1);
}
/*
* get the name of the next property in succession from the standalone
*/
/*ARGSUSED*/
static char *
{
bootprop_t *b;
/*
* A null name is a special signal for the 1st boot property
*/
return (NULL);
}
continue;
b = b->bp_next;
if (b == NULL)
return (NULL);
return (b->bp_name);
}
return (NULL);
}
/*
* Parse numeric value from a string. Understands decimal, hex, octal, - and ~
*/
static int
{
int adjust = 0;
int digit;
int radix = 10;
*retval = 0;
if (*p == '-' || *p == '~')
adjust = *p++;
if (*p == '0') {
++p;
if (*p == 0)
return (0);
if (*p == 'x' || *p == 'X') {
radix = 16;
++p;
} else {
radix = 8;
++p;
}
}
while (*p) {
if ('0' <= *p && *p <= '9')
digit = *p - '0';
else if ('a' <= *p && *p <= 'f')
else if ('A' <= *p && *p <= 'F')
else
return (-1);
return (-1);
++p;
}
if (adjust == '-')
else if (adjust == '~')
return (0);
}
/*
* 2nd part of building the table of boot properties. This includes:
* - values from /boot/solaris/bootenv.rc (ie. eeprom(1m) values)
*
* lines look like one of:
* ^$
* ^# comment till end of line
* setprop name 'value'
* setprop name value
* setprop name "value"
*
* we do single character I/O since this is really just looking at memory
*/
void
boot_prop_finish(void)
{
int fd;
char *line;
int c;
int bytes_read;
char *name;
int n_len;
char *value;
int v_len;
char *inputdev; /* these override the command line if serial ports */
char *outputdev;
char *consoledev;
int use_xencons = 0;
#ifdef __xpv
if (!DOMAIN_IS_INITDOMAIN(xen_info))
use_xencons = 1;
#endif /* __xpv */
DBG_MSG("Opening /boot/solaris/bootenv.rc\n");
while (fd >= 0) {
/*
* get a line
*/
for (c = 0; ; ++c) {
if (bytes_read == 0) {
if (c == 0)
goto done;
break;
}
if (line[c] == '\n')
break;
}
line[c] = 0;
/*
* ignore comment lines
*/
c = 0;
++c;
continue;
/*
* must have "setprop " or "setprop\t"
*/
continue;
c += 8;
++c;
if (line[c] == 0)
continue;
/*
* gather up the property name
*/
n_len = 0;
++n_len, ++c;
/*
* gather up the value, if any
*/
value = "";
v_len = 0;
++c;
if (line[c] != 0) {
++v_len, ++c;
}
++value;
v_len -= 2;
}
if (v_len > 0)
else
continue;
/*
* ignore "boot-file" property, it's now meaningless
*/
continue;
continue;
/*
* If a property was explicitly set on the command line
* it will override a setting in bootenv.rc
*/
continue;
}
done:
if (fd >= 0)
/*
* Check if we have to limit the boot time allocator
*/
}
}
early_allocation = 0;
/*
* check to see if we have to override the default value of the console
*/
if (!use_xencons) {
if (v_len > 0)
else
v_len = 0;
if (v_len > 0)
else
v_len = 0;
if (v_len > 0)
else
v_len = 0;
consoledev[v_len] = 0;
} else {
/*
* Ensure console property exists
* If not create it as "hypervisor"
*/
if (v_len < 0)
}
name = "";
}
}
}
/*
* print formatted output
*/
/*PRINTFLIKE2*/
/*ARGSUSED*/
void
{
if (have_console == 0)
return;
}
/*
* Another panic() variant; this one can be used even earlier during boot than
* prom_panic().
*/
/*PRINTFLIKE1*/
void
{
(void) bcons_getchar();
pc_reset();
}
/*
* Do a real mode interrupt BIOS call
*/
typedef struct bios_regs {
} bios_regs_t;
typedef int (*bios_func_t)(int, bios_regs_t *);
/*ARGSUSED*/
static void
{
#if defined(__xpv)
prom_panic("unsupported call to BOP_DOINT()\n");
#else /* __xpv */
static int firsttime = 1;
/*
* The first time we do this, we have to copy the pre-packaged
* low memory bios call code image into place.
*/
if (firsttime) {
extern char bios_image[];
firsttime = 0;
}
DBG_MSG("Doing BIOS call...");
DBG_MSG("done\n");
#endif /* __xpv */
}
static struct boot_syscalls bop_sysp = {
};
static char *whoami;
#define BUFLEN 64
#if defined(__xpv)
static char namebuf[32];
static void
{
do {
cp++;
}
cp++;
prop_name++;
n_prop--;
} while (n_prop > 0);
}
#define VBDPATHLEN 64
/*
* parse the 'xpv-root' property to create properties used by
* ufs_mountroot.
*/
static void
xen_vbdroot_props(char *s)
{
char *pnp;
char *prop_p;
char mi;
short minor;
long addr = 0;
if (*prop_p == 's')
mi = 'a';
else if (*prop_p == 'p')
mi = 'q';
else
ASSERT(0); /* shouldn't be here */
prop_p++;
prop_p++;
}
} else {
/* malformed root path, use 0 as default */
minor = 0;
}
*pnp++ = ':';
*pnp++ = '\0';
DBG_MSG("VBD bootpath set to ");
DBG_MSG("\n");
}
/*
* parse the xpv-nfsroot property to create properties used by
* nfs_mountroot.
*/
static void
xen_nfsroot_props(char *s)
{
char *prop_map[] = {
BP_SERVER_IP, /* server IP address */
BP_SERVER_NAME, /* server hostname */
BP_SERVER_PATH, /* root path */
};
/*
* If a server name wasn't specified, use a default.
*/
}
/*
* Extract our IP address, etc. from the "xpv-ip" property.
*/
static void
xen_ip_props(char *s)
{
char *prop_map[] = {
BP_HOST_IP, /* IP address */
NULL, /* NFS server IP address (ignored in */
/* favour of xpv-nfsroot) */
BP_ROUTER_IP, /* IP gateway */
BP_SUBNET_MASK, /* IP subnet mask */
"xpv-hostname", /* hostname (ignored) */
BP_NETWORK_INTERFACE, /* interface name */
"xpv-hcp", /* host configuration protocol */
};
/*
* A Linux dom0 administrator expects all interfaces to be
* called "ethX", which is not the case here.
*
* If the interface name specified is "eth0", presume that
* this is really intended to be "xnf0" (the first domU ->
* dom0 interface for this domain).
*/
"network interface name 'eth0' replaced with 'xnf0'\n");
}
}
#else /* __xpv */
static void
{
}
if (sip->sn_netmask != 0) {
}
} else {
}
}
#endif /* __xpv */
static void
{
int proplen;
arglen = sizeof (fastreboot_onpanic_args);
/*
* If we allready have fastreboot-onpanic set to zero,
* don't add them again.
*/
proplen <= sizeof (fastreboot_onpanic_cmdline)) {
arglen = 1;
}
/*
* construct fastreboot_onpanic_cmdline
*/
DBG_MSG("Command line too long: clearing "
FASTREBOOT_ONPANIC "\n");
fastreboot_onpanic = 0;
} else {
if (arglen != 1)
else
}
}
#ifndef __xpv
/*
* Construct boot command line for Fast Reboot
*/
static void
build_fastboot_cmdline(void)
{
DBG_MSG("Command line too long: clearing fastreboot_capable\n");
fastreboot_capable = 0;
} else {
}
}
/*
* Save memory layout, disk drive information, unix and boot archive sizes for
* Fast Reboot.
*/
static void
{
int i;
DBG_MSG("mbi->mmap_length too big: clearing "
"fastreboot_capable\n");
fastreboot_capable = 0;
} else {
mbi->mmap_length);
}
DBG_MSG("mbi->drives_length too big: clearing "
"fastreboot_capable\n");
fastreboot_capable = 0;
} else {
mbi->drives_length);
}
/*
* Current file sizes. Used by fastboot.c to figure out how much
* memory to reserve for panic reboot.
*/
}
}
#endif /* __xpv */
/*
* 1st pass at building the table of boot properties. This includes:
* - values set on the command line: -B a=x,b=y,c=z ....
* - known values we just compute (ie. from xbootp)
* - values from /boot/solaris/bootenv.rc (ie. eeprom(1m) values)
*
* the grub command line looked like:
* kernel boot-file [-B prop=value[,prop=value]...] [boot-args]
*
* whoami is the same as boot-file
*/
static void
build_boot_properties(void)
{
char *name;
int name_len;
char *value;
int value_len;
struct boot_modules *bm;
char *propbuf;
int quoted = 0;
int boot_arg_len;
#ifndef __xpv
static int stdout_val = 0;
char str[3];
int netboot;
struct sol_netinfo *sip;
#endif
/*
* These have to be done first, so that kobj_mount_root() works
*/
DBG_MSG("Building boot properties\n");
if (xbootp->bi_module_cnt > 0) {
}
DBG_MSG("Parsing command line for boot properties\n");
/*
* allocate memory to collect boot_args into
*/
boot_args[0] = 0;
boot_arg_len = 0;
#ifdef __xpv
/*
* Xen puts a lot of device information in front of the kernel name
* let's grab them and make them boot properties. The first
* string w/o an "=" in it will be the boot-file property.
*/
for (;;) {
/*
* get to next property
*/
++value;
/*
* look for an "="
*/
value++;
}
break;
}
value_len = 0;
/*
* skip over the "="
*/
value++;
++value_len;
}
/*
* build property name with "xpv-" prefix
*/
continue;
}
name_len += 4;
/*
* xpv-root is set to the logical disk name of the xen
* VBD when booting from a disk-based filesystem.
*/
/*
* While we're here, if we have a "xpv-nfsroot" property
* then we need to set "fstype" to "nfs" so we mount
* our root from the nfs server. Also parse the xpv-nfsroot
* property to create the properties that nfs_mountroot will
* need to find the root and mount it.
*/
}
#endif
++value;
/*
* value now points at the boot-file
*/
value_len = 0;
++value_len;
if (value_len > 0) {
/*
* strip leading path stuff from whoami, so running from
*/
}
/*
* Values forcibly set boot properties on the command line via -B.
* Allow use of quotes in values. Other stuff goes on kernel
* command line.
*/
while (*name != 0) {
/*
* anything not " -B" is copied to the command line
*/
boot_args[boot_arg_len] = 0;
++name;
continue;
}
/*
* skip the " -B" and following white space
*/
name += 3;
++name;
break;
++value;
value_len = 0;
quoted = 0;
for (; ; ++value_len) {
break;
/*
* is this value quoted?
*/
if (value_len == 0 &&
++value_len;
}
/*
* In the quote accept any character,
* but look for ending quote.
*/
if (quoted) {
quoted = 0;
continue;
}
/*
* a comma or white space ends the value
*/
break;
}
if (value_len == 0) {
} else {
char *v = value;
int l = value_len;
if (v[0] == v[l - 1] &&
(v[0] == '\'' || v[0] == '"')) {
++v;
l -= 2;
}
propbuf[l] = '\0';
l + 1);
}
while (*name == ',')
++name;
}
}
/*
* set boot-args property
* 1275 name is bootargs, so set
* that too
*/
#ifndef __xpv
/*
* set the BIOS boot device from GRUB
*/
netboot = 0;
/*
* Build boot command line for Fast Reboot
*/
/*
* Save various boot information for Fast Reboot
*/
if (boot_device == 0x20)
netboot++;
str[2] = 0;
} else {
netboot = 1;
}
/*
* In the netboot case, drives_info is overloaded with the dhcp ack.
* This is not multiboot compliant and requires special pxegrub!
*/
mbi->drives_length);
}
&stdout_val, sizeof (stdout_val));
#endif /* __xpv */
/*
* more conjured up values for made up things....
*/
#if defined(__xpv)
#else
#endif
/*
* Build firmware-provided system properties
*/
/*
* XXPV
*
* Find out what these are:
* - cpuid_feature_ecx_include
* - cpuid_feature_ecx_exclude
* - cpuid_feature_edx_include
* - cpuid_feature_edx_exclude
*
* Find out what these are in multiboot:
* - netdev-path
* - fstype
*/
}
#ifdef __xpv
/*
* Under the Hypervisor, memory usable for DMA may be scarce. One
* very likely large pool of DMA friendly memory is occupied by
* the boot_archive, as it was loaded by grub into low MFNs.
*
* Here we free up that memory by copying the boot archive to what are
*/
#define PFN_2GIG 0x80000
static void
relocate_boot_archive(void)
{
int slop;
int total = 0;
int relocated = 0;
int mmu_update_return;
mmu_update_t t[2];
/*
* If all MFN's are below 2Gig, don't bother doing this.
*/
return;
DBG_MSG("no boot_archive!");
return;
}
DBG_MSG("moving boot_archive to high MFN memory\n");
if (slop) {
}
/*
* Go through all boot_archive pages, swapping any low MFN pages
* with memory at next_phys.
*/
while (len != 0) {
++total;
bop_panic("relocate_boot_archive(): "
"HYPERVISOR_update_va_mapping() failed");
bop_panic("relocate_boot_archive(): "
"HYPERVISOR_mmu_update() failed");
++relocated;
}
len -= MMU_PAGESIZE;
va += MMU_PAGESIZE;
}
DBG_MSG("Relocated pages:\n");
DBG_MSG("Out of total pages:\n");
}
#endif /* __xpv */
#if !defined(__xpv)
/*
* Install a temporary IDT that lets us catch errors in the boot time code.
* We shouldn't get any faults at all while this is installed, so we'll
* just generate a traceback and exit.
*/
#ifdef __amd64
static const int bcode_sel = B64CODE_SEL;
#else
static const int bcode_sel = B32CODE_SEL;
#endif
/*
* simple description of a stack frame (args are 32 bit only currently)
*/
typedef struct bop_frame {
long arg[1];
} bop_frame_t;
void
{
int cnt;
int a;
char *ksym;
if (pc == 0)
break;
if (ksym)
else
if (frame == 0) {
break;
}
for (a = 0; a < 6; ++a) { /* try for 6 args */
#if defined(__i386)
break;
if (a == 0)
else
#endif
}
}
}
struct trapframe {
#ifdef __amd64
#endif
};
void
{
static int depth = 0;
/*
* Check for an infinite loop of traps.
*/
if (++depth > 2)
bop_panic("Nested trap");
/*
* adjust the tf for optional error_code by detecting the code selector
*/
#ifdef __amd64
#endif
bop_panic("unexpected trap in early boot");
}
extern void bop_trap_handler(void);
static gate_desc_t *bop_idt;
static desctbr_t bop_idt_info;
static void
bop_idt_init(void)
{
int t;
bop_idt = (gate_desc_t *)
for (t = 0; t < NIDT; ++t) {
/*
* Note that since boot runs without a TSS, the
* double fault handler cannot use an alternate stack
* (64-bit) or a task gate (32-bit).
*/
SDT_SYSIGT, TRP_KPL, 0);
}
}
#endif /* !defined(__xpv) */
/*
* This is where we enter the kernel. It dummies up the boot_ops and
* boot_syscalls vectors and jumps off to _kobj_boot()
*/
void
{
extern void _kobj_boot();
/*
* 1st off - initialize the console for any error messages
*/
#ifdef __xpv
#endif
have_console = 1;
#ifndef __xpv
post_fastreboot = 1;
}
#endif
/*
* enable debugging
*/
kbm_debug = 1;
DBG_MSG("\n\n*** Entered Solaris in _start() cmdline is: ");
DBG_MSG("\n\n\n");
/*
* physavail is no longer used by startup
*/
/*
* initialize the boot time allocator
*/
DBG_MSG("Initializing boot time memory management...");
#ifdef __xpv
{
/* This call shouldn't fail, dboot already did it once. */
(void) HYPERVISOR_xen_version(XENVER_platform_parameters, &p);
}
#endif
DBG_MSG("done\n");
/*
* Fill in the bootops vector
*/
/*
* BOP_EALLOC() is no longer needed
*/
#ifdef __xpv
/*
* On domain 0 we need to free up some physical memory that is
* usable for DMA. Since GRUB loaded the boot_archive, it is
* sitting in low MFN memory. We'll relocated the boot archive
* pages to high PFN memory.
*/
if (DOMAIN_IS_INITDOMAIN(xen_info))
#endif
#ifndef __xpv
/*
* Install an IDT to catch early pagefaults (shouldn't have any).
* Also needed for kmdb.
*/
bop_idt_init();
#endif
/*
* Start building the boot properties from the command line
*/
DBG_MSG("Initializing boot properties:\n");
char *name;
char *value;
char *cp;
int len;
name = "";
else
}
}
}
/*
* jump into krtld...
*/
}
/*ARGSUSED*/
static caddr_t
{
panic("Attempt to bsys_alloc() too late\n");
return (NULL);
}
/*ARGSUSED*/
static void
{
panic("Attempt to bsys_free() too late\n");
}
void
bop_no_more_mem(void)
{
}
#ifndef __xpv
/*
* Set ACPI firmware properties
*/
static caddr_t
{
}
static uint8_t
{
while (len-- > 0)
return (sum);
}
static int
{
/* validate the V1.x checksum */
return (0);
/* If pre-ACPI 2.0, this is a valid RSDP */
return (1);
/* validate the V2.x checksum */
return (0);
return (1);
}
/*
* Scan memory range for an RSDP;
* see ACPI 3.0 Spec, 5.2.5.1
*/
static struct rsdp *
{
while (len > 0) {
ptr += 16;
len -= 16;
}
return (NULL);
}
/*
* Refer to ACPI 3.0 Spec, section 5.2.5.1 to understand this function
*/
static struct rsdp *
find_rsdp() {
/*
* Get the EBDA segment and scan the first 1K
*/
/* if EBDA doesn't contain RSDP, look in BIOS memory */
return (rsdp);
}
static struct table_header *
{
struct table_header *tp;
/*
* Map at least a page; if the table is larger than this, remap it
*/
return (tp);
}
static struct table_header *
find_fw_table(char *signature)
{
static int revision = 0;
static int len;
struct table_header *tp;
int n;
return (NULL);
/*
* Reading the ACPI 3.0 Spec, section 5.2.5.3 will help
* revision will be 0. Find the RSDP and check the revision
* to find out whether to use the RSDT or XSDT. If revision is
* 0 or 1, use the RSDT and set internal revision to 1; if it is 2,
* use the XSDT. If the XSDT address is 0, though, fall back to
* revision 1 and use the RSDT.
*/
if (revision == 0) {
switch (revision) {
case 2:
/*
* Use the XSDT unless BIOS is buggy and
* claims to be rev 2 but has a null XSDT
* address
*/
if (xsdt_addr != 0)
break;
/* FALLTHROUGH */
case 0:
/* treat RSDP rev 0 as revision 1 internally */
revision = 1;
/* FALLTHROUGH */
case 1:
/* use the RSDT for rev 0/1 */
break;
default:
/* unknown revision */
revision = 0;
break;
}
}
if (revision == 0)
return (NULL);
/* cache the XSDT info */
}
/*
* Scan the table headers looking for a signature match
*/
for (n = 0; n < len; n++) {
if (table_addr == 0)
continue;
return (tp);
}
}
return (NULL);
}
static void
{
/*
* Determine number of CPUs and keep track of "final" APIC ID
* for each CPU by walking through ACPI MADT processor list
*/
cpu_count++;
}
}
cpu = (struct madt_processor *)
}
/*
* Make boot property for array of "final" APIC IDs for each
* CPU
*/
}
/*
* User-set boot-ncpus overrides firmware count
*/
return;
/*
* Set boot property for boot-ncpus to number of CPUs given in MADT
* if user hasn't set the property already
*/
}
static void
{
int i;
#pragma pack(1)
struct {
} processor;
struct {
} x2apic;
struct {
} memory;
#pragma pack()
char prop_name[30];
return;
case SRAT_PROCESSOR:
break;
for (i = 0; i < 3; i++)
proc_num);
sizeof (processor));
proc_num++;
break;
case SRAT_MEMORY:
break;
mem_num);
sizeof (memory));
mem_num++;
break;
case SRAT_X2APIC:
break;
proc_num);
sizeof (x2apic));
proc_num++;
break;
}
}
}
static void
{
/*
* Check the number of localities; if it's too huge, we just
* return and locality enumeration code will handle this later,
* if possible.
*
* Note that the size of the table is the square of the
* number of localities; if the number of localities exceeds
* UINT16_MAX, the table size may overflow an int when being
* passed to bsetprop() below.
*/
return;
}
static void
{
}
#else /* __xpv */
static void
{
/*
* User-set boot-ncpus overrides enumeration
*/
return;
/*
* Probe every possible virtual CPU id and remember the
* highest id present; the count of CPUs is one greater
* than this. This tacitly assumes at least cpu 0 is present.
*/
max_id = 0;
}
#endif /* __xpv */
static void
{
#ifndef __xpv
struct table_header *tp;
#else /* __xpv */
#endif /* __xpv */
}
/*
* fake up a boot property for deferred early console output
* this is used by both graphical boot and the (developer only)
* USB serial console
*/
void *
{
static char *p = NULL;
*p = 0;
&p, sizeof (p));
return (p);
}
/*ARGSUSED*/
int
{
return (0);
}
#define BP_MAX_STRLEN 32
/*
* Get value for given boot property
*/
int
{
int boot_prop_len;
char str[BP_MAX_STRLEN];
return (-1);
if (prop_value)
*prop_value = value;
return (0);
}