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