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