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