1262744Stychon/*- 2330449Seadler * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3330449Seadler * 4262744Stychon * Copyright (c) 2014 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com> 5262744Stychon * All rights reserved. 6262744Stychon * 7262744Stychon * Redistribution and use in source and binary forms, with or without 8262744Stychon * modification, are permitted provided that the following conditions 9262744Stychon * are met: 10262744Stychon * 1. Redistributions of source code must retain the above copyright 11262744Stychon * notice, this list of conditions and the following disclaimer. 12262744Stychon * 2. Redistributions in binary form must reproduce the above copyright 13262744Stychon * notice, this list of conditions and the following disclaimer in the 14262744Stychon * documentation and/or other materials provided with the distribution. 15262744Stychon * 16262744Stychon * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 17262744Stychon * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18262744Stychon * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19262744Stychon * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20262744Stychon * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21262744Stychon * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22262744Stychon * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23262744Stychon * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24262744Stychon * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25262744Stychon * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26262744Stychon * SUCH DAMAGE. 27262744Stychon */ 28262744Stychon 29262744Stychon#include <sys/cdefs.h> 30262744Stychon__FBSDID("$FreeBSD: stable/11/usr.sbin/bhyve/smbiostbl.c 348269 2019-05-25 10:17:03Z rgrimes $"); 31262744Stychon 32262744Stychon#include <sys/param.h> 33262744Stychon 34262744Stychon#include <assert.h> 35262744Stychon#include <errno.h> 36262744Stychon#include <md5.h> 37262744Stychon#include <stdio.h> 38262744Stychon#include <string.h> 39262744Stychon#include <unistd.h> 40262744Stychon#include <uuid.h> 41262744Stychon 42262744Stychon#include <machine/vmm.h> 43262744Stychon#include <vmmapi.h> 44262744Stychon 45262744Stychon#include "bhyverun.h" 46262744Stychon#include "smbiostbl.h" 47262744Stychon 48262744Stychon#define MB (1024*1024) 49262744Stychon#define GB (1024ULL*1024*1024) 50262744Stychon 51262744Stychon#define SMBIOS_BASE 0xF1000 52262744Stychon 53262744Stychon/* BHYVE_ACPI_BASE - SMBIOS_BASE) */ 54262744Stychon#define SMBIOS_MAX_LENGTH (0xF2400 - 0xF1000) 55262744Stychon 56262744Stychon#define SMBIOS_TYPE_BIOS 0 57262744Stychon#define SMBIOS_TYPE_SYSTEM 1 58262744Stychon#define SMBIOS_TYPE_CHASSIS 3 59262744Stychon#define SMBIOS_TYPE_PROCESSOR 4 60262744Stychon#define SMBIOS_TYPE_MEMARRAY 16 61262744Stychon#define SMBIOS_TYPE_MEMDEVICE 17 62262744Stychon#define SMBIOS_TYPE_MEMARRAYMAP 19 63262744Stychon#define SMBIOS_TYPE_BOOT 32 64262744Stychon#define SMBIOS_TYPE_EOT 127 65262744Stychon 66262744Stychonstruct smbios_structure { 67262744Stychon uint8_t type; 68262744Stychon uint8_t length; 69262744Stychon uint16_t handle; 70262744Stychon} __packed; 71262744Stychon 72262744Stychontypedef int (*initializer_func_t)(struct smbios_structure *template_entry, 73262744Stychon const char **template_strings, char *curaddr, char **endaddr, 74262744Stychon uint16_t *n, uint16_t *size); 75262744Stychon 76262744Stychonstruct smbios_template_entry { 77262744Stychon struct smbios_structure *entry; 78262744Stychon const char **strings; 79262744Stychon initializer_func_t initializer; 80262744Stychon}; 81262744Stychon 82262744Stychon/* 83262744Stychon * SMBIOS Structure Table Entry Point 84262744Stychon */ 85262744Stychon#define SMBIOS_ENTRY_EANCHOR "_SM_" 86262744Stychon#define SMBIOS_ENTRY_EANCHORLEN 4 87262744Stychon#define SMBIOS_ENTRY_IANCHOR "_DMI_" 88262744Stychon#define SMBIOS_ENTRY_IANCHORLEN 5 89262744Stychon 90262744Stychonstruct smbios_entry_point { 91262744Stychon char eanchor[4]; /* anchor tag */ 92262744Stychon uint8_t echecksum; /* checksum of entry point structure */ 93262744Stychon uint8_t eplen; /* length in bytes of entry point */ 94262744Stychon uint8_t major; /* major version of the SMBIOS spec */ 95262744Stychon uint8_t minor; /* minor version of the SMBIOS spec */ 96262744Stychon uint16_t maxssize; /* maximum size in bytes of a struct */ 97262744Stychon uint8_t revision; /* entry point structure revision */ 98262744Stychon uint8_t format[5]; /* entry point rev-specific data */ 99262744Stychon char ianchor[5]; /* intermediate anchor tag */ 100262744Stychon uint8_t ichecksum; /* intermediate checksum */ 101262744Stychon uint16_t stlen; /* len in bytes of structure table */ 102262744Stychon uint32_t staddr; /* physical addr of structure table */ 103262744Stychon uint16_t stnum; /* number of structure table entries */ 104262744Stychon uint8_t bcdrev; /* BCD value representing DMI ver */ 105262744Stychon} __packed; 106262744Stychon 107262744Stychon/* 108262744Stychon * BIOS Information 109262744Stychon */ 110262744Stychon#define SMBIOS_FL_ISA 0x00000010 /* ISA is supported */ 111262744Stychon#define SMBIOS_FL_PCI 0x00000080 /* PCI is supported */ 112262744Stychon#define SMBIOS_FL_SHADOW 0x00001000 /* BIOS shadowing is allowed */ 113262744Stychon#define SMBIOS_FL_CDBOOT 0x00008000 /* Boot from CD is supported */ 114262744Stychon#define SMBIOS_FL_SELBOOT 0x00010000 /* Selectable Boot supported */ 115262744Stychon#define SMBIOS_FL_EDD 0x00080000 /* EDD Spec is supported */ 116262744Stychon 117262744Stychon#define SMBIOS_XB1_FL_ACPI 0x00000001 /* ACPI is supported */ 118262744Stychon 119262744Stychon#define SMBIOS_XB2_FL_BBS 0x00000001 /* BIOS Boot Specification */ 120262744Stychon#define SMBIOS_XB2_FL_VM 0x00000010 /* Virtual Machine */ 121262744Stychon 122262744Stychonstruct smbios_table_type0 { 123262744Stychon struct smbios_structure header; 124262744Stychon uint8_t vendor; /* vendor string */ 125262744Stychon uint8_t version; /* version string */ 126262744Stychon uint16_t segment; /* address segment location */ 127262744Stychon uint8_t rel_date; /* release date */ 128262744Stychon uint8_t size; /* rom size */ 129262744Stychon uint64_t cflags; /* characteristics */ 130262744Stychon uint8_t xc_bytes[2]; /* characteristics ext bytes */ 131262744Stychon uint8_t sb_major_rel; /* system bios version */ 132262744Stychon uint8_t sb_minor_rele; 133262744Stychon uint8_t ecfw_major_rel; /* embedded ctrl fw version */ 134262744Stychon uint8_t ecfw_minor_rel; 135262744Stychon} __packed; 136262744Stychon 137262744Stychon/* 138262744Stychon * System Information 139262744Stychon */ 140262744Stychon#define SMBIOS_WAKEUP_SWITCH 0x06 /* power switch */ 141262744Stychon 142262744Stychonstruct smbios_table_type1 { 143262744Stychon struct smbios_structure header; 144262744Stychon uint8_t manufacturer; /* manufacturer string */ 145262744Stychon uint8_t product; /* product name string */ 146262744Stychon uint8_t version; /* version string */ 147262744Stychon uint8_t serial; /* serial number string */ 148262744Stychon uint8_t uuid[16]; /* uuid byte array */ 149262744Stychon uint8_t wakeup; /* wake-up event */ 150262744Stychon uint8_t sku; /* sku number string */ 151262744Stychon uint8_t family; /* family name string */ 152262744Stychon} __packed; 153262744Stychon 154262744Stychon/* 155262744Stychon * System Enclosure or Chassis 156262744Stychon */ 157262744Stychon#define SMBIOS_CHT_UNKNOWN 0x02 /* unknown */ 158262744Stychon 159262744Stychon#define SMBIOS_CHST_SAFE 0x03 /* safe */ 160262744Stychon 161262744Stychon#define SMBIOS_CHSC_NONE 0x03 /* none */ 162262744Stychon 163262744Stychonstruct smbios_table_type3 { 164262744Stychon struct smbios_structure header; 165262744Stychon uint8_t manufacturer; /* manufacturer string */ 166262744Stychon uint8_t type; /* type */ 167262744Stychon uint8_t version; /* version string */ 168262744Stychon uint8_t serial; /* serial number string */ 169262744Stychon uint8_t asset; /* asset tag string */ 170262744Stychon uint8_t bustate; /* boot-up state */ 171262744Stychon uint8_t psstate; /* power supply state */ 172262744Stychon uint8_t tstate; /* thermal state */ 173262744Stychon uint8_t security; /* security status */ 174262744Stychon uint8_t uheight; /* height in 'u's */ 175262744Stychon uint8_t cords; /* number of power cords */ 176262744Stychon uint8_t elems; /* number of element records */ 177262744Stychon uint8_t elemlen; /* length of records */ 178262744Stychon uint8_t sku; /* sku number string */ 179262744Stychon} __packed; 180262744Stychon 181262744Stychon/* 182262744Stychon * Processor Information 183262744Stychon */ 184262744Stychon#define SMBIOS_PRT_CENTRAL 0x03 /* central processor */ 185262744Stychon 186262744Stychon#define SMBIOS_PRF_OTHER 0x01 /* other */ 187262744Stychon 188262744Stychon#define SMBIOS_PRS_PRESENT 0x40 /* socket is populated */ 189262744Stychon#define SMBIOS_PRS_ENABLED 0x1 /* enabled */ 190262744Stychon 191262744Stychon#define SMBIOS_PRU_NONE 0x06 /* none */ 192262744Stychon 193262744Stychon#define SMBIOS_PFL_64B 0x04 /* 64-bit capable */ 194262744Stychon 195262744Stychonstruct smbios_table_type4 { 196262744Stychon struct smbios_structure header; 197262744Stychon uint8_t socket; /* socket designation string */ 198262744Stychon uint8_t type; /* processor type */ 199262744Stychon uint8_t family; /* processor family */ 200262744Stychon uint8_t manufacturer; /* manufacturer string */ 201262744Stychon uint64_t cpuid; /* processor cpuid */ 202262744Stychon uint8_t version; /* version string */ 203262744Stychon uint8_t voltage; /* voltage */ 204262744Stychon uint16_t clkspeed; /* ext clock speed in mhz */ 205262744Stychon uint16_t maxspeed; /* maximum speed in mhz */ 206262744Stychon uint16_t curspeed; /* current speed in mhz */ 207262744Stychon uint8_t status; /* status */ 208262744Stychon uint8_t upgrade; /* upgrade */ 209262744Stychon uint16_t l1handle; /* l1 cache handle */ 210262744Stychon uint16_t l2handle; /* l2 cache handle */ 211262744Stychon uint16_t l3handle; /* l3 cache handle */ 212262744Stychon uint8_t serial; /* serial number string */ 213262744Stychon uint8_t asset; /* asset tag string */ 214262744Stychon uint8_t part; /* part number string */ 215262744Stychon uint8_t cores; /* cores per socket */ 216262744Stychon uint8_t ecores; /* enabled cores */ 217262744Stychon uint8_t threads; /* threads per socket */ 218262744Stychon uint16_t cflags; /* processor characteristics */ 219262744Stychon uint16_t family2; /* processor family 2 */ 220262744Stychon} __packed; 221262744Stychon 222262744Stychon/* 223262744Stychon * Physical Memory Array 224262744Stychon */ 225262744Stychon#define SMBIOS_MAL_SYSMB 0x03 /* system board or motherboard */ 226262744Stychon 227262744Stychon#define SMBIOS_MAU_SYSTEM 0x03 /* system memory */ 228262744Stychon 229262744Stychon#define SMBIOS_MAE_NONE 0x03 /* none */ 230262744Stychon 231262744Stychonstruct smbios_table_type16 { 232262744Stychon struct smbios_structure header; 233262744Stychon uint8_t location; /* physical device location */ 234262744Stychon uint8_t use; /* device functional purpose */ 235262744Stychon uint8_t ecc; /* err detect/correct method */ 236262744Stychon uint32_t size; /* max mem capacity in kb */ 237262744Stychon uint16_t errhand; /* handle of error (if any) */ 238262744Stychon uint16_t ndevs; /* num of slots or sockets */ 239262744Stychon uint64_t xsize; /* max mem capacity in bytes */ 240262744Stychon} __packed; 241262744Stychon 242262744Stychon/* 243262744Stychon * Memory Device 244262744Stychon */ 245262744Stychon#define SMBIOS_MDFF_UNKNOWN 0x02 /* unknown */ 246262744Stychon 247262744Stychon#define SMBIOS_MDT_UNKNOWN 0x02 /* unknown */ 248262744Stychon 249262744Stychon#define SMBIOS_MDF_UNKNOWN 0x0004 /* unknown */ 250262744Stychon 251262744Stychonstruct smbios_table_type17 { 252262744Stychon struct smbios_structure header; 253262744Stychon uint16_t arrayhand; /* handle of physl mem array */ 254262744Stychon uint16_t errhand; /* handle of mem error data */ 255262744Stychon uint16_t twidth; /* total width in bits */ 256262744Stychon uint16_t dwidth; /* data width in bits */ 257262744Stychon uint16_t size; /* size in bytes */ 258262744Stychon uint8_t form; /* form factor */ 259262744Stychon uint8_t set; /* set */ 260262744Stychon uint8_t dloc; /* device locator string */ 261262744Stychon uint8_t bloc; /* phys bank locator string */ 262262744Stychon uint8_t type; /* memory type */ 263262744Stychon uint16_t flags; /* memory characteristics */ 264262744Stychon uint16_t maxspeed; /* maximum speed in mhz */ 265262744Stychon uint8_t manufacturer; /* manufacturer string */ 266262744Stychon uint8_t serial; /* serial number string */ 267262744Stychon uint8_t asset; /* asset tag string */ 268262744Stychon uint8_t part; /* part number string */ 269262744Stychon uint8_t attributes; /* attributes */ 270262744Stychon uint32_t xsize; /* extended size in mbs */ 271262744Stychon uint16_t curspeed; /* current speed in mhz */ 272262744Stychon uint16_t minvoltage; /* minimum voltage */ 273262744Stychon uint16_t maxvoltage; /* maximum voltage */ 274262744Stychon uint16_t curvoltage; /* configured voltage */ 275262744Stychon} __packed; 276262744Stychon 277262744Stychon/* 278262744Stychon * Memory Array Mapped Address 279262744Stychon */ 280262744Stychonstruct smbios_table_type19 { 281262744Stychon struct smbios_structure header; 282262744Stychon uint32_t saddr; /* start phys addr in kb */ 283262744Stychon uint32_t eaddr; /* end phys addr in kb */ 284262744Stychon uint16_t arrayhand; /* physical mem array handle */ 285262744Stychon uint8_t width; /* num of dev in row */ 286262744Stychon uint64_t xsaddr; /* start phys addr in bytes */ 287262744Stychon uint64_t xeaddr; /* end phys addr in bytes */ 288262744Stychon} __packed; 289262744Stychon 290262744Stychon/* 291262744Stychon * System Boot Information 292262744Stychon */ 293262744Stychon#define SMBIOS_BOOT_NORMAL 0 /* no errors detected */ 294262744Stychon 295262744Stychonstruct smbios_table_type32 { 296262744Stychon struct smbios_structure header; 297262744Stychon uint8_t reserved[6]; 298262744Stychon uint8_t status; /* boot status */ 299262744Stychon} __packed; 300262744Stychon 301262744Stychon/* 302262744Stychon * End-of-Table 303262744Stychon */ 304262744Stychonstruct smbios_table_type127 { 305262744Stychon struct smbios_structure header; 306262744Stychon} __packed; 307262744Stychon 308262744Stychonstruct smbios_table_type0 smbios_type0_template = { 309262744Stychon { SMBIOS_TYPE_BIOS, sizeof (struct smbios_table_type0), 0 }, 310262744Stychon 1, /* bios vendor string */ 311262744Stychon 2, /* bios version string */ 312262744Stychon 0xF000, /* bios address segment location */ 313262744Stychon 3, /* bios release date */ 314262744Stychon 0x0, /* bios size (64k * (n + 1) is the size in bytes) */ 315262744Stychon SMBIOS_FL_ISA | SMBIOS_FL_PCI | SMBIOS_FL_SHADOW | 316262744Stychon SMBIOS_FL_CDBOOT | SMBIOS_FL_EDD, 317262744Stychon { SMBIOS_XB1_FL_ACPI, SMBIOS_XB2_FL_BBS | SMBIOS_XB2_FL_VM }, 318262744Stychon 0x0, /* bios major release */ 319262744Stychon 0x0, /* bios minor release */ 320262744Stychon 0xff, /* embedded controller firmware major release */ 321262744Stychon 0xff /* embedded controller firmware minor release */ 322262744Stychon}; 323262744Stychon 324262744Stychonconst char *smbios_type0_strings[] = { 325262744Stychon "BHYVE", /* vendor string */ 326267949Sgrehan "1.00", /* bios version string */ 327267949Sgrehan "03/14/2014", /* bios release date string */ 328262744Stychon NULL 329262744Stychon}; 330262744Stychon 331262744Stychonstruct smbios_table_type1 smbios_type1_template = { 332262744Stychon { SMBIOS_TYPE_SYSTEM, sizeof (struct smbios_table_type1), 0 }, 333262744Stychon 1, /* manufacturer string */ 334262744Stychon 2, /* product string */ 335262744Stychon 3, /* version string */ 336262744Stychon 4, /* serial number string */ 337262744Stychon { 0 }, 338262744Stychon SMBIOS_WAKEUP_SWITCH, 339262744Stychon 5, /* sku string */ 340262744Stychon 6 /* family string */ 341262744Stychon}; 342262744Stychon 343262744Stychonstatic int smbios_type1_initializer(struct smbios_structure *template_entry, 344262744Stychon const char **template_strings, char *curaddr, char **endaddr, 345262744Stychon uint16_t *n, uint16_t *size); 346262744Stychon 347262744Stychonconst char *smbios_type1_strings[] = { 348262744Stychon " ", /* manufacturer string */ 349262744Stychon "BHYVE", /* product name string */ 350262744Stychon "1.0", /* version string */ 351262744Stychon "None", /* serial number string */ 352262744Stychon "None", /* sku string */ 353262744Stychon " ", /* family name string */ 354262744Stychon NULL 355262744Stychon}; 356262744Stychon 357262744Stychonstruct smbios_table_type3 smbios_type3_template = { 358262744Stychon { SMBIOS_TYPE_CHASSIS, sizeof (struct smbios_table_type3), 0 }, 359262744Stychon 1, /* manufacturer string */ 360262744Stychon SMBIOS_CHT_UNKNOWN, 361262744Stychon 2, /* version string */ 362262744Stychon 3, /* serial number string */ 363262744Stychon 4, /* asset tag string */ 364262744Stychon SMBIOS_CHST_SAFE, 365262744Stychon SMBIOS_CHST_SAFE, 366262744Stychon SMBIOS_CHST_SAFE, 367262744Stychon SMBIOS_CHSC_NONE, 368262744Stychon 0, /* height in 'u's (0=enclosure height unspecified) */ 369262744Stychon 0, /* number of power cords (0=number unspecified) */ 370262744Stychon 0, /* number of contained element records */ 371262744Stychon 0, /* length of records */ 372262744Stychon 5 /* sku number string */ 373262744Stychon}; 374262744Stychon 375262744Stychonconst char *smbios_type3_strings[] = { 376262744Stychon " ", /* manufacturer string */ 377262744Stychon "1.0", /* version string */ 378262744Stychon "None", /* serial number string */ 379262744Stychon "None", /* asset tag string */ 380262744Stychon "None", /* sku number string */ 381262744Stychon NULL 382262744Stychon}; 383262744Stychon 384262744Stychonstruct smbios_table_type4 smbios_type4_template = { 385262744Stychon { SMBIOS_TYPE_PROCESSOR, sizeof (struct smbios_table_type4), 0 }, 386262744Stychon 1, /* socket designation string */ 387262744Stychon SMBIOS_PRT_CENTRAL, 388262744Stychon SMBIOS_PRF_OTHER, 389262744Stychon 2, /* manufacturer string */ 390262744Stychon 0, /* cpuid */ 391262744Stychon 3, /* version string */ 392262744Stychon 0, /* voltage */ 393262744Stychon 0, /* external clock frequency in mhz (0=unknown) */ 394262744Stychon 0, /* maximum frequency in mhz (0=unknown) */ 395262744Stychon 0, /* current frequency in mhz (0=unknown) */ 396262744Stychon SMBIOS_PRS_PRESENT | SMBIOS_PRS_ENABLED, 397262744Stychon SMBIOS_PRU_NONE, 398262744Stychon -1, /* l1 cache handle */ 399262744Stychon -1, /* l2 cache handle */ 400262744Stychon -1, /* l3 cache handle */ 401262744Stychon 4, /* serial number string */ 402262744Stychon 5, /* asset tag string */ 403262744Stychon 6, /* part number string */ 404262744Stychon 0, /* cores per socket (0=unknown) */ 405262744Stychon 0, /* enabled cores per socket (0=unknown) */ 406262744Stychon 0, /* threads per socket (0=unknown) */ 407262744Stychon SMBIOS_PFL_64B, 408262744Stychon SMBIOS_PRF_OTHER 409262744Stychon}; 410262744Stychon 411262744Stychonconst char *smbios_type4_strings[] = { 412262744Stychon " ", /* socket designation string */ 413262744Stychon " ", /* manufacturer string */ 414262744Stychon " ", /* version string */ 415262744Stychon "None", /* serial number string */ 416262744Stychon "None", /* asset tag string */ 417262744Stychon "None", /* part number string */ 418262744Stychon NULL 419262744Stychon}; 420262744Stychon 421262744Stychonstatic int smbios_type4_initializer(struct smbios_structure *template_entry, 422262744Stychon const char **template_strings, char *curaddr, char **endaddr, 423262744Stychon uint16_t *n, uint16_t *size); 424262744Stychon 425262744Stychonstruct smbios_table_type16 smbios_type16_template = { 426262744Stychon { SMBIOS_TYPE_MEMARRAY, sizeof (struct smbios_table_type16), 0 }, 427262744Stychon SMBIOS_MAL_SYSMB, 428262744Stychon SMBIOS_MAU_SYSTEM, 429262744Stychon SMBIOS_MAE_NONE, 430262744Stychon 0x80000000, /* max mem capacity in kb (0x80000000=use extended) */ 431262744Stychon -1, /* handle of error (if any) */ 432262744Stychon 0, /* number of slots or sockets (TBD) */ 433262744Stychon 0 /* extended maximum memory capacity in bytes (TBD) */ 434262744Stychon}; 435262744Stychon 436262744Stychonstatic int smbios_type16_initializer(struct smbios_structure *template_entry, 437262744Stychon const char **template_strings, char *curaddr, char **endaddr, 438262744Stychon uint16_t *n, uint16_t *size); 439262744Stychon 440262744Stychonstruct smbios_table_type17 smbios_type17_template = { 441262744Stychon { SMBIOS_TYPE_MEMDEVICE, sizeof (struct smbios_table_type17), 0 }, 442262744Stychon -1, /* handle of physical memory array */ 443262744Stychon -1, /* handle of memory error data */ 444262744Stychon 64, /* total width in bits including ecc */ 445262744Stychon 64, /* data width in bits */ 446262744Stychon 0x7fff, /* size in bytes (0x7fff=use extended)*/ 447262744Stychon SMBIOS_MDFF_UNKNOWN, 448262744Stychon 0, /* set (0x00=none, 0xff=unknown) */ 449262744Stychon 1, /* device locator string */ 450262744Stychon 2, /* physical bank locator string */ 451262744Stychon SMBIOS_MDT_UNKNOWN, 452262744Stychon SMBIOS_MDF_UNKNOWN, 453262744Stychon 0, /* maximum memory speed in mhz (0=unknown) */ 454262744Stychon 3, /* manufacturer string */ 455262744Stychon 4, /* serial number string */ 456262744Stychon 5, /* asset tag string */ 457262744Stychon 6, /* part number string */ 458262744Stychon 0, /* attributes (0=unknown rank information) */ 459262744Stychon 0, /* extended size in mb (TBD) */ 460262744Stychon 0, /* current speed in mhz (0=unknown) */ 461262744Stychon 0, /* minimum voltage in mv (0=unknown) */ 462262744Stychon 0, /* maximum voltage in mv (0=unknown) */ 463262744Stychon 0 /* configured voltage in mv (0=unknown) */ 464262744Stychon}; 465262744Stychon 466262744Stychonconst char *smbios_type17_strings[] = { 467262744Stychon " ", /* device locator string */ 468262744Stychon " ", /* physical bank locator string */ 469262744Stychon " ", /* manufacturer string */ 470262744Stychon "None", /* serial number string */ 471262744Stychon "None", /* asset tag string */ 472262744Stychon "None", /* part number string */ 473262744Stychon NULL 474262744Stychon}; 475262744Stychon 476262744Stychonstatic int smbios_type17_initializer(struct smbios_structure *template_entry, 477262744Stychon const char **template_strings, char *curaddr, char **endaddr, 478262744Stychon uint16_t *n, uint16_t *size); 479262744Stychon 480262744Stychonstruct smbios_table_type19 smbios_type19_template = { 481262744Stychon { SMBIOS_TYPE_MEMARRAYMAP, sizeof (struct smbios_table_type19), 0 }, 482262744Stychon 0xffffffff, /* starting phys addr in kb (0xffffffff=use ext) */ 483262744Stychon 0xffffffff, /* ending phys addr in kb (0xffffffff=use ext) */ 484262744Stychon -1, /* physical memory array handle */ 485262744Stychon 1, /* number of devices that form a row */ 486262744Stychon 0, /* extended starting phys addr in bytes (TDB) */ 487262744Stychon 0 /* extended ending phys addr in bytes (TDB) */ 488262744Stychon}; 489262744Stychon 490262744Stychonstatic int smbios_type19_initializer(struct smbios_structure *template_entry, 491262744Stychon const char **template_strings, char *curaddr, char **endaddr, 492262744Stychon uint16_t *n, uint16_t *size); 493262744Stychon 494262744Stychonstruct smbios_table_type32 smbios_type32_template = { 495262744Stychon { SMBIOS_TYPE_BOOT, sizeof (struct smbios_table_type32), 0 }, 496262744Stychon { 0, 0, 0, 0, 0, 0 }, 497262744Stychon SMBIOS_BOOT_NORMAL 498262744Stychon}; 499262744Stychon 500262744Stychonstruct smbios_table_type127 smbios_type127_template = { 501262744Stychon { SMBIOS_TYPE_EOT, sizeof (struct smbios_table_type127), 0 } 502262744Stychon}; 503262744Stychon 504262744Stychonstatic int smbios_generic_initializer(struct smbios_structure *template_entry, 505262744Stychon const char **template_strings, char *curaddr, char **endaddr, 506262744Stychon uint16_t *n, uint16_t *size); 507262744Stychon 508262744Stychonstatic struct smbios_template_entry smbios_template[] = { 509262744Stychon { (struct smbios_structure *)&smbios_type0_template, 510262744Stychon smbios_type0_strings, 511262744Stychon smbios_generic_initializer }, 512262744Stychon { (struct smbios_structure *)&smbios_type1_template, 513262744Stychon smbios_type1_strings, 514262744Stychon smbios_type1_initializer }, 515262744Stychon { (struct smbios_structure *)&smbios_type3_template, 516262744Stychon smbios_type3_strings, 517262744Stychon smbios_generic_initializer }, 518262744Stychon { (struct smbios_structure *)&smbios_type4_template, 519262744Stychon smbios_type4_strings, 520262744Stychon smbios_type4_initializer }, 521262744Stychon { (struct smbios_structure *)&smbios_type16_template, 522262744Stychon NULL, 523262744Stychon smbios_type16_initializer }, 524262744Stychon { (struct smbios_structure *)&smbios_type17_template, 525262744Stychon smbios_type17_strings, 526262744Stychon smbios_type17_initializer }, 527262744Stychon { (struct smbios_structure *)&smbios_type19_template, 528262744Stychon NULL, 529262744Stychon smbios_type19_initializer }, 530262744Stychon { (struct smbios_structure *)&smbios_type32_template, 531262744Stychon NULL, 532262744Stychon smbios_generic_initializer }, 533262744Stychon { (struct smbios_structure *)&smbios_type127_template, 534262744Stychon NULL, 535262744Stychon smbios_generic_initializer }, 536262744Stychon { NULL,NULL, NULL } 537262744Stychon}; 538262744Stychon 539262744Stychonstatic uint64_t guest_lomem, guest_himem; 540262744Stychonstatic uint16_t type16_handle; 541262744Stychon 542262744Stychonstatic int 543262744Stychonsmbios_generic_initializer(struct smbios_structure *template_entry, 544262744Stychon const char **template_strings, char *curaddr, char **endaddr, 545262744Stychon uint16_t *n, uint16_t *size) 546262744Stychon{ 547262744Stychon struct smbios_structure *entry; 548262744Stychon 549262744Stychon memcpy(curaddr, template_entry, template_entry->length); 550262744Stychon entry = (struct smbios_structure *)curaddr; 551262744Stychon entry->handle = *n + 1; 552262744Stychon curaddr += entry->length; 553262744Stychon if (template_strings != NULL) { 554262744Stychon int i; 555262744Stychon 556262744Stychon for (i = 0; template_strings[i] != NULL; i++) { 557262744Stychon const char *string; 558262744Stychon int len; 559262744Stychon 560262744Stychon string = template_strings[i]; 561262744Stychon len = strlen(string) + 1; 562262744Stychon memcpy(curaddr, string, len); 563262744Stychon curaddr += len; 564262744Stychon } 565262744Stychon *curaddr = '\0'; 566262744Stychon curaddr++; 567262744Stychon } else { 568262744Stychon /* Minimum string section is double nul */ 569262744Stychon *curaddr = '\0'; 570262744Stychon curaddr++; 571262744Stychon *curaddr = '\0'; 572262744Stychon curaddr++; 573262744Stychon } 574262744Stychon (*n)++; 575262744Stychon *endaddr = curaddr; 576262744Stychon 577262744Stychon return (0); 578262744Stychon} 579262744Stychon 580262744Stychonstatic int 581262744Stychonsmbios_type1_initializer(struct smbios_structure *template_entry, 582262744Stychon const char **template_strings, char *curaddr, char **endaddr, 583262744Stychon uint16_t *n, uint16_t *size) 584262744Stychon{ 585262744Stychon struct smbios_table_type1 *type1; 586262744Stychon 587262744Stychon smbios_generic_initializer(template_entry, template_strings, 588262744Stychon curaddr, endaddr, n, size); 589262744Stychon type1 = (struct smbios_table_type1 *)curaddr; 590262744Stychon 591262744Stychon if (guest_uuid_str != NULL) { 592262744Stychon uuid_t uuid; 593262744Stychon uint32_t status; 594262744Stychon 595262744Stychon uuid_from_string(guest_uuid_str, &uuid, &status); 596262744Stychon if (status != uuid_s_ok) 597262744Stychon return (-1); 598262744Stychon 599262744Stychon uuid_enc_le(&type1->uuid, &uuid); 600262744Stychon } else { 601262744Stychon MD5_CTX mdctx; 602262744Stychon u_char digest[16]; 603262744Stychon char hostname[MAXHOSTNAMELEN]; 604262744Stychon 605262744Stychon /* 606262744Stychon * Universally unique and yet reproducible are an 607262744Stychon * oxymoron, however reproducible is desirable in 608262744Stychon * this case. 609262744Stychon */ 610262744Stychon if (gethostname(hostname, sizeof(hostname))) 611262744Stychon return (-1); 612262744Stychon 613262744Stychon MD5Init(&mdctx); 614262744Stychon MD5Update(&mdctx, vmname, strlen(vmname)); 615262744Stychon MD5Update(&mdctx, hostname, sizeof(hostname)); 616262744Stychon MD5Final(digest, &mdctx); 617262744Stychon 618262744Stychon /* 619262744Stychon * Set the variant and version number. 620262744Stychon */ 621262744Stychon digest[6] &= 0x0F; 622262744Stychon digest[6] |= 0x30; /* version 3 */ 623262744Stychon digest[8] &= 0x3F; 624262744Stychon digest[8] |= 0x80; 625262744Stychon 626262744Stychon memcpy(&type1->uuid, digest, sizeof (digest)); 627262744Stychon } 628262744Stychon 629262744Stychon return (0); 630262744Stychon} 631262744Stychon 632262744Stychonstatic int 633262744Stychonsmbios_type4_initializer(struct smbios_structure *template_entry, 634262744Stychon const char **template_strings, char *curaddr, char **endaddr, 635262744Stychon uint16_t *n, uint16_t *size) 636262744Stychon{ 637262744Stychon int i; 638262744Stychon 639348269Srgrimes for (i = 0; i < sockets; i++) { 640262744Stychon struct smbios_table_type4 *type4; 641262744Stychon char *p; 642262744Stychon int nstrings, len; 643262744Stychon 644262744Stychon smbios_generic_initializer(template_entry, template_strings, 645262744Stychon curaddr, endaddr, n, size); 646262744Stychon type4 = (struct smbios_table_type4 *)curaddr; 647262744Stychon p = curaddr + sizeof (struct smbios_table_type4); 648262744Stychon nstrings = 0; 649262744Stychon while (p < *endaddr - 1) { 650262744Stychon if (*p++ == '\0') 651262744Stychon nstrings++; 652262744Stychon } 653262744Stychon len = sprintf(*endaddr - 1, "CPU #%d", i) + 1; 654262744Stychon *endaddr += len - 1; 655262744Stychon *(*endaddr) = '\0'; 656262744Stychon (*endaddr)++; 657262744Stychon type4->socket = nstrings + 1; 658348269Srgrimes /* Revise cores and threads after update to smbios 3.0 */ 659348269Srgrimes if (cores > 254) 660348269Srgrimes type4->cores = 0; 661348269Srgrimes else 662348269Srgrimes type4->cores = cores; 663348269Srgrimes /* This threads is total threads in a socket */ 664348269Srgrimes if ((cores * threads) > 254) 665348269Srgrimes type4->threads = 0; 666348269Srgrimes else 667348269Srgrimes type4->threads = (cores * threads); 668262744Stychon curaddr = *endaddr; 669262744Stychon } 670262744Stychon 671262744Stychon return (0); 672262744Stychon} 673262744Stychon 674262744Stychonstatic int 675262744Stychonsmbios_type16_initializer(struct smbios_structure *template_entry, 676262744Stychon const char **template_strings, char *curaddr, char **endaddr, 677262744Stychon uint16_t *n, uint16_t *size) 678262744Stychon{ 679262744Stychon struct smbios_table_type16 *type16; 680262744Stychon 681262744Stychon type16_handle = *n; 682262744Stychon smbios_generic_initializer(template_entry, template_strings, 683262744Stychon curaddr, endaddr, n, size); 684262744Stychon type16 = (struct smbios_table_type16 *)curaddr; 685262744Stychon type16->xsize = guest_lomem + guest_himem; 686262744Stychon type16->ndevs = guest_himem > 0 ? 2 : 1; 687262744Stychon 688262744Stychon return (0); 689262744Stychon} 690262744Stychon 691262744Stychonstatic int 692262744Stychonsmbios_type17_initializer(struct smbios_structure *template_entry, 693262744Stychon const char **template_strings, char *curaddr, char **endaddr, 694262744Stychon uint16_t *n, uint16_t *size) 695262744Stychon{ 696262744Stychon struct smbios_table_type17 *type17; 697262744Stychon 698262744Stychon smbios_generic_initializer(template_entry, template_strings, 699262744Stychon curaddr, endaddr, n, size); 700262744Stychon type17 = (struct smbios_table_type17 *)curaddr; 701262744Stychon type17->arrayhand = type16_handle; 702262744Stychon type17->xsize = guest_lomem; 703262744Stychon 704262744Stychon if (guest_himem > 0) { 705262744Stychon curaddr = *endaddr; 706262744Stychon smbios_generic_initializer(template_entry, template_strings, 707262744Stychon curaddr, endaddr, n, size); 708262744Stychon type17 = (struct smbios_table_type17 *)curaddr; 709262744Stychon type17->arrayhand = type16_handle; 710262744Stychon type17->xsize = guest_himem; 711262744Stychon } 712262744Stychon 713262744Stychon return (0); 714262744Stychon} 715262744Stychon 716262744Stychonstatic int 717262744Stychonsmbios_type19_initializer(struct smbios_structure *template_entry, 718262744Stychon const char **template_strings, char *curaddr, char **endaddr, 719262744Stychon uint16_t *n, uint16_t *size) 720262744Stychon{ 721262744Stychon struct smbios_table_type19 *type19; 722262744Stychon 723262744Stychon smbios_generic_initializer(template_entry, template_strings, 724262744Stychon curaddr, endaddr, n, size); 725262744Stychon type19 = (struct smbios_table_type19 *)curaddr; 726262744Stychon type19->arrayhand = type16_handle; 727262744Stychon type19->xsaddr = 0; 728262744Stychon type19->xeaddr = guest_lomem; 729262744Stychon 730262744Stychon if (guest_himem > 0) { 731262744Stychon curaddr = *endaddr; 732262744Stychon smbios_generic_initializer(template_entry, template_strings, 733262744Stychon curaddr, endaddr, n, size); 734262744Stychon type19 = (struct smbios_table_type19 *)curaddr; 735262744Stychon type19->arrayhand = type16_handle; 736262744Stychon type19->xsaddr = 4*GB; 737262744Stychon type19->xeaddr = guest_himem; 738262744Stychon } 739262744Stychon 740262744Stychon return (0); 741262744Stychon} 742262744Stychon 743262744Stychonstatic void 744262744Stychonsmbios_ep_initializer(struct smbios_entry_point *smbios_ep, uint32_t staddr) 745262744Stychon{ 746262744Stychon memset(smbios_ep, 0, sizeof(*smbios_ep)); 747262744Stychon memcpy(smbios_ep->eanchor, SMBIOS_ENTRY_EANCHOR, 748262744Stychon SMBIOS_ENTRY_EANCHORLEN); 749262744Stychon smbios_ep->eplen = 0x1F; 750262744Stychon assert(sizeof (struct smbios_entry_point) == smbios_ep->eplen); 751262744Stychon smbios_ep->major = 2; 752272007Sgrehan smbios_ep->minor = 6; 753262744Stychon smbios_ep->revision = 0; 754262744Stychon memcpy(smbios_ep->ianchor, SMBIOS_ENTRY_IANCHOR, 755262744Stychon SMBIOS_ENTRY_IANCHORLEN); 756262744Stychon smbios_ep->staddr = staddr; 757262744Stychon smbios_ep->bcdrev = 0x24; 758262744Stychon} 759262744Stychon 760262744Stychonstatic void 761262744Stychonsmbios_ep_finalizer(struct smbios_entry_point *smbios_ep, uint16_t len, 762262744Stychon uint16_t num, uint16_t maxssize) 763262744Stychon{ 764262744Stychon uint8_t checksum; 765262744Stychon int i; 766262744Stychon 767262744Stychon smbios_ep->maxssize = maxssize; 768262744Stychon smbios_ep->stlen = len; 769262744Stychon smbios_ep->stnum = num; 770262744Stychon 771262744Stychon checksum = 0; 772262744Stychon for (i = 0x10; i < 0x1f; i++) { 773262744Stychon checksum -= ((uint8_t *)smbios_ep)[i]; 774262744Stychon } 775262744Stychon smbios_ep->ichecksum = checksum; 776262744Stychon 777262744Stychon checksum = 0; 778262744Stychon for (i = 0; i < 0x1f; i++) { 779262744Stychon checksum -= ((uint8_t *)smbios_ep)[i]; 780262744Stychon } 781262744Stychon smbios_ep->echecksum = checksum; 782262744Stychon} 783262744Stychon 784262744Stychonint 785262744Stychonsmbios_build(struct vmctx *ctx) 786262744Stychon{ 787262744Stychon struct smbios_entry_point *smbios_ep; 788262744Stychon uint16_t n; 789262744Stychon uint16_t maxssize; 790262744Stychon char *curaddr, *startaddr, *ststartaddr; 791262744Stychon int i; 792262744Stychon int err; 793262744Stychon 794267811Sneel guest_lomem = vm_get_lowmem_size(ctx); 795267811Sneel guest_himem = vm_get_highmem_size(ctx); 796262744Stychon 797262744Stychon startaddr = paddr_guest2host(ctx, SMBIOS_BASE, SMBIOS_MAX_LENGTH); 798262744Stychon if (startaddr == NULL) { 799262744Stychon fprintf(stderr, "smbios table requires mapped mem\n"); 800262744Stychon return (ENOMEM); 801262744Stychon } 802262744Stychon 803262744Stychon curaddr = startaddr; 804262744Stychon 805262744Stychon smbios_ep = (struct smbios_entry_point *)curaddr; 806262744Stychon smbios_ep_initializer(smbios_ep, SMBIOS_BASE + 807262744Stychon sizeof(struct smbios_entry_point)); 808262744Stychon curaddr += sizeof(struct smbios_entry_point); 809262744Stychon ststartaddr = curaddr; 810262744Stychon 811262744Stychon n = 0; 812262744Stychon maxssize = 0; 813262744Stychon for (i = 0; smbios_template[i].entry != NULL; i++) { 814262744Stychon struct smbios_structure *entry; 815262744Stychon const char **strings; 816262744Stychon initializer_func_t initializer; 817262744Stychon char *endaddr; 818262744Stychon uint16_t size; 819262744Stychon 820262744Stychon entry = smbios_template[i].entry; 821262744Stychon strings = smbios_template[i].strings; 822262744Stychon initializer = smbios_template[i].initializer; 823262744Stychon 824262744Stychon err = (*initializer)(entry, strings, curaddr, &endaddr, 825262744Stychon &n, &size); 826262744Stychon if (err != 0) 827262744Stychon return (err); 828262744Stychon 829262744Stychon if (size > maxssize) 830262744Stychon maxssize = size; 831262744Stychon 832262744Stychon curaddr = endaddr; 833262744Stychon } 834262744Stychon 835262744Stychon assert(curaddr - startaddr < SMBIOS_MAX_LENGTH); 836262744Stychon smbios_ep_finalizer(smbios_ep, curaddr - ststartaddr, n, maxssize); 837262744Stychon 838262744Stychon return (0); 839262744Stychon} 840