smbiostbl.c revision 270074
1214478Srpaulo/*- 217680Spst * Copyright (c) 2014 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com> 317680Spst * All rights reserved. 417680Spst * 517680Spst * Redistribution and use in source and binary forms, with or without 617680Spst * modification, are permitted provided that the following conditions 717680Spst * are met: 817680Spst * 1. Redistributions of source code must retain the above copyright 917680Spst * notice, this list of conditions and the following disclaimer. 1017680Spst * 2. Redistributions in binary form must reproduce the above copyright 1117680Spst * notice, this list of conditions and the following disclaimer in the 1217680Spst * documentation and/or other materials provided with the distribution. 1317680Spst * 1417680Spst * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND 1517680Spst * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1617680Spst * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1717680Spst * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 1817680Spst * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1917680Spst * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2017680Spst * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2117680Spst * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2217680Spst * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2317680Spst * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2475115Sfenner * SUCH DAMAGE. 2575115Sfenner */ 2675115Sfenner 2775115Sfenner#include <sys/cdefs.h> 2817680Spst__FBSDID("$FreeBSD: stable/10/usr.sbin/bhyve/smbiostbl.c 270074 2014-08-17 01:23:52Z grehan $"); 2975115Sfenner 30214478Srpaulo#include <sys/param.h> 31214478Srpaulo 3217680Spst#include <assert.h> 3317680Spst#include <errno.h> 3417680Spst#include <md5.h> 3517680Spst#include <stdio.h> 3675115Sfenner#include <string.h> 3775115Sfenner#include <unistd.h> 3875115Sfenner#include <uuid.h> 3975115Sfenner 40235530Sdelphij#include <machine/vmm.h> 4117680Spst#include <vmmapi.h> 4217680Spst 4317680Spst#include "bhyverun.h" 4417680Spst#include "smbiostbl.h" 4517680Spst 4617680Spst#define MB (1024*1024) 4717680Spst#define GB (1024ULL*1024*1024) 48127668Sbms 49127668Sbms#define SMBIOS_BASE 0xF1000 5017680Spst 5117680Spst/* BHYVE_ACPI_BASE - SMBIOS_BASE) */ 5217680Spst#define SMBIOS_MAX_LENGTH (0xF2400 - 0xF1000) 5317680Spst 5417680Spst#define SMBIOS_TYPE_BIOS 0 5517680Spst#define SMBIOS_TYPE_SYSTEM 1 5617680Spst#define SMBIOS_TYPE_CHASSIS 3 5717680Spst#define SMBIOS_TYPE_PROCESSOR 4 5817680Spst#define SMBIOS_TYPE_MEMARRAY 16 5917680Spst#define SMBIOS_TYPE_MEMDEVICE 17 6017680Spst#define SMBIOS_TYPE_MEMARRAYMAP 19 6117680Spst#define SMBIOS_TYPE_BOOT 32 6217680Spst#define SMBIOS_TYPE_EOT 127 6317680Spst 6417680Spststruct smbios_structure { 6517680Spst uint8_t type; 6617680Spst uint8_t length; 6717680Spst uint16_t handle; 6875115Sfenner} __packed; 6975115Sfenner 7075115Sfennertypedef int (*initializer_func_t)(struct smbios_structure *template_entry, 7175115Sfenner const char **template_strings, char *curaddr, char **endaddr, 7275115Sfenner uint16_t *n, uint16_t *size); 7375115Sfenner 7475115Sfennerstruct smbios_template_entry { 7575115Sfenner struct smbios_structure *entry; 7675115Sfenner const char **strings; 7775115Sfenner initializer_func_t initializer; 7875115Sfenner}; 7975115Sfenner 8075115Sfenner/* 8175115Sfenner * SMBIOS Structure Table Entry Point 8275115Sfenner */ 8317680Spst#define SMBIOS_ENTRY_EANCHOR "_SM_" 8475115Sfenner#define SMBIOS_ENTRY_EANCHORLEN 4 8575115Sfenner#define SMBIOS_ENTRY_IANCHOR "_DMI_" 8675115Sfenner#define SMBIOS_ENTRY_IANCHORLEN 5 8775115Sfenner 8875115Sfennerstruct smbios_entry_point { 8956893Sfenner char eanchor[4]; /* anchor tag */ 9075115Sfenner uint8_t echecksum; /* checksum of entry point structure */ 9175115Sfenner uint8_t eplen; /* length in bytes of entry point */ 9275115Sfenner uint8_t major; /* major version of the SMBIOS spec */ 9375115Sfenner uint8_t minor; /* minor version of the SMBIOS spec */ 9475115Sfenner uint16_t maxssize; /* maximum size in bytes of a struct */ 9575115Sfenner uint8_t revision; /* entry point structure revision */ 9675115Sfenner uint8_t format[5]; /* entry point rev-specific data */ 9775115Sfenner char ianchor[5]; /* intermediate anchor tag */ 9875115Sfenner uint8_t ichecksum; /* intermediate checksum */ 9975115Sfenner uint16_t stlen; /* len in bytes of structure table */ 10075115Sfenner uint32_t staddr; /* physical addr of structure table */ 10175115Sfenner uint16_t stnum; /* number of structure table entries */ 10275115Sfenner uint8_t bcdrev; /* BCD value representing DMI ver */ 10375115Sfenner} __packed; 10475115Sfenner 10575115Sfenner/* 10675115Sfenner * BIOS Information 10775115Sfenner */ 10875115Sfenner#define SMBIOS_FL_ISA 0x00000010 /* ISA is supported */ 10975115Sfenner#define SMBIOS_FL_PCI 0x00000080 /* PCI is supported */ 11075115Sfenner#define SMBIOS_FL_SHADOW 0x00001000 /* BIOS shadowing is allowed */ 11175115Sfenner#define SMBIOS_FL_CDBOOT 0x00008000 /* Boot from CD is supported */ 11275115Sfenner#define SMBIOS_FL_SELBOOT 0x00010000 /* Selectable Boot supported */ 11375115Sfenner#define SMBIOS_FL_EDD 0x00080000 /* EDD Spec is supported */ 11475115Sfenner 11575115Sfenner#define SMBIOS_XB1_FL_ACPI 0x00000001 /* ACPI is supported */ 11675115Sfenner 11775115Sfenner#define SMBIOS_XB2_FL_BBS 0x00000001 /* BIOS Boot Specification */ 11875115Sfenner#define SMBIOS_XB2_FL_VM 0x00000010 /* Virtual Machine */ 11975115Sfenner 12075115Sfennerstruct smbios_table_type0 { 12175115Sfenner struct smbios_structure header; 12275115Sfenner uint8_t vendor; /* vendor string */ 12375115Sfenner uint8_t version; /* version string */ 12475115Sfenner uint16_t segment; /* address segment location */ 12575115Sfenner uint8_t rel_date; /* release date */ 12675115Sfenner uint8_t size; /* rom size */ 12775115Sfenner uint64_t cflags; /* characteristics */ 12875115Sfenner uint8_t xc_bytes[2]; /* characteristics ext bytes */ 12975115Sfenner uint8_t sb_major_rel; /* system bios version */ 13075115Sfenner uint8_t sb_minor_rele; 13175115Sfenner uint8_t ecfw_major_rel; /* embedded ctrl fw version */ 13256893Sfenner uint8_t ecfw_minor_rel; 13375115Sfenner} __packed; 13475115Sfenner 13575115Sfenner/* 13675115Sfenner * System Information 13775115Sfenner */ 13875115Sfenner#define SMBIOS_WAKEUP_SWITCH 0x06 /* power switch */ 13975115Sfenner 14075115Sfennerstruct smbios_table_type1 { 14175115Sfenner struct smbios_structure header; 14275115Sfenner uint8_t manufacturer; /* manufacturer string */ 14375115Sfenner uint8_t product; /* product name string */ 14475115Sfenner uint8_t version; /* version string */ 14575115Sfenner uint8_t serial; /* serial number string */ 14675115Sfenner uint8_t uuid[16]; /* uuid byte array */ 14775115Sfenner uint8_t wakeup; /* wake-up event */ 14875115Sfenner uint8_t sku; /* sku number string */ 14975115Sfenner uint8_t family; /* family name string */ 15075115Sfenner} __packed; 15198524Sfenner 15298524Sfenner/* 15398524Sfenner * System Enclosure or Chassis 15475115Sfenner */ 15575115Sfenner#define SMBIOS_CHT_UNKNOWN 0x02 /* unknown */ 15675115Sfenner 15775115Sfenner#define SMBIOS_CHST_SAFE 0x03 /* safe */ 15875115Sfenner 15975115Sfenner#define SMBIOS_CHSC_NONE 0x03 /* none */ 16075115Sfenner 16175115Sfennerstruct smbios_table_type3 { 16275115Sfenner struct smbios_structure header; 16375115Sfenner uint8_t manufacturer; /* manufacturer string */ 16475115Sfenner uint8_t type; /* type */ 165172683Smlaier uint8_t version; /* version string */ 166172683Smlaier uint8_t serial; /* serial number string */ 167172683Smlaier uint8_t asset; /* asset tag string */ 16875115Sfenner uint8_t bustate; /* boot-up state */ 16975115Sfenner uint8_t psstate; /* power supply state */ 17075115Sfenner uint8_t tstate; /* thermal state */ 17175115Sfenner uint8_t security; /* security status */ 17275115Sfenner uint8_t uheight; /* height in 'u's */ 17375115Sfenner uint8_t cords; /* number of power cords */ 17475115Sfenner uint8_t elems; /* number of element records */ 17575115Sfenner uint8_t elemlen; /* length of records */ 17675115Sfenner uint8_t sku; /* sku number string */ 17775115Sfenner} __packed; 17875115Sfenner 17975115Sfenner/* 18075115Sfenner * Processor Information 18175115Sfenner */ 18275115Sfenner#define SMBIOS_PRT_CENTRAL 0x03 /* central processor */ 18375115Sfenner 18475115Sfenner#define SMBIOS_PRF_OTHER 0x01 /* other */ 18575115Sfenner 18675115Sfenner#define SMBIOS_PRS_PRESENT 0x40 /* socket is populated */ 18775115Sfenner#define SMBIOS_PRS_ENABLED 0x1 /* enabled */ 18875115Sfenner 18975115Sfenner#define SMBIOS_PRU_NONE 0x06 /* none */ 19075115Sfenner 19175115Sfenner#define SMBIOS_PFL_64B 0x04 /* 64-bit capable */ 19275115Sfenner 19375115Sfennerstruct smbios_table_type4 { 19417680Spst struct smbios_structure header; 19575115Sfenner uint8_t socket; /* socket designation string */ 19656893Sfenner uint8_t type; /* processor type */ 19756893Sfenner uint8_t family; /* processor family */ 19856893Sfenner uint8_t manufacturer; /* manufacturer string */ 19956893Sfenner uint64_t cpuid; /* processor cpuid */ 20056893Sfenner uint8_t version; /* version string */ 20156893Sfenner uint8_t voltage; /* voltage */ 20256893Sfenner uint16_t clkspeed; /* ext clock speed in mhz */ 20356893Sfenner uint16_t maxspeed; /* maximum speed in mhz */ 20456893Sfenner uint16_t curspeed; /* current speed in mhz */ 20517680Spst uint8_t status; /* status */ 20617680Spst uint8_t upgrade; /* upgrade */ 20717680Spst uint16_t l1handle; /* l1 cache handle */ 20817680Spst uint16_t l2handle; /* l2 cache handle */ 20917680Spst uint16_t l3handle; /* l3 cache handle */ 21017680Spst uint8_t serial; /* serial number string */ 21117680Spst uint8_t asset; /* asset tag string */ 21275115Sfenner uint8_t part; /* part number string */ 21317680Spst uint8_t cores; /* cores per socket */ 21417680Spst uint8_t ecores; /* enabled cores */ 21517680Spst uint8_t threads; /* threads per socket */ 21617680Spst uint16_t cflags; /* processor characteristics */ 21717680Spst uint16_t family2; /* processor family 2 */ 21817680Spst} __packed; 21975115Sfenner 220235530Sdelphij/* 22117680Spst * Physical Memory Array 22217680Spst */ 22317680Spst#define SMBIOS_MAL_SYSMB 0x03 /* system board or motherboard */ 22417680Spst 225172683Smlaier#define SMBIOS_MAU_SYSTEM 0x03 /* system memory */ 226172683Smlaier 227172683Smlaier#define SMBIOS_MAE_NONE 0x03 /* none */ 228172683Smlaier 229172683Smlaierstruct smbios_table_type16 { 230172683Smlaier struct smbios_structure header; 231172683Smlaier 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 249struct 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 */ 278struct 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 293struct 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 */ 302struct smbios_table_type127 { 303 struct smbios_structure header; 304} __packed; 305 306struct 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 322const char *smbios_type0_strings[] = { 323 "BHYVE", /* vendor string */ 324 __TIME__, /* bios version string */ 325 __DATE__, /* bios release date string */ 326 NULL 327}; 328 329struct 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 341static 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 345const 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 355struct 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 373const 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 382struct 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 409const 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 419static 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 423struct 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 434static 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 438struct 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 464const 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 474static 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 478struct 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 488static 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 492struct 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 498struct smbios_table_type127 smbios_type127_template = { 499 { SMBIOS_TYPE_EOT, sizeof (struct smbios_table_type127), 0 } 500}; 501 502static 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 506static 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 537static uint64_t guest_lomem, guest_himem; 538static uint16_t type16_handle; 539 540static int 541smbios_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 578static int 579smbios_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 630static int 631smbios_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 662static int 663smbios_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 679static int 680smbios_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 704static int 705smbios_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 731static void 732smbios_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 = 4; 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 748static void 749smbios_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 772int 773smbios_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