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