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