2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2014 Tycho Nightingale <tycho.nightingale@pluribusnetworks.com>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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.
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
29 #include <sys/cdefs.h>
30 __FBSDID("$FreeBSD$");
32 #include <sys/param.h>
42 #include <machine/vmm.h>
48 #include "smbiostbl.h"
50 #define MB (1024*1024)
51 #define GB (1024ULL*1024*1024)
53 #define SMBIOS_BASE 0xF1000
55 #define FIRMWARE_VERSION "14.0"
56 /* The SMBIOS specification defines the date format to be mm/dd/yyyy */
57 #define FIRMWARE_RELEASE_DATE "10/17/2021"
59 /* BHYVE_ACPI_BASE - SMBIOS_BASE) */
60 #define SMBIOS_MAX_LENGTH (0xF2400 - 0xF1000)
62 #define SMBIOS_TYPE_BIOS 0
63 #define SMBIOS_TYPE_SYSTEM 1
64 #define SMBIOS_TYPE_BOARD 2
65 #define SMBIOS_TYPE_CHASSIS 3
66 #define SMBIOS_TYPE_PROCESSOR 4
67 #define SMBIOS_TYPE_MEMARRAY 16
68 #define SMBIOS_TYPE_MEMDEVICE 17
69 #define SMBIOS_TYPE_MEMARRAYMAP 19
70 #define SMBIOS_TYPE_BOOT 32
71 #define SMBIOS_TYPE_EOT 127
73 struct smbios_structure {
79 struct smbios_string {
84 typedef int (*initializer_func_t)(struct smbios_structure *template_entry,
85 struct smbios_string *template_strings, char *curaddr, char **endaddr,
86 uint16_t *n, uint16_t *size);
88 struct smbios_template_entry {
89 struct smbios_structure *entry;
90 struct smbios_string *strings;
91 initializer_func_t initializer;
95 * SMBIOS Structure Table Entry Point
97 #define SMBIOS_ENTRY_EANCHOR "_SM_"
98 #define SMBIOS_ENTRY_EANCHORLEN 4
99 #define SMBIOS_ENTRY_IANCHOR "_DMI_"
100 #define SMBIOS_ENTRY_IANCHORLEN 5
102 struct smbios_entry_point {
103 char eanchor[4]; /* anchor tag */
104 uint8_t echecksum; /* checksum of entry point structure */
105 uint8_t eplen; /* length in bytes of entry point */
106 uint8_t major; /* major version of the SMBIOS spec */
107 uint8_t minor; /* minor version of the SMBIOS spec */
108 uint16_t maxssize; /* maximum size in bytes of a struct */
109 uint8_t revision; /* entry point structure revision */
110 uint8_t format[5]; /* entry point rev-specific data */
111 char ianchor[5]; /* intermediate anchor tag */
112 uint8_t ichecksum; /* intermediate checksum */
113 uint16_t stlen; /* len in bytes of structure table */
114 uint32_t staddr; /* physical addr of structure table */
115 uint16_t stnum; /* number of structure table entries */
116 uint8_t bcdrev; /* BCD value representing DMI ver */
122 #define SMBIOS_FL_ISA 0x00000010 /* ISA is supported */
123 #define SMBIOS_FL_PCI 0x00000080 /* PCI is supported */
124 #define SMBIOS_FL_SHADOW 0x00001000 /* BIOS shadowing is allowed */
125 #define SMBIOS_FL_CDBOOT 0x00008000 /* Boot from CD is supported */
126 #define SMBIOS_FL_SELBOOT 0x00010000 /* Selectable Boot supported */
127 #define SMBIOS_FL_EDD 0x00080000 /* EDD Spec is supported */
129 #define SMBIOS_XB1_FL_ACPI 0x00000001 /* ACPI is supported */
131 #define SMBIOS_XB2_FL_BBS 0x00000001 /* BIOS Boot Specification */
132 #define SMBIOS_XB2_FL_VM 0x00000010 /* Virtual Machine */
134 struct smbios_table_type0 {
135 struct smbios_structure header;
136 uint8_t vendor; /* vendor string */
137 uint8_t version; /* version string */
138 uint16_t segment; /* address segment location */
139 uint8_t rel_date; /* release date */
140 uint8_t size; /* rom size */
141 uint64_t cflags; /* characteristics */
142 uint8_t xc_bytes[2]; /* characteristics ext bytes */
143 uint8_t sb_major_rel; /* system bios version */
144 uint8_t sb_minor_rele;
145 uint8_t ecfw_major_rel; /* embedded ctrl fw version */
146 uint8_t ecfw_minor_rel;
152 #define SMBIOS_WAKEUP_SWITCH 0x06 /* power switch */
154 struct smbios_table_type1 {
155 struct smbios_structure header;
156 uint8_t manufacturer; /* manufacturer string */
157 uint8_t product; /* product name string */
158 uint8_t version; /* version string */
159 uint8_t serial; /* serial number string */
160 uint8_t uuid[16]; /* uuid byte array */
161 uint8_t wakeup; /* wake-up event */
162 uint8_t sku; /* sku number string */
163 uint8_t family; /* family name string */
167 * Baseboard (or Module) Information
169 #define SMBIOS_BRF_HOSTING 0x1
170 #define SMBIOS_BRT_MOTHERBOARD 0xa
172 struct smbios_table_type2 {
173 struct smbios_structure header;
174 uint8_t manufacturer; /* manufacturer string */
175 uint8_t product; /* product name string */
176 uint8_t version; /* version string */
177 uint8_t serial; /* serial number string */
178 uint8_t asset; /* asset tag string */
179 uint8_t fflags; /* feature flags */
180 uint8_t location; /* location in chassis */
181 uint16_t chandle; /* chassis handle */
182 uint8_t type; /* board type */
183 uint8_t n_objs; /* number of contained object handles */
187 * System Enclosure or Chassis
189 #define SMBIOS_CHT_UNKNOWN 0x02 /* unknown */
190 #define SMBIOS_CHT_DESKTOP 0x03 /* desktop */
192 #define SMBIOS_CHST_SAFE 0x03 /* safe */
194 #define SMBIOS_CHSC_NONE 0x03 /* none */
196 struct smbios_table_type3 {
197 struct smbios_structure header;
198 uint8_t manufacturer; /* manufacturer string */
199 uint8_t type; /* type */
200 uint8_t version; /* version string */
201 uint8_t serial; /* serial number string */
202 uint8_t asset; /* asset tag string */
203 uint8_t bustate; /* boot-up state */
204 uint8_t psstate; /* power supply state */
205 uint8_t tstate; /* thermal state */
206 uint8_t security; /* security status */
207 uint32_t oemdata; /* OEM-specific data */
208 uint8_t uheight; /* height in 'u's */
209 uint8_t cords; /* number of power cords */
210 uint8_t elems; /* number of element records */
211 uint8_t elemlen; /* length of records */
212 uint8_t sku; /* sku number string */
216 * Processor Information
218 #define SMBIOS_PRT_CENTRAL 0x03 /* central processor */
220 #define SMBIOS_PRF_OTHER 0x01 /* other */
222 #define SMBIOS_PRS_PRESENT 0x40 /* socket is populated */
223 #define SMBIOS_PRS_ENABLED 0x1 /* enabled */
225 #define SMBIOS_PRU_NONE 0x06 /* none */
227 #define SMBIOS_PFL_64B 0x04 /* 64-bit capable */
229 struct smbios_table_type4 {
230 struct smbios_structure header;
231 uint8_t socket; /* socket designation string */
232 uint8_t type; /* processor type */
233 uint8_t family; /* processor family */
234 uint8_t manufacturer; /* manufacturer string */
235 uint64_t cpuid; /* processor cpuid */
236 uint8_t version; /* version string */
237 uint8_t voltage; /* voltage */
238 uint16_t clkspeed; /* ext clock speed in mhz */
239 uint16_t maxspeed; /* maximum speed in mhz */
240 uint16_t curspeed; /* current speed in mhz */
241 uint8_t status; /* status */
242 uint8_t upgrade; /* upgrade */
243 uint16_t l1handle; /* l1 cache handle */
244 uint16_t l2handle; /* l2 cache handle */
245 uint16_t l3handle; /* l3 cache handle */
246 uint8_t serial; /* serial number string */
247 uint8_t asset; /* asset tag string */
248 uint8_t part; /* part number string */
249 uint8_t cores; /* cores per socket */
250 uint8_t ecores; /* enabled cores */
251 uint8_t threads; /* threads per socket */
252 uint16_t cflags; /* processor characteristics */
253 uint16_t family2; /* processor family 2 */
257 * Physical Memory Array
259 #define SMBIOS_MAL_SYSMB 0x03 /* system board or motherboard */
261 #define SMBIOS_MAU_SYSTEM 0x03 /* system memory */
263 #define SMBIOS_MAE_NONE 0x03 /* none */
265 struct smbios_table_type16 {
266 struct smbios_structure header;
267 uint8_t location; /* physical device location */
268 uint8_t use; /* device functional purpose */
269 uint8_t ecc; /* err detect/correct method */
270 uint32_t size; /* max mem capacity in kb */
271 uint16_t errhand; /* handle of error (if any) */
272 uint16_t ndevs; /* num of slots or sockets */
273 uint64_t xsize; /* max mem capacity in bytes */
279 #define SMBIOS_MDFF_UNKNOWN 0x02 /* unknown */
281 #define SMBIOS_MDT_UNKNOWN 0x02 /* unknown */
283 #define SMBIOS_MDF_UNKNOWN 0x0004 /* unknown */
285 struct smbios_table_type17 {
286 struct smbios_structure header;
287 uint16_t arrayhand; /* handle of physl mem array */
288 uint16_t errhand; /* handle of mem error data */
289 uint16_t twidth; /* total width in bits */
290 uint16_t dwidth; /* data width in bits */
291 uint16_t size; /* size in kb or mb */
292 uint8_t form; /* form factor */
293 uint8_t set; /* set */
294 uint8_t dloc; /* device locator string */
295 uint8_t bloc; /* phys bank locator string */
296 uint8_t type; /* memory type */
297 uint16_t flags; /* memory characteristics */
298 uint16_t maxspeed; /* maximum speed in mhz */
299 uint8_t manufacturer; /* manufacturer string */
300 uint8_t serial; /* serial number string */
301 uint8_t asset; /* asset tag string */
302 uint8_t part; /* part number string */
303 uint8_t attributes; /* attributes */
304 uint32_t xsize; /* extended size in mb */
305 uint16_t curspeed; /* current speed in mhz */
306 uint16_t minvoltage; /* minimum voltage */
307 uint16_t maxvoltage; /* maximum voltage */
308 uint16_t curvoltage; /* configured voltage */
312 * Memory Array Mapped Address
314 struct smbios_table_type19 {
315 struct smbios_structure header;
316 uint32_t saddr; /* start phys addr in kb */
317 uint32_t eaddr; /* end phys addr in kb */
318 uint16_t arrayhand; /* physical mem array handle */
319 uint8_t width; /* num of dev in row */
320 uint64_t xsaddr; /* start phys addr in bytes */
321 uint64_t xeaddr; /* end phys addr in bytes */
325 * System Boot Information
327 #define SMBIOS_BOOT_NORMAL 0 /* no errors detected */
329 struct smbios_table_type32 {
330 struct smbios_structure header;
332 uint8_t status; /* boot status */
338 struct smbios_table_type127 {
339 struct smbios_structure header;
342 struct smbios_table_type0 smbios_type0_template = {
343 { SMBIOS_TYPE_BIOS, sizeof (struct smbios_table_type0), 0 },
344 1, /* bios vendor string */
345 2, /* bios version string */
346 0xF000, /* bios address segment location */
347 3, /* bios release date */
348 0x0, /* bios size (64k * (n + 1) is the size in bytes) */
349 SMBIOS_FL_ISA | SMBIOS_FL_PCI | SMBIOS_FL_SHADOW |
350 SMBIOS_FL_CDBOOT | SMBIOS_FL_EDD,
351 { SMBIOS_XB1_FL_ACPI, SMBIOS_XB2_FL_BBS | SMBIOS_XB2_FL_VM },
352 0x0, /* bios major release */
353 0x0, /* bios minor release */
354 0xff, /* embedded controller firmware major release */
355 0xff /* embedded controller firmware minor release */
358 struct smbios_string smbios_type0_strings[] = {
359 { "bios.vendor", "BHYVE" }, /* vendor string */
360 { "bios.version", FIRMWARE_VERSION }, /* bios version string */
361 { "bios.release_date", FIRMWARE_RELEASE_DATE }, /* bios release date string */
365 struct smbios_table_type1 smbios_type1_template = {
366 { SMBIOS_TYPE_SYSTEM, sizeof (struct smbios_table_type1), 0 },
367 1, /* manufacturer string */
368 2, /* product string */
369 3, /* version string */
370 4, /* serial number string */
372 SMBIOS_WAKEUP_SWITCH,
374 6 /* family string */
377 static int smbios_type1_initializer(struct smbios_structure *template_entry,
378 struct smbios_string *template_strings, char *curaddr, char **endaddr,
379 uint16_t *n, uint16_t *size);
381 struct smbios_string smbios_type1_strings[] = {
382 { "system.manufacturer", "FreeBSD" }, /* manufacturer string */
383 { "system.product_name", "BHYVE" }, /* product string */
384 { "system.version", "1.0" }, /* version string */
385 { "system.serial_number", "None" }, /* serial number string */
386 { "system.sku", "None" }, /* sku string */
387 { "system.family_name", "Virtual Machine" }, /* family string */
391 struct smbios_table_type2 smbios_type2_template = {
392 { SMBIOS_TYPE_BOARD, sizeof (struct smbios_table_type2), 0 },
393 1, /* manufacturer string */
394 2, /* product string */
395 3, /* version string */
396 4, /* serial number string */
397 5, /* asset tag string */
398 SMBIOS_BRF_HOSTING, /* feature flags */
399 6, /* location string */
400 SMBIOS_CHT_DESKTOP, /* chassis handle */
401 SMBIOS_BRT_MOTHERBOARD, /* board type */
405 struct smbios_string smbios_type2_strings[] = {
406 { "board.manufacturer", "FreeBSD" }, /* manufacturer string */
407 { "board.product_name", "BHYVE" }, /* product name string */
408 { "board.version", "1.0" }, /* version string */
409 { "board.serial_number", "None" }, /* serial number string */
410 { "board.asset_tag", "None" }, /* asset tag string */
411 { "board.location", "None" }, /* location string */
415 struct smbios_table_type3 smbios_type3_template = {
416 { SMBIOS_TYPE_CHASSIS, sizeof (struct smbios_table_type3), 0 },
417 1, /* manufacturer string */
419 2, /* version string */
420 3, /* serial number string */
421 4, /* asset tag string */
426 0, /* OEM specific data, we have none */
427 0, /* height in 'u's (0=enclosure height unspecified) */
428 0, /* number of power cords (0=number unspecified) */
429 0, /* number of contained element records */
430 0, /* length of records */
431 5 /* sku number string */
434 struct smbios_string smbios_type3_strings[] = {
435 { "chassis.manufacturer", "FreeBSD" }, /* manufacturer string */
436 { "chassis.version", "1.0" }, /* version string */
437 { "chassis.serial_number", "None" }, /* serial number string */
438 { "chassis.asset_tag", "None" }, /* asset tag string */
439 { "chassis.sku", "None" }, /* sku number string */
443 struct smbios_table_type4 smbios_type4_template = {
444 { SMBIOS_TYPE_PROCESSOR, sizeof (struct smbios_table_type4), 0 },
445 1, /* socket designation string */
448 2, /* manufacturer string */
450 3, /* version string */
452 0, /* external clock frequency in mhz (0=unknown) */
453 0, /* maximum frequency in mhz (0=unknown) */
454 0, /* current frequency in mhz (0=unknown) */
455 SMBIOS_PRS_PRESENT | SMBIOS_PRS_ENABLED,
457 -1, /* l1 cache handle */
458 -1, /* l2 cache handle */
459 -1, /* l3 cache handle */
460 4, /* serial number string */
461 5, /* asset tag string */
462 6, /* part number string */
463 0, /* cores per socket (0=unknown) */
464 0, /* enabled cores per socket (0=unknown) */
465 0, /* threads per socket (0=unknown) */
470 struct smbios_string smbios_type4_strings[] = {
471 { NULL, " " }, /* socket designation string */
472 { NULL, " " }, /* manufacturer string */
473 { NULL, " " }, /* version string */
474 { NULL, "None" }, /* serial number string */
475 { NULL, "None" }, /* asset tag string */
476 { NULL, "None" }, /* part number string */
480 static int smbios_type4_initializer(struct smbios_structure *template_entry,
481 struct smbios_string *template_strings, char *curaddr, char **endaddr,
482 uint16_t *n, uint16_t *size);
484 struct smbios_table_type16 smbios_type16_template = {
485 { SMBIOS_TYPE_MEMARRAY, sizeof (struct smbios_table_type16), 0 },
489 0x80000000, /* max mem capacity in kb (0x80000000=use extended) */
490 -1, /* handle of error (if any) */
491 0, /* number of slots or sockets (TBD) */
492 0 /* extended maximum memory capacity in bytes (TBD) */
495 static int smbios_type16_initializer(struct smbios_structure *template_entry,
496 struct smbios_string *template_strings, char *curaddr, char **endaddr,
497 uint16_t *n, uint16_t *size);
499 struct smbios_table_type17 smbios_type17_template = {
500 { SMBIOS_TYPE_MEMDEVICE, sizeof (struct smbios_table_type17), 0 },
501 -1, /* handle of physical memory array */
502 -1, /* handle of memory error data */
503 64, /* total width in bits including ecc */
504 64, /* data width in bits */
505 0, /* size in kb or mb (0x7fff=use extended)*/
507 0, /* set (0x00=none, 0xff=unknown) */
508 1, /* device locator string */
509 2, /* physical bank locator string */
512 0, /* maximum memory speed in mhz (0=unknown) */
513 3, /* manufacturer string */
514 4, /* serial number string */
515 5, /* asset tag string */
516 6, /* part number string */
517 0, /* attributes (0=unknown rank information) */
518 0, /* extended size in mb (TBD) */
519 0, /* current speed in mhz (0=unknown) */
520 0, /* minimum voltage in mv (0=unknown) */
521 0, /* maximum voltage in mv (0=unknown) */
522 0 /* configured voltage in mv (0=unknown) */
525 struct smbios_string smbios_type17_strings[] = {
526 { NULL, " " }, /* device locator string */
527 { NULL, " " }, /* physical bank locator string */
528 { NULL, " " }, /* manufacturer string */
529 { NULL, "None" }, /* serial number string */
530 { NULL, "None" }, /* asset tag string */
531 { NULL, "None" }, /* part number string */
535 static int smbios_type17_initializer(struct smbios_structure *template_entry,
536 struct smbios_string *template_strings, char *curaddr, char **endaddr,
537 uint16_t *n, uint16_t *size);
539 struct smbios_table_type19 smbios_type19_template = {
540 { SMBIOS_TYPE_MEMARRAYMAP, sizeof (struct smbios_table_type19), 0 },
541 0xffffffff, /* starting phys addr in kb (0xffffffff=use ext) */
542 0xffffffff, /* ending phys addr in kb (0xffffffff=use ext) */
543 -1, /* physical memory array handle */
544 1, /* number of devices that form a row */
545 0, /* extended starting phys addr in bytes (TDB) */
546 0 /* extended ending phys addr in bytes (TDB) */
549 static int smbios_type19_initializer(struct smbios_structure *template_entry,
550 struct smbios_string *template_strings, char *curaddr, char **endaddr,
551 uint16_t *n, uint16_t *size);
553 struct smbios_table_type32 smbios_type32_template = {
554 { SMBIOS_TYPE_BOOT, sizeof (struct smbios_table_type32), 0 },
555 { 0, 0, 0, 0, 0, 0 },
559 struct smbios_table_type127 smbios_type127_template = {
560 { SMBIOS_TYPE_EOT, sizeof (struct smbios_table_type127), 0 }
563 static int smbios_generic_initializer(struct smbios_structure *template_entry,
564 struct smbios_string *template_strings, char *curaddr, char **endaddr,
565 uint16_t *n, uint16_t *size);
567 static struct smbios_template_entry smbios_template[] = {
568 { (struct smbios_structure *)&smbios_type0_template,
569 smbios_type0_strings,
570 smbios_generic_initializer },
571 { (struct smbios_structure *)&smbios_type1_template,
572 smbios_type1_strings,
573 smbios_type1_initializer },
574 { (struct smbios_structure *)&smbios_type2_template,
575 smbios_type2_strings,
576 smbios_generic_initializer },
577 { (struct smbios_structure *)&smbios_type3_template,
578 smbios_type3_strings,
579 smbios_generic_initializer },
580 { (struct smbios_structure *)&smbios_type4_template,
581 smbios_type4_strings,
582 smbios_type4_initializer },
583 { (struct smbios_structure *)&smbios_type16_template,
585 smbios_type16_initializer },
586 { (struct smbios_structure *)&smbios_type17_template,
587 smbios_type17_strings,
588 smbios_type17_initializer },
589 { (struct smbios_structure *)&smbios_type19_template,
591 smbios_type19_initializer },
592 { (struct smbios_structure *)&smbios_type32_template,
594 smbios_generic_initializer },
595 { (struct smbios_structure *)&smbios_type127_template,
597 smbios_generic_initializer },
601 static uint64_t guest_lomem, guest_himem;
602 static uint16_t type16_handle;
605 smbios_generic_initializer(struct smbios_structure *template_entry,
606 struct smbios_string *template_strings, char *curaddr, char **endaddr,
607 uint16_t *n, uint16_t *size)
609 struct smbios_structure *entry;
611 memcpy(curaddr, template_entry, template_entry->length);
612 entry = (struct smbios_structure *)curaddr;
613 entry->handle = *n + 1;
614 curaddr += entry->length;
615 if (template_strings != NULL) {
618 for (i = 0; template_strings[i].value != NULL; i++) {
622 if (template_strings[i].node == NULL) {
623 string = template_strings[i].value;
625 set_config_value_if_unset(
626 template_strings[i].node,
627 template_strings[i].value);
628 string = get_config_value(
629 template_strings[i].node);
632 len = strlen(string) + 1;
633 memcpy(curaddr, string, len);
639 /* Minimum string section is double nul */
652 smbios_type1_initializer(struct smbios_structure *template_entry,
653 struct smbios_string *template_strings, char *curaddr, char **endaddr,
654 uint16_t *n, uint16_t *size)
656 struct smbios_table_type1 *type1;
657 const char *guest_uuid_str;
659 smbios_generic_initializer(template_entry, template_strings,
660 curaddr, endaddr, n, size);
661 type1 = (struct smbios_table_type1 *)curaddr;
663 guest_uuid_str = get_config_value("uuid");
664 if (guest_uuid_str != NULL) {
668 uuid_from_string(guest_uuid_str, &uuid, &status);
669 if (status != uuid_s_ok) {
670 EPRINTLN("Invalid UUID");
674 uuid_enc_le(&type1->uuid, &uuid);
678 char hostname[MAXHOSTNAMELEN];
682 * Universally unique and yet reproducible are an
683 * oxymoron, however reproducible is desirable in
686 if (gethostname(hostname, sizeof(hostname)))
690 vmname = get_config_value("name");
691 MD5Update(&mdctx, vmname, strlen(vmname));
692 MD5Update(&mdctx, hostname, sizeof(hostname));
693 MD5Final(digest, &mdctx);
696 * Set the variant and version number.
699 digest[6] |= 0x30; /* version 3 */
703 memcpy(&type1->uuid, digest, sizeof (digest));
710 smbios_type4_initializer(struct smbios_structure *template_entry,
711 struct smbios_string *template_strings, char *curaddr, char **endaddr,
712 uint16_t *n, uint16_t *size)
716 for (i = 0; i < sockets; i++) {
717 struct smbios_table_type4 *type4;
721 smbios_generic_initializer(template_entry, template_strings,
722 curaddr, endaddr, n, size);
723 type4 = (struct smbios_table_type4 *)curaddr;
724 p = curaddr + sizeof (struct smbios_table_type4);
726 while (p < *endaddr - 1) {
730 len = sprintf(*endaddr - 1, "CPU #%d", i) + 1;
734 type4->socket = nstrings + 1;
735 /* Revise cores and threads after update to smbios 3.0 */
739 type4->cores = cores;
740 /* This threads is total threads in a socket */
741 if ((cores * threads) > 254)
744 type4->threads = (cores * threads);
752 smbios_type16_initializer(struct smbios_structure *template_entry,
753 struct smbios_string *template_strings, char *curaddr, char **endaddr,
754 uint16_t *n, uint16_t *size)
756 struct smbios_table_type16 *type16;
759 smbios_generic_initializer(template_entry, template_strings,
760 curaddr, endaddr, n, size);
761 type16 = (struct smbios_table_type16 *)curaddr;
762 type16->xsize = guest_lomem + guest_himem;
763 type16->ndevs = guest_himem > 0 ? 2 : 1;
769 smbios_type17_initializer(struct smbios_structure *template_entry,
770 struct smbios_string *template_strings, char *curaddr, char **endaddr,
771 uint16_t *n, uint16_t *size)
773 struct smbios_table_type17 *type17;
774 uint64_t memsize, size_KB, size_MB;
776 smbios_generic_initializer(template_entry, template_strings,
777 curaddr, endaddr, n, size);
778 type17 = (struct smbios_table_type17 *)curaddr;
779 type17->arrayhand = type16_handle;
781 memsize = guest_lomem + guest_himem;
782 size_KB = memsize / 1024;
783 size_MB = memsize / MB;
785 /* A single Type 17 entry can't represent more than ~2PB RAM */
786 if (size_MB > 0x7FFFFFFF) {
787 printf("Warning: guest memory too big for SMBIOS Type 17 table: "
788 "%luMB greater than max supported 2147483647MB\n", size_MB);
790 size_MB = 0x7FFFFFFF;
793 /* See SMBIOS 2.7.0 section 7.18 - Memory Device (Type 17) */
794 if (size_KB <= 0x7FFF) {
795 /* Can represent up to 32767KB with the top bit set */
796 type17->size = size_KB | (1 << 15);
797 } else if (size_MB < 0x7FFF) {
798 /* Can represent up to 32766MB with the top bit unset */
799 type17->size = size_MB & 0x7FFF;
801 type17->size = 0x7FFF;
803 * Can represent up to 2147483647MB (~2PB)
804 * The top bit is reserved
806 type17->xsize = size_MB & 0x7FFFFFFF;
813 smbios_type19_initializer(struct smbios_structure *template_entry,
814 struct smbios_string *template_strings, char *curaddr, char **endaddr,
815 uint16_t *n, uint16_t *size)
817 struct smbios_table_type19 *type19;
819 smbios_generic_initializer(template_entry, template_strings,
820 curaddr, endaddr, n, size);
821 type19 = (struct smbios_table_type19 *)curaddr;
822 type19->arrayhand = type16_handle;
824 type19->xeaddr = guest_lomem;
826 if (guest_himem > 0) {
828 smbios_generic_initializer(template_entry, template_strings,
829 curaddr, endaddr, n, size);
830 type19 = (struct smbios_table_type19 *)curaddr;
831 type19->arrayhand = type16_handle;
832 type19->xsaddr = 4*GB;
833 type19->xeaddr = type19->xsaddr + guest_himem;
840 smbios_ep_initializer(struct smbios_entry_point *smbios_ep, uint32_t staddr)
842 memset(smbios_ep, 0, sizeof(*smbios_ep));
843 memcpy(smbios_ep->eanchor, SMBIOS_ENTRY_EANCHOR,
844 SMBIOS_ENTRY_EANCHORLEN);
845 smbios_ep->eplen = 0x1F;
846 assert(sizeof (struct smbios_entry_point) == smbios_ep->eplen);
847 smbios_ep->major = 2;
848 smbios_ep->minor = 6;
849 smbios_ep->revision = 0;
850 memcpy(smbios_ep->ianchor, SMBIOS_ENTRY_IANCHOR,
851 SMBIOS_ENTRY_IANCHORLEN);
852 smbios_ep->staddr = staddr;
853 smbios_ep->bcdrev = (smbios_ep->major & 0xf) << 4 | (smbios_ep->minor & 0xf);
857 smbios_ep_finalizer(struct smbios_entry_point *smbios_ep, uint16_t len,
858 uint16_t num, uint16_t maxssize)
863 smbios_ep->maxssize = maxssize;
864 smbios_ep->stlen = len;
865 smbios_ep->stnum = num;
868 for (i = 0x10; i < 0x1f; i++) {
869 checksum -= ((uint8_t *)smbios_ep)[i];
871 smbios_ep->ichecksum = checksum;
874 for (i = 0; i < 0x1f; i++) {
875 checksum -= ((uint8_t *)smbios_ep)[i];
877 smbios_ep->echecksum = checksum;
881 smbios_build(struct vmctx *ctx)
883 struct smbios_entry_point *smbios_ep;
886 char *curaddr, *startaddr, *ststartaddr;
890 guest_lomem = vm_get_lowmem_size(ctx);
891 guest_himem = vm_get_highmem_size(ctx);
893 startaddr = paddr_guest2host(ctx, SMBIOS_BASE, SMBIOS_MAX_LENGTH);
894 if (startaddr == NULL) {
895 EPRINTLN("smbios table requires mapped mem");
901 smbios_ep = (struct smbios_entry_point *)curaddr;
902 smbios_ep_initializer(smbios_ep, SMBIOS_BASE +
903 sizeof(struct smbios_entry_point));
904 curaddr += sizeof(struct smbios_entry_point);
905 ststartaddr = curaddr;
909 for (i = 0; smbios_template[i].entry != NULL; i++) {
910 struct smbios_structure *entry;
911 struct smbios_string *strings;
912 initializer_func_t initializer;
916 entry = smbios_template[i].entry;
917 strings = smbios_template[i].strings;
918 initializer = smbios_template[i].initializer;
920 err = (*initializer)(entry, strings, curaddr, &endaddr,
931 assert(curaddr - startaddr < SMBIOS_MAX_LENGTH);
932 smbios_ep_finalizer(smbios_ep, curaddr - ststartaddr, n, maxssize);