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