Add SMBIOS support.
A new option, -U, can be used to set the UUID in the System Information (Type 1) structure. Manpage fix to follow. Approved by: grehan (co-mentor)
This commit is contained in:
parent
e6a37eded4
commit
af5bfc53b8
@ -34,6 +34,7 @@ SRCS= \
|
||||
pmtmr.c \
|
||||
post.c \
|
||||
rtc.c \
|
||||
smbiostbl.c \
|
||||
uart_emul.c \
|
||||
virtio.c \
|
||||
xmsr.c \
|
||||
|
@ -39,14 +39,14 @@
|
||||
*
|
||||
* Layout
|
||||
* ------
|
||||
* RSDP -> 0xf0400 (36 bytes fixed)
|
||||
* RSDT -> 0xf0440 (36 bytes + 4*N table addrs, 2 used)
|
||||
* XSDT -> 0xf0480 (36 bytes + 8*N table addrs, 2 used)
|
||||
* MADT -> 0xf0500 (depends on #CPUs)
|
||||
* FADT -> 0xf0600 (268 bytes)
|
||||
* HPET -> 0xf0740 (56 bytes)
|
||||
* FACS -> 0xf0780 (64 bytes)
|
||||
* DSDT -> 0xf0800 (variable - can go up to 0x100000)
|
||||
* RSDP -> 0xf2400 (36 bytes fixed)
|
||||
* RSDT -> 0xf2440 (36 bytes + 4*N table addrs, 2 used)
|
||||
* XSDT -> 0xf2480 (36 bytes + 8*N table addrs, 2 used)
|
||||
* MADT -> 0xf2500 (depends on #CPUs)
|
||||
* FADT -> 0xf2600 (268 bytes)
|
||||
* HPET -> 0xf2740 (56 bytes)
|
||||
* FACS -> 0xf2780 (64 bytes)
|
||||
* DSDT -> 0xf2800 (variable - can go up to 0x100000)
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
@ -74,7 +74,7 @@ __FBSDID("$FreeBSD$");
|
||||
* Define the base address of the ACPI tables, and the offsets to
|
||||
* the individual tables
|
||||
*/
|
||||
#define BHYVE_ACPI_BASE 0xf0400
|
||||
#define BHYVE_ACPI_BASE 0xf2400
|
||||
#define RSDT_OFFSET 0x040
|
||||
#define XSDT_OFFSET 0x080
|
||||
#define MADT_OFFSET 0x100
|
||||
|
@ -61,6 +61,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include "mptbl.h"
|
||||
#include "pci_emul.h"
|
||||
#include "pci_lpc.h"
|
||||
#include "smbiostbl.h"
|
||||
#include "xmsr.h"
|
||||
#include "spinup_ap.h"
|
||||
#include "rtc.h"
|
||||
@ -82,6 +83,7 @@ typedef int (*vmexit_handler_t)(struct vmctx *, struct vm_exit *, int *vcpu);
|
||||
char *vmname;
|
||||
|
||||
int guest_ncpus;
|
||||
char *guest_uuid_str;
|
||||
|
||||
static int pincpu = -1;
|
||||
static int guest_vmexit_on_hlt, guest_vmexit_on_pause;
|
||||
@ -141,7 +143,8 @@ usage(int code)
|
||||
" -l: LPC device configuration\n"
|
||||
" -m: memory size in MB\n"
|
||||
" -w: ignore unimplemented MSRs\n"
|
||||
" -x: local apic is in x2APIC mode\n",
|
||||
" -x: local apic is in x2APIC mode\n"
|
||||
" -U: uuid\n",
|
||||
progname, (int)strlen(progname), "");
|
||||
|
||||
exit(code);
|
||||
@ -599,7 +602,7 @@ main(int argc, char *argv[])
|
||||
guest_ncpus = 1;
|
||||
memsize = 256 * MB;
|
||||
|
||||
while ((c = getopt(argc, argv, "abehwxAHIPWp:g:c:s:m:l:")) != -1) {
|
||||
while ((c = getopt(argc, argv, "abehwxAHIPWp:g:c:s:m:l:U:")) != -1) {
|
||||
switch (c) {
|
||||
case 'a':
|
||||
x2apic_mode = 0;
|
||||
@ -653,6 +656,9 @@ main(int argc, char *argv[])
|
||||
case 'e':
|
||||
strictio = 1;
|
||||
break;
|
||||
case 'U':
|
||||
guest_uuid_str = optarg;
|
||||
break;
|
||||
case 'w':
|
||||
strictmsr = 0;
|
||||
break;
|
||||
@ -723,6 +729,9 @@ main(int argc, char *argv[])
|
||||
*/
|
||||
mptable_build(ctx, guest_ncpus);
|
||||
|
||||
error = smbios_build(ctx);
|
||||
assert(error == 0);
|
||||
|
||||
if (acpi) {
|
||||
error = acpi_build(ctx, guest_ncpus);
|
||||
assert(error == 0);
|
||||
|
@ -37,6 +37,7 @@
|
||||
|
||||
struct vmctx;
|
||||
extern int guest_ncpus;
|
||||
extern char *guest_uuid_str;
|
||||
extern char *vmname;
|
||||
|
||||
void *paddr_guest2host(struct vmctx *ctx, uintptr_t addr, size_t len);
|
||||
|
832
usr.sbin/bhyve/smbiostbl.c
Normal file
832
usr.sbin/bhyve/smbiostbl.c
Normal file
@ -0,0 +1,832 @@
|
||||
/*-
|
||||
* Copyright (c) 2014 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <sys/param.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <errno.h>
|
||||
#include <md5.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <uuid.h>
|
||||
|
||||
#include <machine/vmm.h>
|
||||
#include <vmmapi.h>
|
||||
|
||||
#include "bhyverun.h"
|
||||
#include "smbiostbl.h"
|
||||
|
||||
#define MB (1024*1024)
|
||||
#define GB (1024ULL*1024*1024)
|
||||
|
||||
#define SMBIOS_BASE 0xF1000
|
||||
|
||||
/* BHYVE_ACPI_BASE - SMBIOS_BASE) */
|
||||
#define SMBIOS_MAX_LENGTH (0xF2400 - 0xF1000)
|
||||
|
||||
#define SMBIOS_TYPE_BIOS 0
|
||||
#define SMBIOS_TYPE_SYSTEM 1
|
||||
#define SMBIOS_TYPE_CHASSIS 3
|
||||
#define SMBIOS_TYPE_PROCESSOR 4
|
||||
#define SMBIOS_TYPE_MEMARRAY 16
|
||||
#define SMBIOS_TYPE_MEMDEVICE 17
|
||||
#define SMBIOS_TYPE_MEMARRAYMAP 19
|
||||
#define SMBIOS_TYPE_BOOT 32
|
||||
#define SMBIOS_TYPE_EOT 127
|
||||
|
||||
struct smbios_structure {
|
||||
uint8_t type;
|
||||
uint8_t length;
|
||||
uint16_t handle;
|
||||
} __packed;
|
||||
|
||||
typedef int (*initializer_func_t)(struct smbios_structure *template_entry,
|
||||
const char **template_strings, char *curaddr, char **endaddr,
|
||||
uint16_t *n, uint16_t *size);
|
||||
|
||||
struct smbios_template_entry {
|
||||
struct smbios_structure *entry;
|
||||
const char **strings;
|
||||
initializer_func_t initializer;
|
||||
};
|
||||
|
||||
/*
|
||||
* SMBIOS Structure Table Entry Point
|
||||
*/
|
||||
#define SMBIOS_ENTRY_EANCHOR "_SM_"
|
||||
#define SMBIOS_ENTRY_EANCHORLEN 4
|
||||
#define SMBIOS_ENTRY_IANCHOR "_DMI_"
|
||||
#define SMBIOS_ENTRY_IANCHORLEN 5
|
||||
|
||||
struct smbios_entry_point {
|
||||
char eanchor[4]; /* anchor tag */
|
||||
uint8_t echecksum; /* checksum of entry point structure */
|
||||
uint8_t eplen; /* length in bytes of entry point */
|
||||
uint8_t major; /* major version of the SMBIOS spec */
|
||||
uint8_t minor; /* minor version of the SMBIOS spec */
|
||||
uint16_t maxssize; /* maximum size in bytes of a struct */
|
||||
uint8_t revision; /* entry point structure revision */
|
||||
uint8_t format[5]; /* entry point rev-specific data */
|
||||
char ianchor[5]; /* intermediate anchor tag */
|
||||
uint8_t ichecksum; /* intermediate checksum */
|
||||
uint16_t stlen; /* len in bytes of structure table */
|
||||
uint32_t staddr; /* physical addr of structure table */
|
||||
uint16_t stnum; /* number of structure table entries */
|
||||
uint8_t bcdrev; /* BCD value representing DMI ver */
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* BIOS Information
|
||||
*/
|
||||
#define SMBIOS_FL_ISA 0x00000010 /* ISA is supported */
|
||||
#define SMBIOS_FL_PCI 0x00000080 /* PCI is supported */
|
||||
#define SMBIOS_FL_SHADOW 0x00001000 /* BIOS shadowing is allowed */
|
||||
#define SMBIOS_FL_CDBOOT 0x00008000 /* Boot from CD is supported */
|
||||
#define SMBIOS_FL_SELBOOT 0x00010000 /* Selectable Boot supported */
|
||||
#define SMBIOS_FL_EDD 0x00080000 /* EDD Spec is supported */
|
||||
|
||||
#define SMBIOS_XB1_FL_ACPI 0x00000001 /* ACPI is supported */
|
||||
|
||||
#define SMBIOS_XB2_FL_BBS 0x00000001 /* BIOS Boot Specification */
|
||||
#define SMBIOS_XB2_FL_VM 0x00000010 /* Virtual Machine */
|
||||
|
||||
struct smbios_table_type0 {
|
||||
struct smbios_structure header;
|
||||
uint8_t vendor; /* vendor string */
|
||||
uint8_t version; /* version string */
|
||||
uint16_t segment; /* address segment location */
|
||||
uint8_t rel_date; /* release date */
|
||||
uint8_t size; /* rom size */
|
||||
uint64_t cflags; /* characteristics */
|
||||
uint8_t xc_bytes[2]; /* characteristics ext bytes */
|
||||
uint8_t sb_major_rel; /* system bios version */
|
||||
uint8_t sb_minor_rele;
|
||||
uint8_t ecfw_major_rel; /* embedded ctrl fw version */
|
||||
uint8_t ecfw_minor_rel;
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* System Information
|
||||
*/
|
||||
#define SMBIOS_WAKEUP_SWITCH 0x06 /* power switch */
|
||||
|
||||
struct smbios_table_type1 {
|
||||
struct smbios_structure header;
|
||||
uint8_t manufacturer; /* manufacturer string */
|
||||
uint8_t product; /* product name string */
|
||||
uint8_t version; /* version string */
|
||||
uint8_t serial; /* serial number string */
|
||||
uint8_t uuid[16]; /* uuid byte array */
|
||||
uint8_t wakeup; /* wake-up event */
|
||||
uint8_t sku; /* sku number string */
|
||||
uint8_t family; /* family name string */
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* System Enclosure or Chassis
|
||||
*/
|
||||
#define SMBIOS_CHT_UNKNOWN 0x02 /* unknown */
|
||||
|
||||
#define SMBIOS_CHST_SAFE 0x03 /* safe */
|
||||
|
||||
#define SMBIOS_CHSC_NONE 0x03 /* none */
|
||||
|
||||
struct smbios_table_type3 {
|
||||
struct smbios_structure header;
|
||||
uint8_t manufacturer; /* manufacturer string */
|
||||
uint8_t type; /* type */
|
||||
uint8_t version; /* version string */
|
||||
uint8_t serial; /* serial number string */
|
||||
uint8_t asset; /* asset tag string */
|
||||
uint8_t bustate; /* boot-up state */
|
||||
uint8_t psstate; /* power supply state */
|
||||
uint8_t tstate; /* thermal state */
|
||||
uint8_t security; /* security status */
|
||||
uint8_t uheight; /* height in 'u's */
|
||||
uint8_t cords; /* number of power cords */
|
||||
uint8_t elems; /* number of element records */
|
||||
uint8_t elemlen; /* length of records */
|
||||
uint8_t sku; /* sku number string */
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* Processor Information
|
||||
*/
|
||||
#define SMBIOS_PRT_CENTRAL 0x03 /* central processor */
|
||||
|
||||
#define SMBIOS_PRF_OTHER 0x01 /* other */
|
||||
|
||||
#define SMBIOS_PRS_PRESENT 0x40 /* socket is populated */
|
||||
#define SMBIOS_PRS_ENABLED 0x1 /* enabled */
|
||||
|
||||
#define SMBIOS_PRU_NONE 0x06 /* none */
|
||||
|
||||
#define SMBIOS_PFL_64B 0x04 /* 64-bit capable */
|
||||
|
||||
struct smbios_table_type4 {
|
||||
struct smbios_structure header;
|
||||
uint8_t socket; /* socket designation string */
|
||||
uint8_t type; /* processor type */
|
||||
uint8_t family; /* processor family */
|
||||
uint8_t manufacturer; /* manufacturer string */
|
||||
uint64_t cpuid; /* processor cpuid */
|
||||
uint8_t version; /* version string */
|
||||
uint8_t voltage; /* voltage */
|
||||
uint16_t clkspeed; /* ext clock speed in mhz */
|
||||
uint16_t maxspeed; /* maximum speed in mhz */
|
||||
uint16_t curspeed; /* current speed in mhz */
|
||||
uint8_t status; /* status */
|
||||
uint8_t upgrade; /* upgrade */
|
||||
uint16_t l1handle; /* l1 cache handle */
|
||||
uint16_t l2handle; /* l2 cache handle */
|
||||
uint16_t l3handle; /* l3 cache handle */
|
||||
uint8_t serial; /* serial number string */
|
||||
uint8_t asset; /* asset tag string */
|
||||
uint8_t part; /* part number string */
|
||||
uint8_t cores; /* cores per socket */
|
||||
uint8_t ecores; /* enabled cores */
|
||||
uint8_t threads; /* threads per socket */
|
||||
uint16_t cflags; /* processor characteristics */
|
||||
uint16_t family2; /* processor family 2 */
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* Physical Memory Array
|
||||
*/
|
||||
#define SMBIOS_MAL_SYSMB 0x03 /* system board or motherboard */
|
||||
|
||||
#define SMBIOS_MAU_SYSTEM 0x03 /* system memory */
|
||||
|
||||
#define SMBIOS_MAE_NONE 0x03 /* none */
|
||||
|
||||
struct smbios_table_type16 {
|
||||
struct smbios_structure header;
|
||||
uint8_t location; /* physical device location */
|
||||
uint8_t use; /* device functional purpose */
|
||||
uint8_t ecc; /* err detect/correct method */
|
||||
uint32_t size; /* max mem capacity in kb */
|
||||
uint16_t errhand; /* handle of error (if any) */
|
||||
uint16_t ndevs; /* num of slots or sockets */
|
||||
uint64_t xsize; /* max mem capacity in bytes */
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* Memory Device
|
||||
*/
|
||||
#define SMBIOS_MDFF_UNKNOWN 0x02 /* unknown */
|
||||
|
||||
#define SMBIOS_MDT_UNKNOWN 0x02 /* unknown */
|
||||
|
||||
#define SMBIOS_MDF_UNKNOWN 0x0004 /* unknown */
|
||||
|
||||
struct smbios_table_type17 {
|
||||
struct smbios_structure header;
|
||||
uint16_t arrayhand; /* handle of physl mem array */
|
||||
uint16_t errhand; /* handle of mem error data */
|
||||
uint16_t twidth; /* total width in bits */
|
||||
uint16_t dwidth; /* data width in bits */
|
||||
uint16_t size; /* size in bytes */
|
||||
uint8_t form; /* form factor */
|
||||
uint8_t set; /* set */
|
||||
uint8_t dloc; /* device locator string */
|
||||
uint8_t bloc; /* phys bank locator string */
|
||||
uint8_t type; /* memory type */
|
||||
uint16_t flags; /* memory characteristics */
|
||||
uint16_t maxspeed; /* maximum speed in mhz */
|
||||
uint8_t manufacturer; /* manufacturer string */
|
||||
uint8_t serial; /* serial number string */
|
||||
uint8_t asset; /* asset tag string */
|
||||
uint8_t part; /* part number string */
|
||||
uint8_t attributes; /* attributes */
|
||||
uint32_t xsize; /* extended size in mbs */
|
||||
uint16_t curspeed; /* current speed in mhz */
|
||||
uint16_t minvoltage; /* minimum voltage */
|
||||
uint16_t maxvoltage; /* maximum voltage */
|
||||
uint16_t curvoltage; /* configured voltage */
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* Memory Array Mapped Address
|
||||
*/
|
||||
struct smbios_table_type19 {
|
||||
struct smbios_structure header;
|
||||
uint32_t saddr; /* start phys addr in kb */
|
||||
uint32_t eaddr; /* end phys addr in kb */
|
||||
uint16_t arrayhand; /* physical mem array handle */
|
||||
uint8_t width; /* num of dev in row */
|
||||
uint64_t xsaddr; /* start phys addr in bytes */
|
||||
uint64_t xeaddr; /* end phys addr in bytes */
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* System Boot Information
|
||||
*/
|
||||
#define SMBIOS_BOOT_NORMAL 0 /* no errors detected */
|
||||
|
||||
struct smbios_table_type32 {
|
||||
struct smbios_structure header;
|
||||
uint8_t reserved[6];
|
||||
uint8_t status; /* boot status */
|
||||
} __packed;
|
||||
|
||||
/*
|
||||
* End-of-Table
|
||||
*/
|
||||
struct smbios_table_type127 {
|
||||
struct smbios_structure header;
|
||||
} __packed;
|
||||
|
||||
struct smbios_table_type0 smbios_type0_template = {
|
||||
{ SMBIOS_TYPE_BIOS, sizeof (struct smbios_table_type0), 0 },
|
||||
1, /* bios vendor string */
|
||||
2, /* bios version string */
|
||||
0xF000, /* bios address segment location */
|
||||
3, /* bios release date */
|
||||
0x0, /* bios size (64k * (n + 1) is the size in bytes) */
|
||||
SMBIOS_FL_ISA | SMBIOS_FL_PCI | SMBIOS_FL_SHADOW |
|
||||
SMBIOS_FL_CDBOOT | SMBIOS_FL_EDD,
|
||||
{ SMBIOS_XB1_FL_ACPI, SMBIOS_XB2_FL_BBS | SMBIOS_XB2_FL_VM },
|
||||
0x0, /* bios major release */
|
||||
0x0, /* bios minor release */
|
||||
0xff, /* embedded controller firmware major release */
|
||||
0xff /* embedded controller firmware minor release */
|
||||
};
|
||||
|
||||
const char *smbios_type0_strings[] = {
|
||||
"BHYVE", /* vendor string */
|
||||
__TIME__, /* bios version string */
|
||||
__DATE__, /* bios release date string */
|
||||
NULL
|
||||
};
|
||||
|
||||
struct smbios_table_type1 smbios_type1_template = {
|
||||
{ SMBIOS_TYPE_SYSTEM, sizeof (struct smbios_table_type1), 0 },
|
||||
1, /* manufacturer string */
|
||||
2, /* product string */
|
||||
3, /* version string */
|
||||
4, /* serial number string */
|
||||
{ 0 },
|
||||
SMBIOS_WAKEUP_SWITCH,
|
||||
5, /* sku string */
|
||||
6 /* family string */
|
||||
};
|
||||
|
||||
static int smbios_type1_initializer(struct smbios_structure *template_entry,
|
||||
const char **template_strings, char *curaddr, char **endaddr,
|
||||
uint16_t *n, uint16_t *size);
|
||||
|
||||
const char *smbios_type1_strings[] = {
|
||||
" ", /* manufacturer string */
|
||||
"BHYVE", /* product name string */
|
||||
"1.0", /* version string */
|
||||
"None", /* serial number string */
|
||||
"None", /* sku string */
|
||||
" ", /* family name string */
|
||||
NULL
|
||||
};
|
||||
|
||||
struct smbios_table_type3 smbios_type3_template = {
|
||||
{ SMBIOS_TYPE_CHASSIS, sizeof (struct smbios_table_type3), 0 },
|
||||
1, /* manufacturer string */
|
||||
SMBIOS_CHT_UNKNOWN,
|
||||
2, /* version string */
|
||||
3, /* serial number string */
|
||||
4, /* asset tag string */
|
||||
SMBIOS_CHST_SAFE,
|
||||
SMBIOS_CHST_SAFE,
|
||||
SMBIOS_CHST_SAFE,
|
||||
SMBIOS_CHSC_NONE,
|
||||
0, /* height in 'u's (0=enclosure height unspecified) */
|
||||
0, /* number of power cords (0=number unspecified) */
|
||||
0, /* number of contained element records */
|
||||
0, /* length of records */
|
||||
5 /* sku number string */
|
||||
};
|
||||
|
||||
const char *smbios_type3_strings[] = {
|
||||
" ", /* manufacturer string */
|
||||
"1.0", /* version string */
|
||||
"None", /* serial number string */
|
||||
"None", /* asset tag string */
|
||||
"None", /* sku number string */
|
||||
NULL
|
||||
};
|
||||
|
||||
struct smbios_table_type4 smbios_type4_template = {
|
||||
{ SMBIOS_TYPE_PROCESSOR, sizeof (struct smbios_table_type4), 0 },
|
||||
1, /* socket designation string */
|
||||
SMBIOS_PRT_CENTRAL,
|
||||
SMBIOS_PRF_OTHER,
|
||||
2, /* manufacturer string */
|
||||
0, /* cpuid */
|
||||
3, /* version string */
|
||||
0, /* voltage */
|
||||
0, /* external clock frequency in mhz (0=unknown) */
|
||||
0, /* maximum frequency in mhz (0=unknown) */
|
||||
0, /* current frequency in mhz (0=unknown) */
|
||||
SMBIOS_PRS_PRESENT | SMBIOS_PRS_ENABLED,
|
||||
SMBIOS_PRU_NONE,
|
||||
-1, /* l1 cache handle */
|
||||
-1, /* l2 cache handle */
|
||||
-1, /* l3 cache handle */
|
||||
4, /* serial number string */
|
||||
5, /* asset tag string */
|
||||
6, /* part number string */
|
||||
0, /* cores per socket (0=unknown) */
|
||||
0, /* enabled cores per socket (0=unknown) */
|
||||
0, /* threads per socket (0=unknown) */
|
||||
SMBIOS_PFL_64B,
|
||||
SMBIOS_PRF_OTHER
|
||||
};
|
||||
|
||||
const char *smbios_type4_strings[] = {
|
||||
" ", /* socket designation string */
|
||||
" ", /* manufacturer string */
|
||||
" ", /* version string */
|
||||
"None", /* serial number string */
|
||||
"None", /* asset tag string */
|
||||
"None", /* part number string */
|
||||
NULL
|
||||
};
|
||||
|
||||
static int smbios_type4_initializer(struct smbios_structure *template_entry,
|
||||
const char **template_strings, char *curaddr, char **endaddr,
|
||||
uint16_t *n, uint16_t *size);
|
||||
|
||||
struct smbios_table_type16 smbios_type16_template = {
|
||||
{ SMBIOS_TYPE_MEMARRAY, sizeof (struct smbios_table_type16), 0 },
|
||||
SMBIOS_MAL_SYSMB,
|
||||
SMBIOS_MAU_SYSTEM,
|
||||
SMBIOS_MAE_NONE,
|
||||
0x80000000, /* max mem capacity in kb (0x80000000=use extended) */
|
||||
-1, /* handle of error (if any) */
|
||||
0, /* number of slots or sockets (TBD) */
|
||||
0 /* extended maximum memory capacity in bytes (TBD) */
|
||||
};
|
||||
|
||||
static int smbios_type16_initializer(struct smbios_structure *template_entry,
|
||||
const char **template_strings, char *curaddr, char **endaddr,
|
||||
uint16_t *n, uint16_t *size);
|
||||
|
||||
struct smbios_table_type17 smbios_type17_template = {
|
||||
{ SMBIOS_TYPE_MEMDEVICE, sizeof (struct smbios_table_type17), 0 },
|
||||
-1, /* handle of physical memory array */
|
||||
-1, /* handle of memory error data */
|
||||
64, /* total width in bits including ecc */
|
||||
64, /* data width in bits */
|
||||
0x7fff, /* size in bytes (0x7fff=use extended)*/
|
||||
SMBIOS_MDFF_UNKNOWN,
|
||||
0, /* set (0x00=none, 0xff=unknown) */
|
||||
1, /* device locator string */
|
||||
2, /* physical bank locator string */
|
||||
SMBIOS_MDT_UNKNOWN,
|
||||
SMBIOS_MDF_UNKNOWN,
|
||||
0, /* maximum memory speed in mhz (0=unknown) */
|
||||
3, /* manufacturer string */
|
||||
4, /* serial number string */
|
||||
5, /* asset tag string */
|
||||
6, /* part number string */
|
||||
0, /* attributes (0=unknown rank information) */
|
||||
0, /* extended size in mb (TBD) */
|
||||
0, /* current speed in mhz (0=unknown) */
|
||||
0, /* minimum voltage in mv (0=unknown) */
|
||||
0, /* maximum voltage in mv (0=unknown) */
|
||||
0 /* configured voltage in mv (0=unknown) */
|
||||
};
|
||||
|
||||
const char *smbios_type17_strings[] = {
|
||||
" ", /* device locator string */
|
||||
" ", /* physical bank locator string */
|
||||
" ", /* manufacturer string */
|
||||
"None", /* serial number string */
|
||||
"None", /* asset tag string */
|
||||
"None", /* part number string */
|
||||
NULL
|
||||
};
|
||||
|
||||
static int smbios_type17_initializer(struct smbios_structure *template_entry,
|
||||
const char **template_strings, char *curaddr, char **endaddr,
|
||||
uint16_t *n, uint16_t *size);
|
||||
|
||||
struct smbios_table_type19 smbios_type19_template = {
|
||||
{ SMBIOS_TYPE_MEMARRAYMAP, sizeof (struct smbios_table_type19), 0 },
|
||||
0xffffffff, /* starting phys addr in kb (0xffffffff=use ext) */
|
||||
0xffffffff, /* ending phys addr in kb (0xffffffff=use ext) */
|
||||
-1, /* physical memory array handle */
|
||||
1, /* number of devices that form a row */
|
||||
0, /* extended starting phys addr in bytes (TDB) */
|
||||
0 /* extended ending phys addr in bytes (TDB) */
|
||||
};
|
||||
|
||||
static int smbios_type19_initializer(struct smbios_structure *template_entry,
|
||||
const char **template_strings, char *curaddr, char **endaddr,
|
||||
uint16_t *n, uint16_t *size);
|
||||
|
||||
struct smbios_table_type32 smbios_type32_template = {
|
||||
{ SMBIOS_TYPE_BOOT, sizeof (struct smbios_table_type32), 0 },
|
||||
{ 0, 0, 0, 0, 0, 0 },
|
||||
SMBIOS_BOOT_NORMAL
|
||||
};
|
||||
|
||||
struct smbios_table_type127 smbios_type127_template = {
|
||||
{ SMBIOS_TYPE_EOT, sizeof (struct smbios_table_type127), 0 }
|
||||
};
|
||||
|
||||
static int smbios_generic_initializer(struct smbios_structure *template_entry,
|
||||
const char **template_strings, char *curaddr, char **endaddr,
|
||||
uint16_t *n, uint16_t *size);
|
||||
|
||||
static struct smbios_template_entry smbios_template[] = {
|
||||
{ (struct smbios_structure *)&smbios_type0_template,
|
||||
smbios_type0_strings,
|
||||
smbios_generic_initializer },
|
||||
{ (struct smbios_structure *)&smbios_type1_template,
|
||||
smbios_type1_strings,
|
||||
smbios_type1_initializer },
|
||||
{ (struct smbios_structure *)&smbios_type3_template,
|
||||
smbios_type3_strings,
|
||||
smbios_generic_initializer },
|
||||
{ (struct smbios_structure *)&smbios_type4_template,
|
||||
smbios_type4_strings,
|
||||
smbios_type4_initializer },
|
||||
{ (struct smbios_structure *)&smbios_type16_template,
|
||||
NULL,
|
||||
smbios_type16_initializer },
|
||||
{ (struct smbios_structure *)&smbios_type17_template,
|
||||
smbios_type17_strings,
|
||||
smbios_type17_initializer },
|
||||
{ (struct smbios_structure *)&smbios_type19_template,
|
||||
NULL,
|
||||
smbios_type19_initializer },
|
||||
{ (struct smbios_structure *)&smbios_type32_template,
|
||||
NULL,
|
||||
smbios_generic_initializer },
|
||||
{ (struct smbios_structure *)&smbios_type127_template,
|
||||
NULL,
|
||||
smbios_generic_initializer },
|
||||
{ NULL,NULL, NULL }
|
||||
};
|
||||
|
||||
static uint64_t guest_lomem, guest_himem;
|
||||
static uint16_t type16_handle;
|
||||
|
||||
static int
|
||||
smbios_generic_initializer(struct smbios_structure *template_entry,
|
||||
const char **template_strings, char *curaddr, char **endaddr,
|
||||
uint16_t *n, uint16_t *size)
|
||||
{
|
||||
struct smbios_structure *entry;
|
||||
|
||||
memcpy(curaddr, template_entry, template_entry->length);
|
||||
entry = (struct smbios_structure *)curaddr;
|
||||
entry->handle = *n + 1;
|
||||
curaddr += entry->length;
|
||||
if (template_strings != NULL) {
|
||||
int i;
|
||||
|
||||
for (i = 0; template_strings[i] != NULL; i++) {
|
||||
const char *string;
|
||||
int len;
|
||||
|
||||
string = template_strings[i];
|
||||
len = strlen(string) + 1;
|
||||
memcpy(curaddr, string, len);
|
||||
curaddr += len;
|
||||
}
|
||||
*curaddr = '\0';
|
||||
curaddr++;
|
||||
} else {
|
||||
/* Minimum string section is double nul */
|
||||
*curaddr = '\0';
|
||||
curaddr++;
|
||||
*curaddr = '\0';
|
||||
curaddr++;
|
||||
}
|
||||
(*n)++;
|
||||
*endaddr = curaddr;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
smbios_type1_initializer(struct smbios_structure *template_entry,
|
||||
const char **template_strings, char *curaddr, char **endaddr,
|
||||
uint16_t *n, uint16_t *size)
|
||||
{
|
||||
struct smbios_table_type1 *type1;
|
||||
|
||||
smbios_generic_initializer(template_entry, template_strings,
|
||||
curaddr, endaddr, n, size);
|
||||
type1 = (struct smbios_table_type1 *)curaddr;
|
||||
|
||||
if (guest_uuid_str != NULL) {
|
||||
uuid_t uuid;
|
||||
uint32_t status;
|
||||
|
||||
uuid_from_string(guest_uuid_str, &uuid, &status);
|
||||
if (status != uuid_s_ok)
|
||||
return (-1);
|
||||
|
||||
uuid_enc_le(&type1->uuid, &uuid);
|
||||
} else {
|
||||
MD5_CTX mdctx;
|
||||
u_char digest[16];
|
||||
char hostname[MAXHOSTNAMELEN];
|
||||
|
||||
/*
|
||||
* Universally unique and yet reproducible are an
|
||||
* oxymoron, however reproducible is desirable in
|
||||
* this case.
|
||||
*/
|
||||
if (gethostname(hostname, sizeof(hostname)))
|
||||
return (-1);
|
||||
|
||||
MD5Init(&mdctx);
|
||||
MD5Update(&mdctx, vmname, strlen(vmname));
|
||||
MD5Update(&mdctx, hostname, sizeof(hostname));
|
||||
MD5Final(digest, &mdctx);
|
||||
|
||||
/*
|
||||
* Set the variant and version number.
|
||||
*/
|
||||
digest[6] &= 0x0F;
|
||||
digest[6] |= 0x30; /* version 3 */
|
||||
digest[8] &= 0x3F;
|
||||
digest[8] |= 0x80;
|
||||
|
||||
memcpy(&type1->uuid, digest, sizeof (digest));
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
smbios_type4_initializer(struct smbios_structure *template_entry,
|
||||
const char **template_strings, char *curaddr, char **endaddr,
|
||||
uint16_t *n, uint16_t *size)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < guest_ncpus; i++) {
|
||||
struct smbios_table_type4 *type4;
|
||||
char *p;
|
||||
int nstrings, len;
|
||||
|
||||
smbios_generic_initializer(template_entry, template_strings,
|
||||
curaddr, endaddr, n, size);
|
||||
type4 = (struct smbios_table_type4 *)curaddr;
|
||||
p = curaddr + sizeof (struct smbios_table_type4);
|
||||
nstrings = 0;
|
||||
while (p < *endaddr - 1) {
|
||||
if (*p++ == '\0')
|
||||
nstrings++;
|
||||
}
|
||||
len = sprintf(*endaddr - 1, "CPU #%d", i) + 1;
|
||||
*endaddr += len - 1;
|
||||
*(*endaddr) = '\0';
|
||||
(*endaddr)++;
|
||||
type4->socket = nstrings + 1;
|
||||
curaddr = *endaddr;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
smbios_type16_initializer(struct smbios_structure *template_entry,
|
||||
const char **template_strings, char *curaddr, char **endaddr,
|
||||
uint16_t *n, uint16_t *size)
|
||||
{
|
||||
struct smbios_table_type16 *type16;
|
||||
|
||||
type16_handle = *n;
|
||||
smbios_generic_initializer(template_entry, template_strings,
|
||||
curaddr, endaddr, n, size);
|
||||
type16 = (struct smbios_table_type16 *)curaddr;
|
||||
type16->xsize = guest_lomem + guest_himem;
|
||||
type16->ndevs = guest_himem > 0 ? 2 : 1;
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
smbios_type17_initializer(struct smbios_structure *template_entry,
|
||||
const char **template_strings, char *curaddr, char **endaddr,
|
||||
uint16_t *n, uint16_t *size)
|
||||
{
|
||||
struct smbios_table_type17 *type17;
|
||||
|
||||
smbios_generic_initializer(template_entry, template_strings,
|
||||
curaddr, endaddr, n, size);
|
||||
type17 = (struct smbios_table_type17 *)curaddr;
|
||||
type17->arrayhand = type16_handle;
|
||||
type17->xsize = guest_lomem;
|
||||
|
||||
if (guest_himem > 0) {
|
||||
curaddr = *endaddr;
|
||||
smbios_generic_initializer(template_entry, template_strings,
|
||||
curaddr, endaddr, n, size);
|
||||
type17 = (struct smbios_table_type17 *)curaddr;
|
||||
type17->arrayhand = type16_handle;
|
||||
type17->xsize = guest_himem;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static int
|
||||
smbios_type19_initializer(struct smbios_structure *template_entry,
|
||||
const char **template_strings, char *curaddr, char **endaddr,
|
||||
uint16_t *n, uint16_t *size)
|
||||
{
|
||||
struct smbios_table_type19 *type19;
|
||||
|
||||
smbios_generic_initializer(template_entry, template_strings,
|
||||
curaddr, endaddr, n, size);
|
||||
type19 = (struct smbios_table_type19 *)curaddr;
|
||||
type19->arrayhand = type16_handle;
|
||||
type19->xsaddr = 0;
|
||||
type19->xeaddr = guest_lomem;
|
||||
|
||||
if (guest_himem > 0) {
|
||||
curaddr = *endaddr;
|
||||
smbios_generic_initializer(template_entry, template_strings,
|
||||
curaddr, endaddr, n, size);
|
||||
type19 = (struct smbios_table_type19 *)curaddr;
|
||||
type19->arrayhand = type16_handle;
|
||||
type19->xsaddr = 4*GB;
|
||||
type19->xeaddr = guest_himem;
|
||||
}
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
static void
|
||||
smbios_ep_initializer(struct smbios_entry_point *smbios_ep, uint32_t staddr)
|
||||
{
|
||||
memset(smbios_ep, 0, sizeof(*smbios_ep));
|
||||
memcpy(smbios_ep->eanchor, SMBIOS_ENTRY_EANCHOR,
|
||||
SMBIOS_ENTRY_EANCHORLEN);
|
||||
smbios_ep->eplen = 0x1F;
|
||||
assert(sizeof (struct smbios_entry_point) == smbios_ep->eplen);
|
||||
smbios_ep->major = 2;
|
||||
smbios_ep->minor = 4;
|
||||
smbios_ep->revision = 0;
|
||||
memcpy(smbios_ep->ianchor, SMBIOS_ENTRY_IANCHOR,
|
||||
SMBIOS_ENTRY_IANCHORLEN);
|
||||
smbios_ep->staddr = staddr;
|
||||
smbios_ep->bcdrev = 0x24;
|
||||
}
|
||||
|
||||
static void
|
||||
smbios_ep_finalizer(struct smbios_entry_point *smbios_ep, uint16_t len,
|
||||
uint16_t num, uint16_t maxssize)
|
||||
{
|
||||
uint8_t checksum;
|
||||
int i;
|
||||
|
||||
smbios_ep->maxssize = maxssize;
|
||||
smbios_ep->stlen = len;
|
||||
smbios_ep->stnum = num;
|
||||
|
||||
checksum = 0;
|
||||
for (i = 0x10; i < 0x1f; i++) {
|
||||
checksum -= ((uint8_t *)smbios_ep)[i];
|
||||
}
|
||||
smbios_ep->ichecksum = checksum;
|
||||
|
||||
checksum = 0;
|
||||
for (i = 0; i < 0x1f; i++) {
|
||||
checksum -= ((uint8_t *)smbios_ep)[i];
|
||||
}
|
||||
smbios_ep->echecksum = checksum;
|
||||
}
|
||||
|
||||
int
|
||||
smbios_build(struct vmctx *ctx)
|
||||
{
|
||||
struct smbios_entry_point *smbios_ep;
|
||||
uint16_t n;
|
||||
uint16_t maxssize;
|
||||
char *curaddr, *startaddr, *ststartaddr;
|
||||
int i;
|
||||
int err;
|
||||
|
||||
err = vm_get_memory_seg(ctx, 0, &guest_lomem, NULL);
|
||||
if (err != 0)
|
||||
return (err);
|
||||
|
||||
err = vm_get_memory_seg(ctx, 4*GB, &guest_himem, NULL);
|
||||
if (err != 0)
|
||||
return (err);
|
||||
|
||||
startaddr = paddr_guest2host(ctx, SMBIOS_BASE, SMBIOS_MAX_LENGTH);
|
||||
if (startaddr == NULL) {
|
||||
fprintf(stderr, "smbios table requires mapped mem\n");
|
||||
return (ENOMEM);
|
||||
}
|
||||
|
||||
curaddr = startaddr;
|
||||
|
||||
smbios_ep = (struct smbios_entry_point *)curaddr;
|
||||
smbios_ep_initializer(smbios_ep, SMBIOS_BASE +
|
||||
sizeof(struct smbios_entry_point));
|
||||
curaddr += sizeof(struct smbios_entry_point);
|
||||
ststartaddr = curaddr;
|
||||
|
||||
n = 0;
|
||||
maxssize = 0;
|
||||
for (i = 0; smbios_template[i].entry != NULL; i++) {
|
||||
struct smbios_structure *entry;
|
||||
const char **strings;
|
||||
initializer_func_t initializer;
|
||||
char *endaddr;
|
||||
uint16_t size;
|
||||
|
||||
entry = smbios_template[i].entry;
|
||||
strings = smbios_template[i].strings;
|
||||
initializer = smbios_template[i].initializer;
|
||||
|
||||
err = (*initializer)(entry, strings, curaddr, &endaddr,
|
||||
&n, &size);
|
||||
if (err != 0)
|
||||
return (err);
|
||||
|
||||
if (size > maxssize)
|
||||
maxssize = size;
|
||||
|
||||
curaddr = endaddr;
|
||||
}
|
||||
|
||||
assert(curaddr - startaddr < SMBIOS_MAX_LENGTH);
|
||||
smbios_ep_finalizer(smbios_ep, curaddr - ststartaddr, n, maxssize);
|
||||
|
||||
return (0);
|
||||
}
|
36
usr.sbin/bhyve/smbiostbl.h
Normal file
36
usr.sbin/bhyve/smbiostbl.h
Normal file
@ -0,0 +1,36 @@
|
||||
/*-
|
||||
* Copyright (c) 2014 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef _SMBIOSTBL_H_
|
||||
#define _SMBIOSTBL_H_
|
||||
|
||||
struct vmctx;
|
||||
|
||||
int smbios_build(struct vmctx *ctx);
|
||||
|
||||
#endif /* _SMBIOSTBL_H_ */
|
Loading…
Reference in New Issue
Block a user