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