1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2014 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29 #include <sys/cdefs.h> 30 __FBSDID("$FreeBSD$"); 31 32 #include <sys/param.h> 33 34 #include <assert.h> 35 #include <errno.h> 36 #include <md5.h> 37 #include <stdio.h> 38 #include <stdlib.h> 39 #include <string.h> 40 #include <unistd.h> 41 #include <uuid.h> 42 43 #include <machine/vmm.h> 44 #include <vmmapi.h> 45 46 #ifndef __FreeBSD__ 47 #include <sys/sysmacros.h> 48 #endif 49 50 #include "bhyverun.h" 51 #include "config.h" 52 #include "debug.h" 53 #include "smbiostbl.h" 54 55 #define MB (1024*1024) 56 #define GB (1024ULL*1024*1024) 57 58 #define SMBIOS_BASE 0xF1000 59 60 #define FIRMWARE_VERSION "14.0" 61 /* The SMBIOS specification defines the date format to be mm/dd/yyyy */ 62 #define FIRMWARE_RELEASE_DATE "10/10/2021" 63 64 /* BHYVE_ACPI_BASE - SMBIOS_BASE) */ 65 #define SMBIOS_MAX_LENGTH (0xF2400 - 0xF1000) 66 67 #define SMBIOS_TYPE_BIOS 0 68 #define SMBIOS_TYPE_SYSTEM 1 69 #define SMBIOS_TYPE_BOARD 2 70 #define SMBIOS_TYPE_CHASSIS 3 71 #define SMBIOS_TYPE_PROCESSOR 4 72 #define SMBIOS_TYPE_MEMARRAY 16 73 #define SMBIOS_TYPE_MEMDEVICE 17 74 #define SMBIOS_TYPE_MEMARRAYMAP 19 75 #define SMBIOS_TYPE_BOOT 32 76 #define SMBIOS_TYPE_EOT 127 77 78 struct smbios_structure { 79 uint8_t type; 80 uint8_t length; 81 uint16_t handle; 82 } __packed; 83 84 struct smbios_string { 85 const char *node; 86 const char *value; 87 }; 88 89 typedef int (*initializer_func_t)(const struct smbios_structure *template_entry, 90 const struct smbios_string *template_strings, char *curaddr, char **endaddr, 91 uint16_t *n); 92 93 struct smbios_template_entry { 94 const struct smbios_structure *entry; 95 const struct smbios_string *strings; 96 initializer_func_t initializer; 97 }; 98 99 /* 100 * SMBIOS Structure Table Entry Point 101 */ 102 #define SMBIOS_ENTRY_EANCHOR "_SM_" 103 #define SMBIOS_ENTRY_EANCHORLEN 4 104 #define SMBIOS_ENTRY_IANCHOR "_DMI_" 105 #define SMBIOS_ENTRY_IANCHORLEN 5 106 107 struct smbios_entry_point { 108 char eanchor[4]; /* anchor tag */ 109 uint8_t echecksum; /* checksum of entry point structure */ 110 uint8_t eplen; /* length in bytes of entry point */ 111 uint8_t major; /* major version of the SMBIOS spec */ 112 uint8_t minor; /* minor version of the SMBIOS spec */ 113 uint16_t maxssize; /* maximum size in bytes of a struct */ 114 uint8_t revision; /* entry point structure revision */ 115 uint8_t format[5]; /* entry point rev-specific data */ 116 char ianchor[5]; /* intermediate anchor tag */ 117 uint8_t ichecksum; /* intermediate checksum */ 118 uint16_t stlen; /* len in bytes of structure table */ 119 uint32_t staddr; /* physical addr of structure table */ 120 uint16_t stnum; /* number of structure table entries */ 121 uint8_t bcdrev; /* BCD value representing DMI ver */ 122 } __packed; 123 124 /* 125 * BIOS Information 126 */ 127 #define SMBIOS_FL_ISA 0x00000010 /* ISA is supported */ 128 #define SMBIOS_FL_PCI 0x00000080 /* PCI is supported */ 129 #define SMBIOS_FL_SHADOW 0x00001000 /* BIOS shadowing is allowed */ 130 #define SMBIOS_FL_CDBOOT 0x00008000 /* Boot from CD is supported */ 131 #define SMBIOS_FL_SELBOOT 0x00010000 /* Selectable Boot supported */ 132 #define SMBIOS_FL_EDD 0x00080000 /* EDD Spec is supported */ 133 134 #define SMBIOS_XB1_FL_ACPI 0x00000001 /* ACPI is supported */ 135 136 #define SMBIOS_XB2_FL_BBS 0x00000001 /* BIOS Boot Specification */ 137 #define SMBIOS_XB2_FL_VM 0x00000010 /* Virtual Machine */ 138 139 struct smbios_table_type0 { 140 struct smbios_structure header; 141 uint8_t vendor; /* vendor string */ 142 uint8_t version; /* version string */ 143 uint16_t segment; /* address segment location */ 144 uint8_t rel_date; /* release date */ 145 uint8_t size; /* rom size */ 146 uint64_t cflags; /* characteristics */ 147 uint8_t xc_bytes[2]; /* characteristics ext bytes */ 148 uint8_t sb_major_rel; /* system bios version */ 149 uint8_t sb_minor_rele; 150 uint8_t ecfw_major_rel; /* embedded ctrl fw version */ 151 uint8_t ecfw_minor_rel; 152 } __packed; 153 154 /* 155 * System Information 156 */ 157 #define SMBIOS_WAKEUP_SWITCH 0x06 /* power switch */ 158 159 struct smbios_table_type1 { 160 struct smbios_structure header; 161 uint8_t manufacturer; /* manufacturer string */ 162 uint8_t product; /* product name string */ 163 uint8_t version; /* version string */ 164 uint8_t serial; /* serial number string */ 165 uint8_t uuid[16]; /* uuid byte array */ 166 uint8_t wakeup; /* wake-up event */ 167 uint8_t sku; /* sku number string */ 168 uint8_t family; /* family name string */ 169 } __packed; 170 171 /* 172 * Baseboard (or Module) Information 173 */ 174 #define SMBIOS_BRF_HOSTING 0x1 175 #define SMBIOS_BRT_MOTHERBOARD 0xa 176 177 struct smbios_table_type2 { 178 struct smbios_structure header; 179 uint8_t manufacturer; /* manufacturer string */ 180 uint8_t product; /* product name string */ 181 uint8_t version; /* version string */ 182 uint8_t serial; /* serial number string */ 183 uint8_t asset; /* asset tag string */ 184 uint8_t fflags; /* feature flags */ 185 uint8_t location; /* location in chassis */ 186 uint16_t chandle; /* chassis handle */ 187 uint8_t type; /* board type */ 188 uint8_t n_objs; /* number of contained object handles */ 189 } __packed; 190 191 /* 192 * System Enclosure or Chassis 193 */ 194 #define SMBIOS_CHT_UNKNOWN 0x02 /* unknown */ 195 #define SMBIOS_CHT_DESKTOP 0x03 /* desktop */ 196 197 #define SMBIOS_CHST_SAFE 0x03 /* safe */ 198 199 #define SMBIOS_CHSC_NONE 0x03 /* none */ 200 201 struct smbios_table_type3 { 202 struct smbios_structure header; 203 uint8_t manufacturer; /* manufacturer string */ 204 uint8_t type; /* type */ 205 uint8_t version; /* version string */ 206 uint8_t serial; /* serial number string */ 207 uint8_t asset; /* asset tag string */ 208 uint8_t bustate; /* boot-up state */ 209 uint8_t psstate; /* power supply state */ 210 uint8_t tstate; /* thermal state */ 211 uint8_t security; /* security status */ 212 uint32_t oemdata; /* OEM-specific data */ 213 uint8_t uheight; /* height in 'u's */ 214 uint8_t cords; /* number of power cords */ 215 uint8_t elems; /* number of element records */ 216 uint8_t elemlen; /* length of records */ 217 uint8_t sku; /* sku number string */ 218 } __packed; 219 220 /* 221 * Processor Information 222 */ 223 #define SMBIOS_PRT_CENTRAL 0x03 /* central processor */ 224 225 #define SMBIOS_PRF_OTHER 0x01 /* other */ 226 227 #define SMBIOS_PRS_PRESENT 0x40 /* socket is populated */ 228 #define SMBIOS_PRS_ENABLED 0x1 /* enabled */ 229 230 #define SMBIOS_PRU_NONE 0x06 /* none */ 231 232 #define SMBIOS_PFL_64B 0x04 /* 64-bit capable */ 233 234 struct smbios_table_type4 { 235 struct smbios_structure header; 236 uint8_t socket; /* socket designation string */ 237 uint8_t type; /* processor type */ 238 uint8_t family; /* processor family */ 239 uint8_t manufacturer; /* manufacturer string */ 240 uint64_t cpuid; /* processor cpuid */ 241 uint8_t version; /* version string */ 242 uint8_t voltage; /* voltage */ 243 uint16_t clkspeed; /* ext clock speed in mhz */ 244 uint16_t maxspeed; /* maximum speed in mhz */ 245 uint16_t curspeed; /* current speed in mhz */ 246 uint8_t status; /* status */ 247 uint8_t upgrade; /* upgrade */ 248 uint16_t l1handle; /* l1 cache handle */ 249 uint16_t l2handle; /* l2 cache handle */ 250 uint16_t l3handle; /* l3 cache handle */ 251 uint8_t serial; /* serial number string */ 252 uint8_t asset; /* asset tag string */ 253 uint8_t part; /* part number string */ 254 uint8_t cores; /* cores per socket */ 255 uint8_t ecores; /* enabled cores */ 256 uint8_t threads; /* threads per socket */ 257 uint16_t cflags; /* processor characteristics */ 258 uint16_t family2; /* processor family 2 */ 259 } __packed; 260 261 /* 262 * Physical Memory Array 263 */ 264 #define SMBIOS_MAL_SYSMB 0x03 /* system board or motherboard */ 265 266 #define SMBIOS_MAU_SYSTEM 0x03 /* system memory */ 267 268 #define SMBIOS_MAE_NONE 0x03 /* none */ 269 270 struct smbios_table_type16 { 271 struct smbios_structure header; 272 uint8_t location; /* physical device location */ 273 uint8_t use; /* device functional purpose */ 274 uint8_t ecc; /* err detect/correct method */ 275 uint32_t size; /* max mem capacity in kb */ 276 uint16_t errhand; /* handle of error (if any) */ 277 uint16_t ndevs; /* num of slots or sockets */ 278 uint64_t xsize; /* max mem capacity in bytes */ 279 } __packed; 280 281 /* 282 * Memory Device 283 */ 284 #define SMBIOS_MDFF_UNKNOWN 0x02 /* unknown */ 285 286 #define SMBIOS_MDT_UNKNOWN 0x02 /* unknown */ 287 288 #define SMBIOS_MDF_UNKNOWN 0x0004 /* unknown */ 289 290 struct smbios_table_type17 { 291 struct smbios_structure header; 292 uint16_t arrayhand; /* handle of physl mem array */ 293 uint16_t errhand; /* handle of mem error data */ 294 uint16_t twidth; /* total width in bits */ 295 uint16_t dwidth; /* data width in bits */ 296 uint16_t size; /* size in kb or mb */ 297 uint8_t form; /* form factor */ 298 uint8_t set; /* set */ 299 uint8_t dloc; /* device locator string */ 300 uint8_t bloc; /* phys bank locator string */ 301 uint8_t type; /* memory type */ 302 uint16_t flags; /* memory characteristics */ 303 uint16_t maxspeed; /* maximum speed in mhz */ 304 uint8_t manufacturer; /* manufacturer string */ 305 uint8_t serial; /* serial number string */ 306 uint8_t asset; /* asset tag string */ 307 uint8_t part; /* part number string */ 308 uint8_t attributes; /* attributes */ 309 uint32_t xsize; /* extended size in mb */ 310 uint16_t curspeed; /* current speed in mhz */ 311 uint16_t minvoltage; /* minimum voltage */ 312 uint16_t maxvoltage; /* maximum voltage */ 313 uint16_t curvoltage; /* configured voltage */ 314 } __packed; 315 316 /* 317 * Memory Array Mapped Address 318 */ 319 struct smbios_table_type19 { 320 struct smbios_structure header; 321 uint32_t saddr; /* start phys addr in kb */ 322 uint32_t eaddr; /* end phys addr in kb */ 323 uint16_t arrayhand; /* physical mem array handle */ 324 uint8_t width; /* num of dev in row */ 325 uint64_t xsaddr; /* start phys addr in bytes */ 326 uint64_t xeaddr; /* end phys addr in bytes */ 327 } __packed; 328 329 /* 330 * System Boot Information 331 */ 332 #define SMBIOS_BOOT_NORMAL 0 /* no errors detected */ 333 334 struct smbios_table_type32 { 335 struct smbios_structure header; 336 uint8_t reserved[6]; 337 uint8_t status; /* boot status */ 338 } __packed; 339 340 /* 341 * End-of-Table 342 */ 343 struct smbios_table_type127 { 344 struct smbios_structure header; 345 } __packed; 346 347 static const struct smbios_table_type0 smbios_type0_template = { 348 { SMBIOS_TYPE_BIOS, sizeof (struct smbios_table_type0), 0 }, 349 1, /* bios vendor string */ 350 2, /* bios version string */ 351 0xF000, /* bios address segment location */ 352 3, /* bios release date */ 353 0x0, /* bios size (64k * (n + 1) is the size in bytes) */ 354 SMBIOS_FL_ISA | SMBIOS_FL_PCI | SMBIOS_FL_SHADOW | 355 SMBIOS_FL_CDBOOT | SMBIOS_FL_EDD, 356 { SMBIOS_XB1_FL_ACPI, SMBIOS_XB2_FL_BBS | SMBIOS_XB2_FL_VM }, 357 0x0, /* bios major release */ 358 0x0, /* bios minor release */ 359 0xff, /* embedded controller firmware major release */ 360 0xff /* embedded controller firmware minor release */ 361 }; 362 363 static const struct smbios_string smbios_type0_strings[] = { 364 { "bios.vendor", "BHYVE" }, /* vendor string */ 365 { "bios.version", FIRMWARE_VERSION }, /* bios version string */ 366 { "bios.release_date", FIRMWARE_RELEASE_DATE }, /* bios release date string */ 367 { 0 } 368 }; 369 370 static const struct smbios_table_type1 smbios_type1_template = { 371 { SMBIOS_TYPE_SYSTEM, sizeof (struct smbios_table_type1), 0 }, 372 1, /* manufacturer string */ 373 2, /* product string */ 374 3, /* version string */ 375 4, /* serial number string */ 376 { 0 }, 377 SMBIOS_WAKEUP_SWITCH, 378 5, /* sku string */ 379 6 /* family string */ 380 }; 381 382 static int smbios_type1_initializer(const struct smbios_structure *template_entry, 383 const struct smbios_string *template_strings, char *curaddr, char **endaddr, 384 uint16_t *n); 385 386 static const struct smbios_string smbios_type1_strings[] = { 387 { "system.manufacturer", "illumos" }, /* manufacturer string */ 388 { "system.product_name", "BHYVE" }, /* product string */ 389 { "system.version", "1.0" }, /* version string */ 390 { "system.serial_number", "None" }, /* serial number string */ 391 { "system.sku", "None" }, /* sku string */ 392 { "system.family_name", "Virtual Machine" }, /* family string */ 393 { 0 } 394 }; 395 396 static const struct smbios_table_type2 smbios_type2_template = { 397 { SMBIOS_TYPE_BOARD, sizeof (struct smbios_table_type2), 0 }, 398 1, /* manufacturer string */ 399 2, /* product string */ 400 3, /* version string */ 401 4, /* serial number string */ 402 5, /* asset tag string */ 403 SMBIOS_BRF_HOSTING, /* feature flags */ 404 6, /* location string */ 405 SMBIOS_CHT_DESKTOP, /* chassis handle */ 406 SMBIOS_BRT_MOTHERBOARD, /* board type */ 407 0 408 }; 409 410 static const struct smbios_string smbios_type2_strings[] = { 411 { "board.manufacturer", "illumos" }, /* manufacturer string */ 412 { "board.product_name", "BHYVE" }, /* product name string */ 413 { "board.version", "1.0" }, /* version string */ 414 { "board.serial_number", "None" }, /* serial number string */ 415 { "board.asset_tag", "None" }, /* asset tag string */ 416 { "board.location", "None" }, /* location string */ 417 { 0 } 418 }; 419 420 static const struct smbios_table_type3 smbios_type3_template = { 421 { SMBIOS_TYPE_CHASSIS, sizeof (struct smbios_table_type3), 0 }, 422 1, /* manufacturer string */ 423 SMBIOS_CHT_UNKNOWN, 424 2, /* version string */ 425 3, /* serial number string */ 426 4, /* asset tag string */ 427 SMBIOS_CHST_SAFE, 428 SMBIOS_CHST_SAFE, 429 SMBIOS_CHST_SAFE, 430 SMBIOS_CHSC_NONE, 431 0, /* OEM specific data, we have none */ 432 0, /* height in 'u's (0=enclosure height unspecified) */ 433 0, /* number of power cords (0=number unspecified) */ 434 0, /* number of contained element records */ 435 0, /* length of records */ 436 5 /* sku number string */ 437 }; 438 439 static const struct smbios_string smbios_type3_strings[] = { 440 { "chassis.manufacturer", "illumos" }, /* manufacturer string */ 441 { "chassis.version", "1.0" }, /* version string */ 442 { "chassis.serial_number", "None" }, /* serial number string */ 443 { "chassis.asset_tag", "None" }, /* asset tag string */ 444 { "chassis.sku", "None" }, /* sku number string */ 445 { 0 } 446 }; 447 448 static const struct smbios_table_type4 smbios_type4_template = { 449 { SMBIOS_TYPE_PROCESSOR, sizeof (struct smbios_table_type4), 0 }, 450 1, /* socket designation string */ 451 SMBIOS_PRT_CENTRAL, 452 SMBIOS_PRF_OTHER, 453 2, /* manufacturer string */ 454 0, /* cpuid */ 455 3, /* version string */ 456 0, /* voltage */ 457 0, /* external clock frequency in mhz (0=unknown) */ 458 0, /* maximum frequency in mhz (0=unknown) */ 459 0, /* current frequency in mhz (0=unknown) */ 460 SMBIOS_PRS_PRESENT | SMBIOS_PRS_ENABLED, 461 SMBIOS_PRU_NONE, 462 -1, /* l1 cache handle */ 463 -1, /* l2 cache handle */ 464 -1, /* l3 cache handle */ 465 4, /* serial number string */ 466 5, /* asset tag string */ 467 6, /* part number string */ 468 0, /* cores per socket (0=unknown) */ 469 0, /* enabled cores per socket (0=unknown) */ 470 0, /* threads per socket (0=unknown) */ 471 SMBIOS_PFL_64B, 472 SMBIOS_PRF_OTHER 473 }; 474 475 static const struct smbios_string smbios_type4_strings[] = { 476 { NULL, " " }, /* socket designation string */ 477 { NULL, " " }, /* manufacturer string */ 478 { NULL, " " }, /* version string */ 479 { NULL, "None" }, /* serial number string */ 480 { NULL, "None" }, /* asset tag string */ 481 { NULL, "None" }, /* part number string */ 482 { 0 } 483 }; 484 485 static int smbios_type4_initializer( 486 const struct smbios_structure *template_entry, 487 const struct smbios_string *template_strings, char *curaddr, char **endaddr, 488 uint16_t *n); 489 490 static const struct smbios_table_type16 smbios_type16_template = { 491 { SMBIOS_TYPE_MEMARRAY, sizeof (struct smbios_table_type16), 0 }, 492 SMBIOS_MAL_SYSMB, 493 SMBIOS_MAU_SYSTEM, 494 SMBIOS_MAE_NONE, 495 0x80000000, /* max mem capacity in kb (0x80000000=use extended) */ 496 -1, /* handle of error (if any) */ 497 0, /* number of slots or sockets (TBD) */ 498 0 /* extended maximum memory capacity in bytes (TBD) */ 499 }; 500 501 static int smbios_type16_initializer( 502 const struct smbios_structure *template_entry, 503 const struct smbios_string *template_strings, char *curaddr, char **endaddr, 504 uint16_t *n); 505 506 static const struct smbios_table_type17 smbios_type17_template = { 507 { SMBIOS_TYPE_MEMDEVICE, sizeof (struct smbios_table_type17), 0 }, 508 -1, /* handle of physical memory array */ 509 -1, /* handle of memory error data */ 510 64, /* total width in bits including ecc */ 511 64, /* data width in bits */ 512 0, /* size in kb or mb (0x7fff=use extended)*/ 513 SMBIOS_MDFF_UNKNOWN, 514 0, /* set (0x00=none, 0xff=unknown) */ 515 1, /* device locator string */ 516 2, /* physical bank locator string */ 517 SMBIOS_MDT_UNKNOWN, 518 SMBIOS_MDF_UNKNOWN, 519 0, /* maximum memory speed in mhz (0=unknown) */ 520 3, /* manufacturer string */ 521 4, /* serial number string */ 522 5, /* asset tag string */ 523 6, /* part number string */ 524 0, /* attributes (0=unknown rank information) */ 525 0, /* extended size in mb (TBD) */ 526 0, /* current speed in mhz (0=unknown) */ 527 0, /* minimum voltage in mv (0=unknown) */ 528 0, /* maximum voltage in mv (0=unknown) */ 529 0 /* configured voltage in mv (0=unknown) */ 530 }; 531 532 static const struct smbios_string smbios_type17_strings[] = { 533 { NULL, " " }, /* device locator string */ 534 { NULL, " " }, /* physical bank locator string */ 535 { NULL, " " }, /* manufacturer string */ 536 { NULL, "None" }, /* serial number string */ 537 { NULL, "None" }, /* asset tag string */ 538 { NULL, "None" }, /* part number string */ 539 { 0 } 540 }; 541 542 static int smbios_type17_initializer( 543 const struct smbios_structure *template_entry, 544 const struct smbios_string *template_strings, char *curaddr, char **endaddr, 545 uint16_t *n); 546 547 static const struct smbios_table_type19 smbios_type19_template = { 548 { SMBIOS_TYPE_MEMARRAYMAP, sizeof (struct smbios_table_type19), 0 }, 549 0xffffffff, /* starting phys addr in kb (0xffffffff=use ext) */ 550 0xffffffff, /* ending phys addr in kb (0xffffffff=use ext) */ 551 -1, /* physical memory array handle */ 552 1, /* number of devices that form a row */ 553 0, /* extended starting phys addr in bytes (TDB) */ 554 0 /* extended ending phys addr in bytes (TDB) */ 555 }; 556 557 static int smbios_type19_initializer( 558 const struct smbios_structure *template_entry, 559 const struct smbios_string *template_strings, char *curaddr, char **endaddr, 560 uint16_t *n); 561 562 static struct smbios_table_type32 smbios_type32_template = { 563 { SMBIOS_TYPE_BOOT, sizeof (struct smbios_table_type32), 0 }, 564 { 0, 0, 0, 0, 0, 0 }, 565 SMBIOS_BOOT_NORMAL 566 }; 567 568 static const struct smbios_table_type127 smbios_type127_template = { 569 { SMBIOS_TYPE_EOT, sizeof (struct smbios_table_type127), 0 } 570 }; 571 572 static int smbios_generic_initializer( 573 const struct smbios_structure *template_entry, 574 const struct smbios_string *template_strings, char *curaddr, char **endaddr, 575 uint16_t *n); 576 577 static struct smbios_template_entry smbios_template[] = { 578 { (const struct smbios_structure *)&smbios_type0_template, 579 smbios_type0_strings, 580 smbios_generic_initializer }, 581 { (const struct smbios_structure *)&smbios_type1_template, 582 smbios_type1_strings, 583 smbios_type1_initializer }, 584 { (const struct smbios_structure *)&smbios_type2_template, 585 smbios_type2_strings, 586 smbios_generic_initializer }, 587 { (const struct smbios_structure *)&smbios_type3_template, 588 smbios_type3_strings, 589 smbios_generic_initializer }, 590 { (const struct smbios_structure *)&smbios_type4_template, 591 smbios_type4_strings, 592 smbios_type4_initializer }, 593 { (const struct smbios_structure *)&smbios_type16_template, 594 NULL, 595 smbios_type16_initializer }, 596 { (const struct smbios_structure *)&smbios_type17_template, 597 smbios_type17_strings, 598 smbios_type17_initializer }, 599 { (const struct smbios_structure *)&smbios_type19_template, 600 NULL, 601 smbios_type19_initializer }, 602 { (const struct smbios_structure *)&smbios_type32_template, 603 NULL, 604 smbios_generic_initializer }, 605 { (const struct smbios_structure *)&smbios_type127_template, 606 NULL, 607 smbios_generic_initializer }, 608 { NULL,NULL, NULL } 609 }; 610 611 static uint64_t guest_lomem, guest_himem; 612 static uint16_t type16_handle; 613 614 static int 615 smbios_generic_initializer(const struct smbios_structure *template_entry, 616 const struct smbios_string *template_strings, char *curaddr, char **endaddr, 617 uint16_t *n) 618 { 619 struct smbios_structure *entry; 620 621 memcpy(curaddr, template_entry, template_entry->length); 622 entry = (struct smbios_structure *)curaddr; 623 entry->handle = *n + 1; 624 curaddr += entry->length; 625 if (template_strings != NULL) { 626 int i; 627 628 for (i = 0; template_strings[i].value != NULL; i++) { 629 const char *string; 630 int len; 631 632 if (template_strings[i].node == NULL) { 633 string = template_strings[i].value; 634 } else { 635 set_config_value_if_unset( 636 template_strings[i].node, 637 template_strings[i].value); 638 string = get_config_value( 639 template_strings[i].node); 640 } 641 642 len = strlen(string) + 1; 643 memcpy(curaddr, string, len); 644 curaddr += len; 645 } 646 *curaddr = '\0'; 647 curaddr++; 648 } else { 649 /* Minimum string section is double nul */ 650 *curaddr = '\0'; 651 curaddr++; 652 *curaddr = '\0'; 653 curaddr++; 654 } 655 (*n)++; 656 *endaddr = curaddr; 657 658 return (0); 659 } 660 661 static int 662 smbios_type1_initializer(const struct smbios_structure *template_entry, 663 const struct smbios_string *template_strings, char *curaddr, char **endaddr, 664 uint16_t *n) 665 { 666 struct smbios_table_type1 *type1; 667 const char *guest_uuid_str; 668 669 smbios_generic_initializer(template_entry, template_strings, 670 curaddr, endaddr, n); 671 type1 = (struct smbios_table_type1 *)curaddr; 672 673 guest_uuid_str = get_config_value("uuid"); 674 if (guest_uuid_str != NULL) { 675 uuid_t uuid; 676 uint32_t status; 677 678 uuid_from_string(guest_uuid_str, &uuid, &status); 679 if (status != uuid_s_ok) { 680 EPRINTLN("Invalid UUID"); 681 return (-1); 682 } 683 684 uuid_enc_le(&type1->uuid, &uuid); 685 } else { 686 MD5_CTX mdctx; 687 u_char digest[16]; 688 char hostname[MAXHOSTNAMELEN]; 689 const char *vmname; 690 691 /* 692 * Universally unique and yet reproducible are an 693 * oxymoron, however reproducible is desirable in 694 * this case. 695 */ 696 if (gethostname(hostname, sizeof(hostname))) 697 return (-1); 698 699 MD5Init(&mdctx); 700 vmname = get_config_value("name"); 701 MD5Update(&mdctx, vmname, strlen(vmname)); 702 MD5Update(&mdctx, hostname, sizeof(hostname)); 703 MD5Final(digest, &mdctx); 704 705 /* 706 * Set the variant and version number. 707 */ 708 digest[6] &= 0x0F; 709 digest[6] |= 0x30; /* version 3 */ 710 digest[8] &= 0x3F; 711 digest[8] |= 0x80; 712 713 memcpy(&type1->uuid, digest, sizeof (digest)); 714 } 715 716 return (0); 717 } 718 719 static int 720 smbios_type4_initializer(const struct smbios_structure *template_entry, 721 const struct smbios_string *template_strings, char *curaddr, char **endaddr, 722 uint16_t *n) 723 { 724 int i; 725 726 for (i = 0; i < cpu_sockets; i++) { 727 struct smbios_table_type4 *type4; 728 char *p; 729 int nstrings, len; 730 731 smbios_generic_initializer(template_entry, template_strings, 732 curaddr, endaddr, n); 733 type4 = (struct smbios_table_type4 *)curaddr; 734 p = curaddr + sizeof (struct smbios_table_type4); 735 nstrings = 0; 736 while (p < *endaddr - 1) { 737 if (*p++ == '\0') 738 nstrings++; 739 } 740 len = sprintf(*endaddr - 1, "CPU #%d", i) + 1; 741 *endaddr += len - 1; 742 *(*endaddr) = '\0'; 743 (*endaddr)++; 744 type4->socket = nstrings + 1; 745 /* Revise cores and threads after update to smbios 3.0 */ 746 if (cpu_cores > 254) 747 type4->cores = 0; 748 else 749 type4->cores = cpu_cores; 750 /* This threads is total threads in a socket */ 751 if (cpu_cores * cpu_threads > 254) 752 type4->threads = 0; 753 else 754 type4->threads = cpu_cores * cpu_threads; 755 curaddr = *endaddr; 756 } 757 758 return (0); 759 } 760 761 static int 762 smbios_type16_initializer(const struct smbios_structure *template_entry, 763 const struct smbios_string *template_strings, char *curaddr, char **endaddr, 764 uint16_t *n) 765 { 766 struct smbios_table_type16 *type16; 767 768 type16_handle = *n; 769 smbios_generic_initializer(template_entry, template_strings, 770 curaddr, endaddr, n); 771 type16 = (struct smbios_table_type16 *)curaddr; 772 type16->xsize = guest_lomem + guest_himem; 773 type16->ndevs = guest_himem > 0 ? 2 : 1; 774 775 return (0); 776 } 777 778 static int 779 smbios_type17_initializer(const struct smbios_structure *template_entry, 780 const struct smbios_string *template_strings, char *curaddr, char **endaddr, 781 uint16_t *n) 782 { 783 struct smbios_table_type17 *type17; 784 uint64_t memsize, size_KB, size_MB; 785 786 smbios_generic_initializer(template_entry, template_strings, 787 curaddr, endaddr, n); 788 type17 = (struct smbios_table_type17 *)curaddr; 789 type17->arrayhand = type16_handle; 790 791 memsize = guest_lomem + guest_himem; 792 size_KB = memsize / 1024; 793 size_MB = memsize / MB; 794 795 /* A single Type 17 entry can't represent more than ~2PB RAM */ 796 if (size_MB > 0x7FFFFFFF) { 797 printf("Warning: guest memory too big for SMBIOS Type 17 table: " 798 "%luMB greater than max supported 2147483647MB\n", size_MB); 799 800 size_MB = 0x7FFFFFFF; 801 } 802 803 /* See SMBIOS 2.7.0 section 7.18 - Memory Device (Type 17) */ 804 if (size_KB <= 0x7FFF) { 805 /* Can represent up to 32767KB with the top bit set */ 806 type17->size = size_KB | (1 << 15); 807 } else if (size_MB < 0x7FFF) { 808 /* Can represent up to 32766MB with the top bit unset */ 809 type17->size = size_MB & 0x7FFF; 810 } else { 811 type17->size = 0x7FFF; 812 /* 813 * Can represent up to 2147483647MB (~2PB) 814 * The top bit is reserved 815 */ 816 type17->xsize = size_MB & 0x7FFFFFFF; 817 } 818 819 return (0); 820 } 821 822 static int 823 smbios_type19_initializer(const struct smbios_structure *template_entry, 824 const struct smbios_string *template_strings, char *curaddr, char **endaddr, 825 uint16_t *n) 826 { 827 struct smbios_table_type19 *type19; 828 829 smbios_generic_initializer(template_entry, template_strings, 830 curaddr, endaddr, n); 831 type19 = (struct smbios_table_type19 *)curaddr; 832 type19->arrayhand = type16_handle; 833 type19->xsaddr = 0; 834 type19->xeaddr = guest_lomem; 835 836 if (guest_himem > 0) { 837 curaddr = *endaddr; 838 smbios_generic_initializer(template_entry, template_strings, 839 curaddr, endaddr, n); 840 type19 = (struct smbios_table_type19 *)curaddr; 841 type19->arrayhand = type16_handle; 842 type19->xsaddr = 4*GB; 843 type19->xeaddr = type19->xsaddr + guest_himem; 844 } 845 846 return (0); 847 } 848 849 static void 850 smbios_ep_initializer(struct smbios_entry_point *smbios_ep, uint32_t staddr) 851 { 852 memset(smbios_ep, 0, sizeof(*smbios_ep)); 853 memcpy(smbios_ep->eanchor, SMBIOS_ENTRY_EANCHOR, 854 SMBIOS_ENTRY_EANCHORLEN); 855 smbios_ep->eplen = 0x1F; 856 assert(sizeof (struct smbios_entry_point) == smbios_ep->eplen); 857 smbios_ep->major = 2; 858 smbios_ep->minor = 6; 859 smbios_ep->revision = 0; 860 memcpy(smbios_ep->ianchor, SMBIOS_ENTRY_IANCHOR, 861 SMBIOS_ENTRY_IANCHORLEN); 862 smbios_ep->staddr = staddr; 863 smbios_ep->bcdrev = (smbios_ep->major & 0xf) << 4 | (smbios_ep->minor & 0xf); 864 } 865 866 static void 867 smbios_ep_finalizer(struct smbios_entry_point *smbios_ep, uint16_t len, 868 uint16_t num, uint16_t maxssize) 869 { 870 uint8_t checksum; 871 int i; 872 873 smbios_ep->maxssize = maxssize; 874 smbios_ep->stlen = len; 875 smbios_ep->stnum = num; 876 877 checksum = 0; 878 for (i = 0x10; i < 0x1f; i++) { 879 checksum -= ((uint8_t *)smbios_ep)[i]; 880 } 881 smbios_ep->ichecksum = checksum; 882 883 checksum = 0; 884 for (i = 0; i < 0x1f; i++) { 885 checksum -= ((uint8_t *)smbios_ep)[i]; 886 } 887 smbios_ep->echecksum = checksum; 888 } 889 890 #ifndef __FreeBSD__ 891 /* 892 * bhyve on illumos previously used configuration keys starting with 'smbios.' 893 * to control type 1 SMBIOS information. Since these may still be present in 894 * bhyve configuration files, the following table is used to translate them 895 * to their new key names. 896 */ 897 static struct { 898 const char *oldkey; 899 const char *newkey; 900 } smbios_legacy_config_map[] = { 901 { "smbios.manufacturer", "system.manufacturer" }, 902 { "smbios.family", "system.family_name" }, 903 { "smbios.product", "system.product_name" }, 904 { "smbios.serial", "system.serial_number" }, 905 { "smbios.sku", "system.sku" }, 906 { "smbios.version", "system.version" }, 907 }; 908 #endif 909 910 int 911 smbios_build(struct vmctx *ctx) 912 { 913 struct smbios_entry_point *smbios_ep; 914 uint16_t n; 915 uint16_t maxssize; 916 char *curaddr, *startaddr, *ststartaddr; 917 int i; 918 int err; 919 920 guest_lomem = vm_get_lowmem_size(ctx); 921 guest_himem = vm_get_highmem_size(ctx); 922 923 startaddr = paddr_guest2host(ctx, SMBIOS_BASE, SMBIOS_MAX_LENGTH); 924 if (startaddr == NULL) { 925 EPRINTLN("smbios table requires mapped mem"); 926 return (ENOMEM); 927 } 928 929 #ifndef __FreeBSD__ 930 /* Translate legacy illumos configuration keys */ 931 for (uint_t i = 0; i < ARRAY_SIZE(smbios_legacy_config_map); i++) { 932 const char *v; 933 934 v = get_config_value(smbios_legacy_config_map[i].oldkey); 935 if (v != NULL) { 936 set_config_value_if_unset( 937 smbios_legacy_config_map[i].newkey, v); 938 } 939 } 940 #endif 941 942 curaddr = startaddr; 943 944 smbios_ep = (struct smbios_entry_point *)curaddr; 945 smbios_ep_initializer(smbios_ep, SMBIOS_BASE + 946 sizeof(struct smbios_entry_point)); 947 curaddr += sizeof(struct smbios_entry_point); 948 ststartaddr = curaddr; 949 950 n = 0; 951 maxssize = 0; 952 for (i = 0; smbios_template[i].entry != NULL; i++) { 953 const struct smbios_structure *entry; 954 const struct smbios_string *strings; 955 initializer_func_t initializer; 956 char *endaddr; 957 size_t size; 958 959 entry = smbios_template[i].entry; 960 strings = smbios_template[i].strings; 961 initializer = smbios_template[i].initializer; 962 963 err = (*initializer)(entry, strings, curaddr, &endaddr, &n); 964 if (err != 0) 965 return (err); 966 967 size = endaddr - curaddr; 968 assert(size <= UINT16_MAX); 969 if (size > maxssize) 970 maxssize = (uint16_t)size; 971 curaddr = endaddr; 972 } 973 974 assert(curaddr - startaddr < SMBIOS_MAX_LENGTH); 975 smbios_ep_finalizer(smbios_ep, curaddr - ststartaddr, n, maxssize); 976 977 return (0); 978 } 979 980 #ifndef __FreeBSD__ 981 static struct { 982 uint_t type; 983 const char *key; 984 char *val; 985 } smbios_legacy_map[] = { 986 { 1, "product", "product_name" }, 987 { 1, "serial", "serial_number" }, 988 { 1, "family", "family_name" }, 989 }; 990 991 static const struct smbios_string *smbios_tbl_map[] = { 992 smbios_type0_strings, 993 smbios_type1_strings, 994 smbios_type2_strings, 995 smbios_type3_strings, 996 }; 997 998 /* 999 * This function accepts an option of the form 1000 * type,[key=value][,key=value]... 1001 * and sets smbios data for the given type. Keys for type X are defined in the 1002 * smbios_typeX_strings tables above, but for type 1 there are also some 1003 * legacy values which were accepted in earlier versions of bhyve on illumos 1004 * which need to be mapped. 1005 */ 1006 int 1007 smbios_parse(const char *opts) 1008 { 1009 char *buf, *lasts, *token, *typekey = NULL; 1010 const char *errstr; 1011 const struct smbios_string *tbl; 1012 nvlist_t *nvl; 1013 uint_t i; 1014 long type; 1015 1016 if ((buf = strdup(opts)) == NULL) { 1017 (void) fprintf(stderr, "out of memory\n"); 1018 return (-1); 1019 } 1020 1021 if ((token = strtok_r(buf, ",", &lasts)) == NULL) { 1022 (void) fprintf(stderr, "too few fields\n"); 1023 goto fail; 1024 } 1025 1026 type = strtonum(token, 0, 3, &errstr); 1027 if (errstr != NULL) { 1028 fprintf(stderr, "First token (type) is %s\n", errstr); 1029 goto fail; 1030 } 1031 1032 tbl = smbios_tbl_map[type]; 1033 1034 /* Extract the config key for this type */ 1035 typekey = strdup(tbl[0].node); 1036 if (typekey == NULL) { 1037 (void) fprintf(stderr, "out of memory\n"); 1038 goto fail; 1039 } 1040 1041 token = strchr(typekey, '.'); 1042 assert(token != NULL); 1043 *token = '\0'; 1044 1045 nvl = create_config_node(typekey); 1046 if (nvl == NULL) { 1047 (void) fprintf(stderr, "out of memory\n"); 1048 goto fail; 1049 } 1050 1051 while ((token = strtok_r(NULL, ",", &lasts)) != NULL) { 1052 char *val; 1053 1054 if ((val = strchr(token, '=')) == NULL || val[1] == '\0') { 1055 (void) fprintf(stderr, "invalid key=value: '%s'\n", 1056 token); 1057 goto fail; 1058 } 1059 *val++ = '\0'; 1060 1061 /* UUID is a top-level config item, but -U takes priority */ 1062 if (strcmp(token, "uuid") == 0) { 1063 set_config_value_if_unset(token, val); 1064 continue; 1065 } 1066 1067 /* Translate legacy keys */ 1068 for (i = 0; i < ARRAY_SIZE(smbios_legacy_map); i++) { 1069 if (type == smbios_legacy_map[i].type && 1070 strcmp(token, smbios_legacy_map[i].key) == 0) { 1071 token = smbios_legacy_map[i].val; 1072 break; 1073 } 1074 } 1075 1076 for (i = 0; tbl[i].value != NULL; i++) { 1077 if (strcmp(tbl[i].node + strlen(typekey) + 1, 1078 token) == 0) { 1079 /* Found match */ 1080 break; 1081 } 1082 } 1083 1084 if (tbl[i].value == NULL) { 1085 (void) fprintf(stderr, 1086 "Unknown SMBIOS key %s for type %d\n", token, type); 1087 goto fail; 1088 } 1089 1090 set_config_value_node(nvl, token, val); 1091 } 1092 1093 free(typekey); 1094 return (0); 1095 1096 fail: 1097 free(buf); 1098 free(typekey); 1099 return (-1); 1100 } 1101 #endif 1102