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