2 * SPDX-License-Identifier: BSD-2-Clause
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>
31 #include <sys/param.h>
42 #include <machine/vmm.h>
46 #include <sys/sysmacros.h>
52 #include "smbiostbl.h"
54 #define MB (1024*1024)
55 #define GB (1024ULL*1024*1024)
57 #define SMBIOS_BASE 0xF1000
59 #define FIRMWARE_VERSION "14.0"
60 /* The SMBIOS specification defines the date format to be mm/dd/yyyy */
61 #define FIRMWARE_RELEASE_DATE "10/10/2021"
63 /* BHYVE_ACPI_BASE - SMBIOS_BASE) */
64 #define SMBIOS_MAX_LENGTH (0xF2400 - 0xF1000)
66 #define SMBIOS_TYPE_BIOS 0
67 #define SMBIOS_TYPE_SYSTEM 1
68 #define SMBIOS_TYPE_BOARD 2
69 #define SMBIOS_TYPE_CHASSIS 3
70 #define SMBIOS_TYPE_PROCESSOR 4
71 #define SMBIOS_TYPE_MEMARRAY 16
72 #define SMBIOS_TYPE_MEMDEVICE 17
73 #define SMBIOS_TYPE_MEMARRAYMAP 19
74 #define SMBIOS_TYPE_BOOT 32
75 #define SMBIOS_TYPE_EOT 127
77 struct smbios_structure
{
83 struct smbios_string
{
88 typedef int (*initializer_func_t
)(const struct smbios_structure
*template_entry
,
89 const struct smbios_string
*template_strings
, char *curaddr
, char **endaddr
,
92 struct smbios_template_entry
{
93 const struct smbios_structure
*entry
;
94 const struct smbios_string
*strings
;
95 initializer_func_t initializer
;
99 * SMBIOS Structure Table Entry Point
101 #define SMBIOS_ENTRY_EANCHOR "_SM_"
102 #define SMBIOS_ENTRY_EANCHORLEN 4
103 #define SMBIOS_ENTRY_IANCHOR "_DMI_"
104 #define SMBIOS_ENTRY_IANCHORLEN 5
106 struct smbios_entry_point
{
107 char eanchor
[4]; /* anchor tag */
108 uint8_t echecksum
; /* checksum of entry point structure */
109 uint8_t eplen
; /* length in bytes of entry point */
110 uint8_t major
; /* major version of the SMBIOS spec */
111 uint8_t minor
; /* minor version of the SMBIOS spec */
112 uint16_t maxssize
; /* maximum size in bytes of a struct */
113 uint8_t revision
; /* entry point structure revision */
114 uint8_t format
[5]; /* entry point rev-specific data */
115 char ianchor
[5]; /* intermediate anchor tag */
116 uint8_t ichecksum
; /* intermediate checksum */
117 uint16_t stlen
; /* len in bytes of structure table */
118 uint32_t staddr
; /* physical addr of structure table */
119 uint16_t stnum
; /* number of structure table entries */
120 uint8_t bcdrev
; /* BCD value representing DMI ver */
126 #define SMBIOS_FL_ISA 0x00000010 /* ISA is supported */
127 #define SMBIOS_FL_PCI 0x00000080 /* PCI is supported */
128 #define SMBIOS_FL_SHADOW 0x00001000 /* BIOS shadowing is allowed */
129 #define SMBIOS_FL_CDBOOT 0x00008000 /* Boot from CD is supported */
130 #define SMBIOS_FL_SELBOOT 0x00010000 /* Selectable Boot supported */
131 #define SMBIOS_FL_EDD 0x00080000 /* EDD Spec is supported */
133 #define SMBIOS_XB1_FL_ACPI 0x00000001 /* ACPI is supported */
135 #define SMBIOS_XB2_FL_BBS 0x00000001 /* BIOS Boot Specification */
136 #define SMBIOS_XB2_FL_VM 0x00000010 /* Virtual Machine */
138 struct smbios_table_type0
{
139 struct smbios_structure header
;
140 uint8_t vendor
; /* vendor string */
141 uint8_t version
; /* version string */
142 uint16_t segment
; /* address segment location */
143 uint8_t rel_date
; /* release date */
144 uint8_t size
; /* rom size */
145 uint64_t cflags
; /* characteristics */
146 uint8_t xc_bytes
[2]; /* characteristics ext bytes */
147 uint8_t sb_major_rel
; /* system bios version */
148 uint8_t sb_minor_rele
;
149 uint8_t ecfw_major_rel
; /* embedded ctrl fw version */
150 uint8_t ecfw_minor_rel
;
156 #define SMBIOS_WAKEUP_SWITCH 0x06 /* power switch */
158 struct smbios_table_type1
{
159 struct smbios_structure header
;
160 uint8_t manufacturer
; /* manufacturer string */
161 uint8_t product
; /* product name string */
162 uint8_t version
; /* version string */
163 uint8_t serial
; /* serial number string */
164 uint8_t uuid
[16]; /* uuid byte array */
165 uint8_t wakeup
; /* wake-up event */
166 uint8_t sku
; /* sku number string */
167 uint8_t family
; /* family name string */
171 * Baseboard (or Module) Information
173 #define SMBIOS_BRF_HOSTING 0x1
174 #define SMBIOS_BRT_MOTHERBOARD 0xa
176 struct smbios_table_type2
{
177 struct smbios_structure header
;
178 uint8_t manufacturer
; /* manufacturer string */
179 uint8_t product
; /* product name string */
180 uint8_t version
; /* version string */
181 uint8_t serial
; /* serial number string */
182 uint8_t asset
; /* asset tag string */
183 uint8_t fflags
; /* feature flags */
184 uint8_t location
; /* location in chassis */
185 uint16_t chandle
; /* chassis handle */
186 uint8_t type
; /* board type */
187 uint8_t n_objs
; /* number of contained object handles */
191 * System Enclosure or Chassis
193 #define SMBIOS_CHT_UNKNOWN 0x02 /* unknown */
194 #define SMBIOS_CHT_DESKTOP 0x03 /* desktop */
196 #define SMBIOS_CHST_SAFE 0x03 /* safe */
198 #define SMBIOS_CHSC_NONE 0x03 /* none */
200 struct smbios_table_type3
{
201 struct smbios_structure header
;
202 uint8_t manufacturer
; /* manufacturer string */
203 uint8_t type
; /* type */
204 uint8_t version
; /* version string */
205 uint8_t serial
; /* serial number string */
206 uint8_t asset
; /* asset tag string */
207 uint8_t bustate
; /* boot-up state */
208 uint8_t psstate
; /* power supply state */
209 uint8_t tstate
; /* thermal state */
210 uint8_t security
; /* security status */
211 uint32_t oemdata
; /* OEM-specific data */
212 uint8_t uheight
; /* height in 'u's */
213 uint8_t cords
; /* number of power cords */
214 uint8_t elems
; /* number of element records */
215 uint8_t elemlen
; /* length of records */
216 uint8_t sku
; /* sku number string */
220 * Processor Information
222 #define SMBIOS_PRT_CENTRAL 0x03 /* central processor */
224 #define SMBIOS_PRF_OTHER 0x01 /* other */
226 #define SMBIOS_PRS_PRESENT 0x40 /* socket is populated */
227 #define SMBIOS_PRS_ENABLED 0x1 /* enabled */
229 #define SMBIOS_PRU_NONE 0x06 /* none */
231 #define SMBIOS_PFL_64B 0x04 /* 64-bit capable */
233 struct smbios_table_type4
{
234 struct smbios_structure header
;
235 uint8_t socket
; /* socket designation string */
236 uint8_t type
; /* processor type */
237 uint8_t family
; /* processor family */
238 uint8_t manufacturer
; /* manufacturer string */
239 uint64_t cpuid
; /* processor cpuid */
240 uint8_t version
; /* version string */
241 uint8_t voltage
; /* voltage */
242 uint16_t clkspeed
; /* ext clock speed in mhz */
243 uint16_t maxspeed
; /* maximum speed in mhz */
244 uint16_t curspeed
; /* current speed in mhz */
245 uint8_t status
; /* status */
246 uint8_t upgrade
; /* upgrade */
247 uint16_t l1handle
; /* l1 cache handle */
248 uint16_t l2handle
; /* l2 cache handle */
249 uint16_t l3handle
; /* l3 cache handle */
250 uint8_t serial
; /* serial number string */
251 uint8_t asset
; /* asset tag string */
252 uint8_t part
; /* part number string */
253 uint8_t cores
; /* cores per socket */
254 uint8_t ecores
; /* enabled cores */
255 uint8_t threads
; /* threads per socket */
256 uint16_t cflags
; /* processor characteristics */
257 uint16_t family2
; /* processor family 2 */
261 * Physical Memory Array
263 #define SMBIOS_MAL_SYSMB 0x03 /* system board or motherboard */
265 #define SMBIOS_MAU_SYSTEM 0x03 /* system memory */
267 #define SMBIOS_MAE_NONE 0x03 /* none */
269 struct smbios_table_type16
{
270 struct smbios_structure header
;
271 uint8_t location
; /* physical device location */
272 uint8_t use
; /* device functional purpose */
273 uint8_t ecc
; /* err detect/correct method */
274 uint32_t size
; /* max mem capacity in kb */
275 uint16_t errhand
; /* handle of error (if any) */
276 uint16_t ndevs
; /* num of slots or sockets */
277 uint64_t xsize
; /* max mem capacity in bytes */
283 #define SMBIOS_MDFF_UNKNOWN 0x02 /* unknown */
285 #define SMBIOS_MDT_UNKNOWN 0x02 /* unknown */
287 #define SMBIOS_MDF_UNKNOWN 0x0004 /* unknown */
289 struct smbios_table_type17
{
290 struct smbios_structure header
;
291 uint16_t arrayhand
; /* handle of physl mem array */
292 uint16_t errhand
; /* handle of mem error data */
293 uint16_t twidth
; /* total width in bits */
294 uint16_t dwidth
; /* data width in bits */
295 uint16_t size
; /* size in kb or mb */
296 uint8_t form
; /* form factor */
297 uint8_t set
; /* set */
298 uint8_t dloc
; /* device locator string */
299 uint8_t bloc
; /* phys bank locator string */
300 uint8_t type
; /* memory type */
301 uint16_t flags
; /* memory characteristics */
302 uint16_t maxspeed
; /* maximum speed in mhz */
303 uint8_t manufacturer
; /* manufacturer string */
304 uint8_t serial
; /* serial number string */
305 uint8_t asset
; /* asset tag string */
306 uint8_t part
; /* part number string */
307 uint8_t attributes
; /* attributes */
308 uint32_t xsize
; /* extended size in mb */
309 uint16_t curspeed
; /* current speed in mhz */
310 uint16_t minvoltage
; /* minimum voltage */
311 uint16_t maxvoltage
; /* maximum voltage */
312 uint16_t curvoltage
; /* configured voltage */
316 * Memory Array Mapped Address
318 struct smbios_table_type19
{
319 struct smbios_structure header
;
320 uint32_t saddr
; /* start phys addr in kb */
321 uint32_t eaddr
; /* end phys addr in kb */
322 uint16_t arrayhand
; /* physical mem array handle */
323 uint8_t width
; /* num of dev in row */
324 uint64_t xsaddr
; /* start phys addr in bytes */
325 uint64_t xeaddr
; /* end phys addr in bytes */
329 * System Boot Information
331 #define SMBIOS_BOOT_NORMAL 0 /* no errors detected */
333 struct smbios_table_type32
{
334 struct smbios_structure header
;
336 uint8_t status
; /* boot status */
342 struct smbios_table_type127
{
343 struct smbios_structure header
;
346 static const struct smbios_table_type0 smbios_type0_template
= {
347 { SMBIOS_TYPE_BIOS
, sizeof (struct smbios_table_type0
), 0 },
348 1, /* bios vendor string */
349 2, /* bios version string */
350 0xF000, /* bios address segment location */
351 3, /* bios release date */
352 0x0, /* bios size (64k * (n + 1) is the size in bytes) */
353 SMBIOS_FL_ISA
| SMBIOS_FL_PCI
| SMBIOS_FL_SHADOW
|
354 SMBIOS_FL_CDBOOT
| SMBIOS_FL_EDD
,
355 { SMBIOS_XB1_FL_ACPI
, SMBIOS_XB2_FL_BBS
| SMBIOS_XB2_FL_VM
},
356 0x0, /* bios major release */
357 0x0, /* bios minor release */
358 0xff, /* embedded controller firmware major release */
359 0xff /* embedded controller firmware minor release */
362 static const struct smbios_string smbios_type0_strings
[] = {
363 { "bios.vendor", "BHYVE" }, /* vendor string */
364 { "bios.version", FIRMWARE_VERSION
}, /* bios version string */
365 { "bios.release_date", FIRMWARE_RELEASE_DATE
}, /* bios release date string */
369 static const struct smbios_table_type1 smbios_type1_template
= {
370 { SMBIOS_TYPE_SYSTEM
, sizeof (struct smbios_table_type1
), 0 },
371 1, /* manufacturer string */
372 2, /* product string */
373 3, /* version string */
374 4, /* serial number string */
376 SMBIOS_WAKEUP_SWITCH
,
378 6 /* family string */
381 static int smbios_type1_initializer(const struct smbios_structure
*template_entry
,
382 const struct smbios_string
*template_strings
, char *curaddr
, char **endaddr
,
385 static const struct smbios_string smbios_type1_strings
[] = {
386 { "system.manufacturer", "illumos" }, /* manufacturer string */
387 { "system.product_name", "BHYVE" }, /* product string */
388 { "system.version", "1.0" }, /* version string */
389 { "system.serial_number", "None" }, /* serial number string */
390 { "system.sku", "None" }, /* sku string */
391 { "system.family_name", "Virtual Machine" }, /* family string */
395 static const struct smbios_table_type2 smbios_type2_template
= {
396 { SMBIOS_TYPE_BOARD
, sizeof (struct smbios_table_type2
), 0 },
397 1, /* manufacturer string */
398 2, /* product string */
399 3, /* version string */
400 4, /* serial number string */
401 5, /* asset tag string */
402 SMBIOS_BRF_HOSTING
, /* feature flags */
403 6, /* location string */
404 SMBIOS_CHT_DESKTOP
, /* chassis handle */
405 SMBIOS_BRT_MOTHERBOARD
, /* board type */
409 static const struct smbios_string smbios_type2_strings
[] = {
410 { "board.manufacturer", "illumos" }, /* manufacturer string */
411 { "board.product_name", "BHYVE" }, /* product name string */
412 { "board.version", "1.0" }, /* version string */
413 { "board.serial_number", "None" }, /* serial number string */
414 { "board.asset_tag", "None" }, /* asset tag string */
415 { "board.location", "None" }, /* location string */
419 static const struct smbios_table_type3 smbios_type3_template
= {
420 { SMBIOS_TYPE_CHASSIS
, sizeof (struct smbios_table_type3
), 0 },
421 1, /* manufacturer string */
423 2, /* version string */
424 3, /* serial number string */
425 4, /* asset tag string */
430 0, /* OEM specific data, we have none */
431 0, /* height in 'u's (0=enclosure height unspecified) */
432 0, /* number of power cords (0=number unspecified) */
433 0, /* number of contained element records */
434 0, /* length of records */
435 5 /* sku number string */
438 static const struct smbios_string smbios_type3_strings
[] = {
439 { "chassis.manufacturer", "illumos" }, /* manufacturer string */
440 { "chassis.version", "1.0" }, /* version string */
441 { "chassis.serial_number", "None" }, /* serial number string */
442 { "chassis.asset_tag", "None" }, /* asset tag string */
443 { "chassis.sku", "None" }, /* sku number string */
447 static const struct smbios_table_type4 smbios_type4_template
= {
448 { SMBIOS_TYPE_PROCESSOR
, sizeof (struct smbios_table_type4
), 0 },
449 1, /* socket designation string */
452 2, /* manufacturer string */
454 3, /* version string */
456 0, /* external clock frequency in mhz (0=unknown) */
457 0, /* maximum frequency in mhz (0=unknown) */
458 0, /* current frequency in mhz (0=unknown) */
459 SMBIOS_PRS_PRESENT
| SMBIOS_PRS_ENABLED
,
461 -1, /* l1 cache handle */
462 -1, /* l2 cache handle */
463 -1, /* l3 cache handle */
464 4, /* serial number string */
465 5, /* asset tag string */
466 6, /* part number string */
467 0, /* cores per socket (0=unknown) */
468 0, /* enabled cores per socket (0=unknown) */
469 0, /* threads per socket (0=unknown) */
474 static const struct smbios_string smbios_type4_strings
[] = {
475 { NULL
, " " }, /* socket designation string */
476 { NULL
, " " }, /* manufacturer string */
477 { NULL
, " " }, /* version string */
478 { NULL
, "None" }, /* serial number string */
479 { NULL
, "None" }, /* asset tag string */
480 { NULL
, "None" }, /* part number string */
484 static int smbios_type4_initializer(
485 const struct smbios_structure
*template_entry
,
486 const struct smbios_string
*template_strings
, char *curaddr
, char **endaddr
,
489 static const struct smbios_table_type16 smbios_type16_template
= {
490 { SMBIOS_TYPE_MEMARRAY
, sizeof (struct smbios_table_type16
), 0 },
494 0x80000000, /* max mem capacity in kb (0x80000000=use extended) */
495 -1, /* handle of error (if any) */
496 0, /* number of slots or sockets (TBD) */
497 0 /* extended maximum memory capacity in bytes (TBD) */
500 static int smbios_type16_initializer(
501 const struct smbios_structure
*template_entry
,
502 const struct smbios_string
*template_strings
, char *curaddr
, char **endaddr
,
505 static const struct smbios_table_type17 smbios_type17_template
= {
506 { SMBIOS_TYPE_MEMDEVICE
, sizeof (struct smbios_table_type17
), 0 },
507 -1, /* handle of physical memory array */
508 -1, /* handle of memory error data */
509 64, /* total width in bits including ecc */
510 64, /* data width in bits */
511 0, /* size in kb or mb (0x7fff=use extended)*/
513 0, /* set (0x00=none, 0xff=unknown) */
514 1, /* device locator string */
515 2, /* physical bank locator string */
518 0, /* maximum memory speed in mhz (0=unknown) */
519 3, /* manufacturer string */
520 4, /* serial number string */
521 5, /* asset tag string */
522 6, /* part number string */
523 0, /* attributes (0=unknown rank information) */
524 0, /* extended size in mb (TBD) */
525 0, /* current speed in mhz (0=unknown) */
526 0, /* minimum voltage in mv (0=unknown) */
527 0, /* maximum voltage in mv (0=unknown) */
528 0 /* configured voltage in mv (0=unknown) */
531 static const struct smbios_string smbios_type17_strings
[] = {
532 { NULL
, " " }, /* device locator string */
533 { NULL
, " " }, /* physical bank locator string */
534 { NULL
, " " }, /* manufacturer string */
535 { NULL
, "None" }, /* serial number string */
536 { NULL
, "None" }, /* asset tag string */
537 { NULL
, "None" }, /* part number string */
541 static int smbios_type17_initializer(
542 const struct smbios_structure
*template_entry
,
543 const struct smbios_string
*template_strings
, char *curaddr
, char **endaddr
,
546 static const struct smbios_table_type19 smbios_type19_template
= {
547 { SMBIOS_TYPE_MEMARRAYMAP
, sizeof (struct smbios_table_type19
), 0 },
548 0xffffffff, /* starting phys addr in kb (0xffffffff=use ext) */
549 0xffffffff, /* ending phys addr in kb (0xffffffff=use ext) */
550 -1, /* physical memory array handle */
551 1, /* number of devices that form a row */
552 0, /* extended starting phys addr in bytes (TDB) */
553 0 /* extended ending phys addr in bytes (TDB) */
556 static int smbios_type19_initializer(
557 const struct smbios_structure
*template_entry
,
558 const struct smbios_string
*template_strings
, char *curaddr
, char **endaddr
,
561 static struct smbios_table_type32 smbios_type32_template
= {
562 { SMBIOS_TYPE_BOOT
, sizeof (struct smbios_table_type32
), 0 },
563 { 0, 0, 0, 0, 0, 0 },
567 static const struct smbios_table_type127 smbios_type127_template
= {
568 { SMBIOS_TYPE_EOT
, sizeof (struct smbios_table_type127
), 0 }
571 static int smbios_generic_initializer(
572 const struct smbios_structure
*template_entry
,
573 const struct smbios_string
*template_strings
, char *curaddr
, char **endaddr
,
576 static struct smbios_template_entry smbios_template
[] = {
577 { (const struct smbios_structure
*)&smbios_type0_template
,
578 smbios_type0_strings
,
579 smbios_generic_initializer
},
580 { (const struct smbios_structure
*)&smbios_type1_template
,
581 smbios_type1_strings
,
582 smbios_type1_initializer
},
583 { (const struct smbios_structure
*)&smbios_type2_template
,
584 smbios_type2_strings
,
585 smbios_generic_initializer
},
586 { (const struct smbios_structure
*)&smbios_type3_template
,
587 smbios_type3_strings
,
588 smbios_generic_initializer
},
589 { (const struct smbios_structure
*)&smbios_type4_template
,
590 smbios_type4_strings
,
591 smbios_type4_initializer
},
592 { (const struct smbios_structure
*)&smbios_type16_template
,
594 smbios_type16_initializer
},
595 { (const struct smbios_structure
*)&smbios_type17_template
,
596 smbios_type17_strings
,
597 smbios_type17_initializer
},
598 { (const struct smbios_structure
*)&smbios_type19_template
,
600 smbios_type19_initializer
},
601 { (const struct smbios_structure
*)&smbios_type32_template
,
603 smbios_generic_initializer
},
604 { (const struct smbios_structure
*)&smbios_type127_template
,
606 smbios_generic_initializer
},
610 static uint64_t guest_lomem
, guest_himem
;
611 static uint16_t type16_handle
;
614 smbios_generic_initializer(const struct smbios_structure
*template_entry
,
615 const struct smbios_string
*template_strings
, char *curaddr
, char **endaddr
,
618 struct smbios_structure
*entry
;
620 memcpy(curaddr
, template_entry
, template_entry
->length
);
621 entry
= (struct smbios_structure
*)curaddr
;
622 entry
->handle
= *n
+ 1;
623 curaddr
+= entry
->length
;
624 if (template_strings
!= NULL
) {
627 for (i
= 0; template_strings
[i
].value
!= NULL
; i
++) {
631 if (template_strings
[i
].node
== NULL
) {
632 string
= template_strings
[i
].value
;
634 set_config_value_if_unset(
635 template_strings
[i
].node
,
636 template_strings
[i
].value
);
637 string
= get_config_value(
638 template_strings
[i
].node
);
641 len
= strlen(string
) + 1;
642 memcpy(curaddr
, string
, len
);
648 /* Minimum string section is double nul */
661 smbios_type1_initializer(const struct smbios_structure
*template_entry
,
662 const struct smbios_string
*template_strings
, char *curaddr
, char **endaddr
,
665 struct smbios_table_type1
*type1
;
666 const char *guest_uuid_str
;
668 smbios_generic_initializer(template_entry
, template_strings
,
669 curaddr
, endaddr
, n
);
670 type1
= (struct smbios_table_type1
*)curaddr
;
672 guest_uuid_str
= get_config_value("uuid");
673 if (guest_uuid_str
!= NULL
) {
677 uuid_from_string(guest_uuid_str
, &uuid
, &status
);
678 if (status
!= uuid_s_ok
) {
679 EPRINTLN("Invalid UUID");
683 uuid_enc_le(&type1
->uuid
, &uuid
);
687 char hostname
[MAXHOSTNAMELEN
];
691 * Universally unique and yet reproducible are an
692 * oxymoron, however reproducible is desirable in
695 if (gethostname(hostname
, sizeof(hostname
)))
699 vmname
= get_config_value("name");
700 MD5Update(&mdctx
, vmname
, strlen(vmname
));
701 MD5Update(&mdctx
, hostname
, sizeof(hostname
));
702 MD5Final(digest
, &mdctx
);
705 * Set the variant and version number.
708 digest
[6] |= 0x30; /* version 3 */
712 memcpy(&type1
->uuid
, digest
, sizeof (digest
));
719 smbios_type4_initializer(const struct smbios_structure
*template_entry
,
720 const struct smbios_string
*template_strings
, char *curaddr
, char **endaddr
,
725 for (i
= 0; i
< cpu_sockets
; i
++) {
726 struct smbios_table_type4
*type4
;
730 smbios_generic_initializer(template_entry
, template_strings
,
731 curaddr
, endaddr
, n
);
732 type4
= (struct smbios_table_type4
*)curaddr
;
733 p
= curaddr
+ sizeof (struct smbios_table_type4
);
735 while (p
< *endaddr
- 1) {
739 len
= sprintf(*endaddr
- 1, "CPU #%d", i
) + 1;
743 type4
->socket
= nstrings
+ 1;
744 /* Revise cores and threads after update to smbios 3.0 */
748 type4
->cores
= cpu_cores
;
749 /* This threads is total threads in a socket */
750 if (cpu_cores
* cpu_threads
> 254)
753 type4
->threads
= cpu_cores
* cpu_threads
;
761 smbios_type16_initializer(const struct smbios_structure
*template_entry
,
762 const struct smbios_string
*template_strings
, char *curaddr
, char **endaddr
,
765 struct smbios_table_type16
*type16
;
768 smbios_generic_initializer(template_entry
, template_strings
,
769 curaddr
, endaddr
, n
);
770 type16
= (struct smbios_table_type16
*)curaddr
;
771 type16
->xsize
= guest_lomem
+ guest_himem
;
772 type16
->ndevs
= guest_himem
> 0 ? 2 : 1;
778 smbios_type17_initializer(const struct smbios_structure
*template_entry
,
779 const struct smbios_string
*template_strings
, char *curaddr
, char **endaddr
,
782 struct smbios_table_type17
*type17
;
783 uint64_t memsize
, size_KB
, size_MB
;
785 smbios_generic_initializer(template_entry
, template_strings
,
786 curaddr
, endaddr
, n
);
787 type17
= (struct smbios_table_type17
*)curaddr
;
788 type17
->arrayhand
= type16_handle
;
790 memsize
= guest_lomem
+ guest_himem
;
791 size_KB
= memsize
/ 1024;
792 size_MB
= memsize
/ MB
;
794 /* A single Type 17 entry can't represent more than ~2PB RAM */
795 if (size_MB
> 0x7FFFFFFF) {
796 printf("Warning: guest memory too big for SMBIOS Type 17 table: "
797 "%luMB greater than max supported 2147483647MB\n", size_MB
);
799 size_MB
= 0x7FFFFFFF;
802 /* See SMBIOS 2.7.0 section 7.18 - Memory Device (Type 17) */
803 if (size_KB
<= 0x7FFF) {
804 /* Can represent up to 32767KB with the top bit set */
805 type17
->size
= size_KB
| (1 << 15);
806 } else if (size_MB
< 0x7FFF) {
807 /* Can represent up to 32766MB with the top bit unset */
808 type17
->size
= size_MB
& 0x7FFF;
810 type17
->size
= 0x7FFF;
812 * Can represent up to 2147483647MB (~2PB)
813 * The top bit is reserved
815 type17
->xsize
= size_MB
& 0x7FFFFFFF;
822 smbios_type19_initializer(const struct smbios_structure
*template_entry
,
823 const struct smbios_string
*template_strings
, char *curaddr
, char **endaddr
,
826 struct smbios_table_type19
*type19
;
828 smbios_generic_initializer(template_entry
, template_strings
,
829 curaddr
, endaddr
, n
);
830 type19
= (struct smbios_table_type19
*)curaddr
;
831 type19
->arrayhand
= type16_handle
;
833 type19
->xeaddr
= guest_lomem
;
835 if (guest_himem
> 0) {
837 smbios_generic_initializer(template_entry
, template_strings
,
838 curaddr
, endaddr
, n
);
839 type19
= (struct smbios_table_type19
*)curaddr
;
840 type19
->arrayhand
= type16_handle
;
841 type19
->xsaddr
= 4*GB
;
842 type19
->xeaddr
= type19
->xsaddr
+ guest_himem
;
849 smbios_ep_initializer(struct smbios_entry_point
*smbios_ep
, uint32_t staddr
)
851 memset(smbios_ep
, 0, sizeof(*smbios_ep
));
852 memcpy(smbios_ep
->eanchor
, SMBIOS_ENTRY_EANCHOR
,
853 SMBIOS_ENTRY_EANCHORLEN
);
854 smbios_ep
->eplen
= 0x1F;
855 assert(sizeof (struct smbios_entry_point
) == smbios_ep
->eplen
);
856 smbios_ep
->major
= 2;
857 smbios_ep
->minor
= 6;
858 smbios_ep
->revision
= 0;
859 memcpy(smbios_ep
->ianchor
, SMBIOS_ENTRY_IANCHOR
,
860 SMBIOS_ENTRY_IANCHORLEN
);
861 smbios_ep
->staddr
= staddr
;
862 smbios_ep
->bcdrev
= (smbios_ep
->major
& 0xf) << 4 | (smbios_ep
->minor
& 0xf);
866 smbios_ep_finalizer(struct smbios_entry_point
*smbios_ep
, uint16_t len
,
867 uint16_t num
, uint16_t maxssize
)
872 smbios_ep
->maxssize
= maxssize
;
873 smbios_ep
->stlen
= len
;
874 smbios_ep
->stnum
= num
;
877 for (i
= 0x10; i
< 0x1f; i
++) {
878 checksum
-= ((uint8_t *)smbios_ep
)[i
];
880 smbios_ep
->ichecksum
= checksum
;
883 for (i
= 0; i
< 0x1f; i
++) {
884 checksum
-= ((uint8_t *)smbios_ep
)[i
];
886 smbios_ep
->echecksum
= checksum
;
891 * bhyve on illumos previously used configuration keys starting with 'smbios.'
892 * to control type 1 SMBIOS information. Since these may still be present in
893 * bhyve configuration files, the following table is used to translate them
894 * to their new key names.
899 } smbios_legacy_config_map
[] = {
900 { "smbios.manufacturer", "system.manufacturer" },
901 { "smbios.family", "system.family_name" },
902 { "smbios.product", "system.product_name" },
903 { "smbios.serial", "system.serial_number" },
904 { "smbios.sku", "system.sku" },
905 { "smbios.version", "system.version" },
910 smbios_build(struct vmctx
*ctx
)
912 struct smbios_entry_point
*smbios_ep
;
915 char *curaddr
, *startaddr
, *ststartaddr
;
919 guest_lomem
= vm_get_lowmem_size(ctx
);
920 guest_himem
= vm_get_highmem_size(ctx
);
922 startaddr
= paddr_guest2host(ctx
, SMBIOS_BASE
, SMBIOS_MAX_LENGTH
);
923 if (startaddr
== NULL
) {
924 EPRINTLN("smbios table requires mapped mem");
929 /* Translate legacy illumos configuration keys */
930 for (uint_t i
= 0; i
< ARRAY_SIZE(smbios_legacy_config_map
); i
++) {
933 v
= get_config_value(smbios_legacy_config_map
[i
].oldkey
);
935 set_config_value_if_unset(
936 smbios_legacy_config_map
[i
].newkey
, v
);
943 smbios_ep
= (struct smbios_entry_point
*)curaddr
;
944 smbios_ep_initializer(smbios_ep
, SMBIOS_BASE
+
945 sizeof(struct smbios_entry_point
));
946 curaddr
+= sizeof(struct smbios_entry_point
);
947 ststartaddr
= curaddr
;
951 for (i
= 0; smbios_template
[i
].entry
!= NULL
; i
++) {
952 const struct smbios_structure
*entry
;
953 const struct smbios_string
*strings
;
954 initializer_func_t initializer
;
958 entry
= smbios_template
[i
].entry
;
959 strings
= smbios_template
[i
].strings
;
960 initializer
= smbios_template
[i
].initializer
;
962 err
= (*initializer
)(entry
, strings
, curaddr
, &endaddr
, &n
);
966 size
= endaddr
- curaddr
;
967 assert(size
<= UINT16_MAX
);
969 maxssize
= (uint16_t)size
;
973 assert(curaddr
- startaddr
< SMBIOS_MAX_LENGTH
);
974 smbios_ep_finalizer(smbios_ep
, curaddr
- ststartaddr
, n
, maxssize
);
984 } smbios_legacy_map
[] = {
985 { 1, "product", "product_name" },
986 { 1, "serial", "serial_number" },
987 { 1, "family", "family_name" },
990 static const struct smbios_string
*smbios_tbl_map
[] = {
991 smbios_type0_strings
,
992 smbios_type1_strings
,
993 smbios_type2_strings
,
994 smbios_type3_strings
,
998 * This function accepts an option of the form
999 * type,[key=value][,key=value]...
1000 * and sets smbios data for the given type. Keys for type X are defined in the
1001 * smbios_typeX_strings tables above, but for type 1 there are also some
1002 * legacy values which were accepted in earlier versions of bhyve on illumos
1003 * which need to be mapped.
1006 smbios_parse(const char *opts
)
1008 char *buf
, *lasts
, *token
, *typekey
= NULL
;
1010 const struct smbios_string
*tbl
;
1015 if ((buf
= strdup(opts
)) == NULL
) {
1016 (void) fprintf(stderr
, "out of memory\n");
1020 if ((token
= strtok_r(buf
, ",", &lasts
)) == NULL
) {
1021 (void) fprintf(stderr
, "too few fields\n");
1025 type
= strtonum(token
, 0, 3, &errstr
);
1026 if (errstr
!= NULL
) {
1027 fprintf(stderr
, "First token (type) is %s\n", errstr
);
1031 tbl
= smbios_tbl_map
[type
];
1033 /* Extract the config key for this type */
1034 typekey
= strdup(tbl
[0].node
);
1035 if (typekey
== NULL
) {
1036 (void) fprintf(stderr
, "out of memory\n");
1040 token
= strchr(typekey
, '.');
1041 assert(token
!= NULL
);
1044 nvl
= create_config_node(typekey
);
1046 (void) fprintf(stderr
, "out of memory\n");
1050 while ((token
= strtok_r(NULL
, ",", &lasts
)) != NULL
) {
1053 if ((val
= strchr(token
, '=')) == NULL
|| val
[1] == '\0') {
1054 (void) fprintf(stderr
, "invalid key=value: '%s'\n",
1060 /* UUID is a top-level config item, but -U takes priority */
1061 if (strcmp(token
, "uuid") == 0) {
1062 set_config_value_if_unset(token
, val
);
1066 /* Translate legacy keys */
1067 for (i
= 0; i
< ARRAY_SIZE(smbios_legacy_map
); i
++) {
1068 if (type
== smbios_legacy_map
[i
].type
&&
1069 strcmp(token
, smbios_legacy_map
[i
].key
) == 0) {
1070 token
= smbios_legacy_map
[i
].val
;
1075 for (i
= 0; tbl
[i
].value
!= NULL
; i
++) {
1076 if (strcmp(tbl
[i
].node
+ strlen(typekey
) + 1,
1083 if (tbl
[i
].value
== NULL
) {
1084 (void) fprintf(stderr
,
1085 "Unknown SMBIOS key %s for type %d\n", token
, type
);
1089 set_config_value_node(nvl
, token
, val
);