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)(struct smbios_structure *template_entry, 90 struct smbios_string *template_strings, char *curaddr, char **endaddr, 91 uint16_t *n, uint16_t *size); 92 93 struct smbios_template_entry { 94 struct smbios_structure *entry; 95 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 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 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 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(struct smbios_structure *template_entry, 383 struct smbios_string *template_strings, char *curaddr, char **endaddr, 384 uint16_t *n, uint16_t *size); 385 386 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 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 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 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 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 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 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(struct smbios_structure *template_entry, 486 struct smbios_string *template_strings, char *curaddr, char **endaddr, 487 uint16_t *n, uint16_t *size); 488 489 struct smbios_table_type16 smbios_type16_template = { 490 { SMBIOS_TYPE_MEMARRAY, sizeof (struct smbios_table_type16), 0 }, 491 SMBIOS_MAL_SYSMB, 492 SMBIOS_MAU_SYSTEM, 493 SMBIOS_MAE_NONE, 494 0x80000000, /* max mem capacity in kb (0x80000000=use extended) */ 495 -1, /* handle of error (if any) */ 496 0, /* number of slots or sockets (TBD) */ 497 0 /* extended maximum memory capacity in bytes (TBD) */ 498 }; 499 500 static int smbios_type16_initializer(struct smbios_structure *template_entry, 501 struct smbios_string *template_strings, char *curaddr, char **endaddr, 502 uint16_t *n, uint16_t *size); 503 504 struct smbios_table_type17 smbios_type17_template = { 505 { SMBIOS_TYPE_MEMDEVICE, sizeof (struct smbios_table_type17), 0 }, 506 -1, /* handle of physical memory array */ 507 -1, /* handle of memory error data */ 508 64, /* total width in bits including ecc */ 509 64, /* data width in bits */ 510 0, /* size in kb or mb (0x7fff=use extended)*/ 511 SMBIOS_MDFF_UNKNOWN, 512 0, /* set (0x00=none, 0xff=unknown) */ 513 1, /* device locator string */ 514 2, /* physical bank locator string */ 515 SMBIOS_MDT_UNKNOWN, 516 SMBIOS_MDF_UNKNOWN, 517 0, /* maximum memory speed in mhz (0=unknown) */ 518 3, /* manufacturer string */ 519 4, /* serial number string */ 520 5, /* asset tag string */ 521 6, /* part number string */ 522 0, /* attributes (0=unknown rank information) */ 523 0, /* extended size in mb (TBD) */ 524 0, /* current speed in mhz (0=unknown) */ 525 0, /* minimum voltage in mv (0=unknown) */ 526 0, /* maximum voltage in mv (0=unknown) */ 527 0 /* configured voltage in mv (0=unknown) */ 528 }; 529 530 struct smbios_string smbios_type17_strings[] = { 531 { NULL, " " }, /* device locator string */ 532 { NULL, " " }, /* physical bank locator string */ 533 { NULL, " " }, /* manufacturer string */ 534 { NULL, "None" }, /* serial number string */ 535 { NULL, "None" }, /* asset tag string */ 536 { NULL, "None" }, /* part number string */ 537 { 0 } 538 }; 539 540 static int smbios_type17_initializer(struct smbios_structure *template_entry, 541 struct smbios_string *template_strings, char *curaddr, char **endaddr, 542 uint16_t *n, uint16_t *size); 543 544 struct smbios_table_type19 smbios_type19_template = { 545 { SMBIOS_TYPE_MEMARRAYMAP, sizeof (struct smbios_table_type19), 0 }, 546 0xffffffff, /* starting phys addr in kb (0xffffffff=use ext) */ 547 0xffffffff, /* ending phys addr in kb (0xffffffff=use ext) */ 548 -1, /* physical memory array handle */ 549 1, /* number of devices that form a row */ 550 0, /* extended starting phys addr in bytes (TDB) */ 551 0 /* extended ending phys addr in bytes (TDB) */ 552 }; 553 554 static int smbios_type19_initializer(struct smbios_structure *template_entry, 555 struct smbios_string *template_strings, char *curaddr, char **endaddr, 556 uint16_t *n, uint16_t *size); 557 558 struct smbios_table_type32 smbios_type32_template = { 559 { SMBIOS_TYPE_BOOT, sizeof (struct smbios_table_type32), 0 }, 560 { 0, 0, 0, 0, 0, 0 }, 561 SMBIOS_BOOT_NORMAL 562 }; 563 564 struct smbios_table_type127 smbios_type127_template = { 565 { SMBIOS_TYPE_EOT, sizeof (struct smbios_table_type127), 0 } 566 }; 567 568 static int smbios_generic_initializer(struct smbios_structure *template_entry, 569 struct smbios_string *template_strings, char *curaddr, char **endaddr, 570 uint16_t *n, uint16_t *size); 571 572 static struct smbios_template_entry smbios_template[] = { 573 { (struct smbios_structure *)&smbios_type0_template, 574 smbios_type0_strings, 575 smbios_generic_initializer }, 576 { (struct smbios_structure *)&smbios_type1_template, 577 smbios_type1_strings, 578 smbios_type1_initializer }, 579 { (struct smbios_structure *)&smbios_type2_template, 580 smbios_type2_strings, 581 smbios_generic_initializer }, 582 { (struct smbios_structure *)&smbios_type3_template, 583 smbios_type3_strings, 584 smbios_generic_initializer }, 585 { (struct smbios_structure *)&smbios_type4_template, 586 smbios_type4_strings, 587 smbios_type4_initializer }, 588 { (struct smbios_structure *)&smbios_type16_template, 589 NULL, 590 smbios_type16_initializer }, 591 { (struct smbios_structure *)&smbios_type17_template, 592 smbios_type17_strings, 593 smbios_type17_initializer }, 594 { (struct smbios_structure *)&smbios_type19_template, 595 NULL, 596 smbios_type19_initializer }, 597 { (struct smbios_structure *)&smbios_type32_template, 598 NULL, 599 smbios_generic_initializer }, 600 { (struct smbios_structure *)&smbios_type127_template, 601 NULL, 602 smbios_generic_initializer }, 603 { NULL,NULL, NULL } 604 }; 605 606 static uint64_t guest_lomem, guest_himem; 607 static uint16_t type16_handle; 608 609 static int 610 smbios_generic_initializer(struct smbios_structure *template_entry, 611 struct smbios_string *template_strings, char *curaddr, char **endaddr, 612 uint16_t *n, uint16_t *size) 613 { 614 struct smbios_structure *entry; 615 616 memcpy(curaddr, template_entry, template_entry->length); 617 entry = (struct smbios_structure *)curaddr; 618 entry->handle = *n + 1; 619 curaddr += entry->length; 620 if (template_strings != NULL) { 621 int i; 622 623 for (i = 0; template_strings[i].value != NULL; i++) { 624 const char *string; 625 int len; 626 627 if (template_strings[i].node == NULL) { 628 string = template_strings[i].value; 629 } else { 630 set_config_value_if_unset( 631 template_strings[i].node, 632 template_strings[i].value); 633 string = get_config_value( 634 template_strings[i].node); 635 } 636 637 len = strlen(string) + 1; 638 memcpy(curaddr, string, len); 639 curaddr += len; 640 } 641 *curaddr = '\0'; 642 curaddr++; 643 } else { 644 /* Minimum string section is double nul */ 645 *curaddr = '\0'; 646 curaddr++; 647 *curaddr = '\0'; 648 curaddr++; 649 } 650 (*n)++; 651 *endaddr = curaddr; 652 653 return (0); 654 } 655 656 static int 657 smbios_type1_initializer(struct smbios_structure *template_entry, 658 struct smbios_string *template_strings, char *curaddr, char **endaddr, 659 uint16_t *n, uint16_t *size) 660 { 661 struct smbios_table_type1 *type1; 662 const char *guest_uuid_str; 663 664 smbios_generic_initializer(template_entry, template_strings, 665 curaddr, endaddr, n, size); 666 type1 = (struct smbios_table_type1 *)curaddr; 667 668 guest_uuid_str = get_config_value("uuid"); 669 if (guest_uuid_str != NULL) { 670 uuid_t uuid; 671 uint32_t status; 672 673 uuid_from_string(guest_uuid_str, &uuid, &status); 674 if (status != uuid_s_ok) { 675 EPRINTLN("Invalid UUID"); 676 return (-1); 677 } 678 679 uuid_enc_le(&type1->uuid, &uuid); 680 } else { 681 MD5_CTX mdctx; 682 u_char digest[16]; 683 char hostname[MAXHOSTNAMELEN]; 684 const char *vmname; 685 686 /* 687 * Universally unique and yet reproducible are an 688 * oxymoron, however reproducible is desirable in 689 * this case. 690 */ 691 if (gethostname(hostname, sizeof(hostname))) 692 return (-1); 693 694 MD5Init(&mdctx); 695 vmname = get_config_value("name"); 696 MD5Update(&mdctx, vmname, strlen(vmname)); 697 MD5Update(&mdctx, hostname, sizeof(hostname)); 698 MD5Final(digest, &mdctx); 699 700 /* 701 * Set the variant and version number. 702 */ 703 digest[6] &= 0x0F; 704 digest[6] |= 0x30; /* version 3 */ 705 digest[8] &= 0x3F; 706 digest[8] |= 0x80; 707 708 memcpy(&type1->uuid, digest, sizeof (digest)); 709 } 710 711 return (0); 712 } 713 714 static int 715 smbios_type4_initializer(struct smbios_structure *template_entry, 716 struct smbios_string *template_strings, char *curaddr, char **endaddr, 717 uint16_t *n, uint16_t *size) 718 { 719 int i; 720 721 for (i = 0; i < sockets; i++) { 722 struct smbios_table_type4 *type4; 723 char *p; 724 int nstrings, len; 725 726 smbios_generic_initializer(template_entry, template_strings, 727 curaddr, endaddr, n, size); 728 type4 = (struct smbios_table_type4 *)curaddr; 729 p = curaddr + sizeof (struct smbios_table_type4); 730 nstrings = 0; 731 while (p < *endaddr - 1) { 732 if (*p++ == '\0') 733 nstrings++; 734 } 735 len = sprintf(*endaddr - 1, "CPU #%d", i) + 1; 736 *endaddr += len - 1; 737 *(*endaddr) = '\0'; 738 (*endaddr)++; 739 type4->socket = nstrings + 1; 740 /* Revise cores and threads after update to smbios 3.0 */ 741 if (cores > 254) 742 type4->cores = 0; 743 else 744 type4->cores = cores; 745 /* This threads is total threads in a socket */ 746 if ((cores * threads) > 254) 747 type4->threads = 0; 748 else 749 type4->threads = (cores * threads); 750 curaddr = *endaddr; 751 } 752 753 return (0); 754 } 755 756 static int 757 smbios_type16_initializer(struct smbios_structure *template_entry, 758 struct smbios_string *template_strings, char *curaddr, char **endaddr, 759 uint16_t *n, uint16_t *size) 760 { 761 struct smbios_table_type16 *type16; 762 763 type16_handle = *n; 764 smbios_generic_initializer(template_entry, template_strings, 765 curaddr, endaddr, n, size); 766 type16 = (struct smbios_table_type16 *)curaddr; 767 type16->xsize = guest_lomem + guest_himem; 768 type16->ndevs = guest_himem > 0 ? 2 : 1; 769 770 return (0); 771 } 772 773 static int 774 smbios_type17_initializer(struct smbios_structure *template_entry, 775 struct smbios_string *template_strings, char *curaddr, char **endaddr, 776 uint16_t *n, uint16_t *size) 777 { 778 struct smbios_table_type17 *type17; 779 uint64_t memsize, size_KB, size_MB; 780 781 smbios_generic_initializer(template_entry, template_strings, 782 curaddr, endaddr, n, size); 783 type17 = (struct smbios_table_type17 *)curaddr; 784 type17->arrayhand = type16_handle; 785 786 memsize = guest_lomem + guest_himem; 787 size_KB = memsize / 1024; 788 size_MB = memsize / MB; 789 790 /* A single Type 17 entry can't represent more than ~2PB RAM */ 791 if (size_MB > 0x7FFFFFFF) { 792 printf("Warning: guest memory too big for SMBIOS Type 17 table: " 793 "%luMB greater than max supported 2147483647MB\n", size_MB); 794 795 size_MB = 0x7FFFFFFF; 796 } 797 798 /* See SMBIOS 2.7.0 section 7.18 - Memory Device (Type 17) */ 799 if (size_KB <= 0x7FFF) { 800 /* Can represent up to 32767KB with the top bit set */ 801 type17->size = size_KB | (1 << 15); 802 } else if (size_MB < 0x7FFF) { 803 /* Can represent up to 32766MB with the top bit unset */ 804 type17->size = size_MB & 0x7FFF; 805 } else { 806 type17->size = 0x7FFF; 807 /* 808 * Can represent up to 2147483647MB (~2PB) 809 * The top bit is reserved 810 */ 811 type17->xsize = size_MB & 0x7FFFFFFF; 812 } 813 814 return (0); 815 } 816 817 static int 818 smbios_type19_initializer(struct smbios_structure *template_entry, 819 struct smbios_string *template_strings, char *curaddr, char **endaddr, 820 uint16_t *n, uint16_t *size) 821 { 822 struct smbios_table_type19 *type19; 823 824 smbios_generic_initializer(template_entry, template_strings, 825 curaddr, endaddr, n, size); 826 type19 = (struct smbios_table_type19 *)curaddr; 827 type19->arrayhand = type16_handle; 828 type19->xsaddr = 0; 829 type19->xeaddr = guest_lomem; 830 831 if (guest_himem > 0) { 832 curaddr = *endaddr; 833 smbios_generic_initializer(template_entry, template_strings, 834 curaddr, endaddr, n, size); 835 type19 = (struct smbios_table_type19 *)curaddr; 836 type19->arrayhand = type16_handle; 837 type19->xsaddr = 4*GB; 838 type19->xeaddr = type19->xsaddr + guest_himem; 839 } 840 841 return (0); 842 } 843 844 static void 845 smbios_ep_initializer(struct smbios_entry_point *smbios_ep, uint32_t staddr) 846 { 847 memset(smbios_ep, 0, sizeof(*smbios_ep)); 848 memcpy(smbios_ep->eanchor, SMBIOS_ENTRY_EANCHOR, 849 SMBIOS_ENTRY_EANCHORLEN); 850 smbios_ep->eplen = 0x1F; 851 assert(sizeof (struct smbios_entry_point) == smbios_ep->eplen); 852 smbios_ep->major = 2; 853 smbios_ep->minor = 6; 854 smbios_ep->revision = 0; 855 memcpy(smbios_ep->ianchor, SMBIOS_ENTRY_IANCHOR, 856 SMBIOS_ENTRY_IANCHORLEN); 857 smbios_ep->staddr = staddr; 858 smbios_ep->bcdrev = (smbios_ep->major & 0xf) << 4 | (smbios_ep->minor & 0xf); 859 } 860 861 static void 862 smbios_ep_finalizer(struct smbios_entry_point *smbios_ep, uint16_t len, 863 uint16_t num, uint16_t maxssize) 864 { 865 uint8_t checksum; 866 int i; 867 868 smbios_ep->maxssize = maxssize; 869 smbios_ep->stlen = len; 870 smbios_ep->stnum = num; 871 872 checksum = 0; 873 for (i = 0x10; i < 0x1f; i++) { 874 checksum -= ((uint8_t *)smbios_ep)[i]; 875 } 876 smbios_ep->ichecksum = checksum; 877 878 checksum = 0; 879 for (i = 0; i < 0x1f; i++) { 880 checksum -= ((uint8_t *)smbios_ep)[i]; 881 } 882 smbios_ep->echecksum = checksum; 883 } 884 885 #ifndef __FreeBSD__ 886 /* 887 * bhyve on illumos previously used configuration keys starting with 'smbios.' 888 * to control type 1 SMBIOS information. Since these may still be present in 889 * bhyve configuration files, the following table is used to translate them 890 * to their new key names. 891 */ 892 static struct { 893 const char *oldkey; 894 const char *newkey; 895 } smbios_legacy_config_map[] = { 896 { "smbios.manufacturer", "system.manufacturer" }, 897 { "smbios.family", "system.family_name" }, 898 { "smbios.product", "system.product_name" }, 899 { "smbios.serial", "system.serial_number" }, 900 { "smbios.sku", "system.sku" }, 901 { "smbios.version", "system.version" }, 902 }; 903 #endif 904 905 int 906 smbios_build(struct vmctx *ctx) 907 { 908 struct smbios_entry_point *smbios_ep; 909 uint16_t n; 910 uint16_t maxssize; 911 char *curaddr, *startaddr, *ststartaddr; 912 int i; 913 int err; 914 915 guest_lomem = vm_get_lowmem_size(ctx); 916 guest_himem = vm_get_highmem_size(ctx); 917 918 startaddr = paddr_guest2host(ctx, SMBIOS_BASE, SMBIOS_MAX_LENGTH); 919 if (startaddr == NULL) { 920 EPRINTLN("smbios table requires mapped mem"); 921 return (ENOMEM); 922 } 923 924 #ifndef __FreeBSD__ 925 /* Translate legacy illumos configuration keys */ 926 for (uint_t i = 0; i < ARRAY_SIZE(smbios_legacy_config_map); i++) { 927 const char *v; 928 929 v = get_config_value(smbios_legacy_config_map[i].oldkey); 930 if (v != NULL) { 931 set_config_value_if_unset( 932 smbios_legacy_config_map[i].newkey, v); 933 } 934 } 935 #endif 936 937 curaddr = startaddr; 938 939 smbios_ep = (struct smbios_entry_point *)curaddr; 940 smbios_ep_initializer(smbios_ep, SMBIOS_BASE + 941 sizeof(struct smbios_entry_point)); 942 curaddr += sizeof(struct smbios_entry_point); 943 ststartaddr = curaddr; 944 945 n = 0; 946 maxssize = 0; 947 for (i = 0; smbios_template[i].entry != NULL; i++) { 948 struct smbios_structure *entry; 949 struct smbios_string *strings; 950 initializer_func_t initializer; 951 char *endaddr; 952 uint16_t size; 953 954 entry = smbios_template[i].entry; 955 strings = smbios_template[i].strings; 956 initializer = smbios_template[i].initializer; 957 958 err = (*initializer)(entry, strings, curaddr, &endaddr, 959 &n, &size); 960 if (err != 0) 961 return (err); 962 963 if (size > maxssize) 964 maxssize = size; 965 966 curaddr = endaddr; 967 } 968 969 assert(curaddr - startaddr < SMBIOS_MAX_LENGTH); 970 smbios_ep_finalizer(smbios_ep, curaddr - ststartaddr, n, maxssize); 971 972 return (0); 973 } 974 975 #ifndef __FreeBSD__ 976 static struct { 977 uint_t type; 978 const char *key; 979 char *val; 980 } smbios_legacy_map[] = { 981 { 1, "product", "product_name" }, 982 { 1, "serial", "serial_number" }, 983 { 1, "family", "family_name" }, 984 }; 985 986 static struct smbios_string *smbios_tbl_map[] = { 987 smbios_type0_strings, 988 smbios_type1_strings, 989 smbios_type2_strings, 990 smbios_type3_strings, 991 }; 992 993 /* 994 * This function accepts an option of the form 995 * type,[key=value][,key=value]... 996 * and sets smbios data for the given type. Keys for type X are defined in the 997 * smbios_typeX_strings tables above, but for type 1 there are also some 998 * legacy values which were accepted in earlier versions of bhyve on illumos 999 * which need to be mapped. 1000 */ 1001 int 1002 smbios_parse(const char *opts) 1003 { 1004 char *buf, *lasts, *token, *typekey = NULL; 1005 const char *errstr; 1006 struct smbios_string *tbl; 1007 nvlist_t *nvl; 1008 uint_t i; 1009 long type; 1010 1011 if ((buf = strdup(opts)) == NULL) { 1012 (void) fprintf(stderr, "out of memory\n"); 1013 return (-1); 1014 } 1015 1016 if ((token = strtok_r(buf, ",", &lasts)) == NULL) { 1017 (void) fprintf(stderr, "too few fields\n"); 1018 goto fail; 1019 } 1020 1021 type = strtonum(token, 0, 3, &errstr); 1022 if (errstr != NULL) { 1023 fprintf(stderr, "First token (type) is %s\n", errstr); 1024 goto fail; 1025 } 1026 1027 tbl = smbios_tbl_map[type]; 1028 1029 /* Extract the config key for this type */ 1030 typekey = strdup(tbl[0].node); 1031 if (typekey == NULL) { 1032 (void) fprintf(stderr, "out of memory\n"); 1033 goto fail; 1034 } 1035 1036 token = strchr(typekey, '.'); 1037 assert(token != NULL); 1038 *token = '\0'; 1039 1040 nvl = create_config_node(typekey); 1041 if (nvl == NULL) { 1042 (void) fprintf(stderr, "out of memory\n"); 1043 goto fail; 1044 } 1045 1046 while ((token = strtok_r(NULL, ",", &lasts)) != NULL) { 1047 char *val; 1048 1049 if ((val = strchr(token, '=')) == NULL || val[1] == '\0') { 1050 (void) fprintf(stderr, "invalid key=value: '%s'\n", 1051 token); 1052 goto fail; 1053 } 1054 *val++ = '\0'; 1055 1056 /* UUID is a top-level config item, but -U takes priority */ 1057 if (strcmp(token, "uuid") == 0) { 1058 set_config_value_if_unset(token, val); 1059 continue; 1060 } 1061 1062 /* Translate legacy keys */ 1063 for (i = 0; i < ARRAY_SIZE(smbios_legacy_map); i++) { 1064 if (type == smbios_legacy_map[i].type && 1065 strcmp(token, smbios_legacy_map[i].key) == 0) { 1066 token = smbios_legacy_map[i].val; 1067 break; 1068 } 1069 } 1070 1071 for (i = 0; tbl[i].value != NULL; i++) { 1072 if (strcmp(tbl[i].node + strlen(typekey) + 1, 1073 token) == 0) { 1074 /* Found match */ 1075 break; 1076 } 1077 } 1078 1079 if (tbl[i].value == NULL) { 1080 (void) fprintf(stderr, 1081 "Unknown SMBIOS key %s for type %d\n", token, type); 1082 goto fail; 1083 } 1084 1085 set_config_value_node(nvl, token, val); 1086 } 1087 1088 free(typekey); 1089 return (0); 1090 1091 fail: 1092 free(buf); 1093 free(typekey); 1094 return (-1); 1095 } 1096 #endif 1097