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