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