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>
47 #include "smbiostbl.h"
49 #define MB (1024*1024)
50 #define GB (1024ULL*1024*1024)
52 #define SMBIOS_BASE 0xF1000
54 #define FIRMWARE_VERSION "13.0"
55 /* The SMBIOS specification defines the date format to be mm/dd/yyyy */
56 #define FIRMWARE_RELEASE_DATE "11/10/2020"
58 /* BHYVE_ACPI_BASE - SMBIOS_BASE) */
59 #define SMBIOS_MAX_LENGTH (0xF2400 - 0xF1000)
61 #define SMBIOS_TYPE_BIOS 0
62 #define SMBIOS_TYPE_SYSTEM 1
63 #define SMBIOS_TYPE_CHASSIS 3
64 #define SMBIOS_TYPE_PROCESSOR 4
65 #define SMBIOS_TYPE_MEMARRAY 16
66 #define SMBIOS_TYPE_MEMDEVICE 17
67 #define SMBIOS_TYPE_MEMARRAYMAP 19
68 #define SMBIOS_TYPE_BOOT 32
69 #define SMBIOS_TYPE_EOT 127
71 struct smbios_structure {
77 typedef int (*initializer_func_t)(struct smbios_structure *template_entry,
78 const char **template_strings, char *curaddr, char **endaddr,
79 uint16_t *n, uint16_t *size);
81 struct smbios_template_entry {
82 struct smbios_structure *entry;
84 initializer_func_t initializer;
88 * SMBIOS Structure Table Entry Point
90 #define SMBIOS_ENTRY_EANCHOR "_SM_"
91 #define SMBIOS_ENTRY_EANCHORLEN 4
92 #define SMBIOS_ENTRY_IANCHOR "_DMI_"
93 #define SMBIOS_ENTRY_IANCHORLEN 5
95 struct smbios_entry_point {
96 char eanchor[4]; /* anchor tag */
97 uint8_t echecksum; /* checksum of entry point structure */
98 uint8_t eplen; /* length in bytes of entry point */
99 uint8_t major; /* major version of the SMBIOS spec */
100 uint8_t minor; /* minor version of the SMBIOS spec */
101 uint16_t maxssize; /* maximum size in bytes of a struct */
102 uint8_t revision; /* entry point structure revision */
103 uint8_t format[5]; /* entry point rev-specific data */
104 char ianchor[5]; /* intermediate anchor tag */
105 uint8_t ichecksum; /* intermediate checksum */
106 uint16_t stlen; /* len in bytes of structure table */
107 uint32_t staddr; /* physical addr of structure table */
108 uint16_t stnum; /* number of structure table entries */
109 uint8_t bcdrev; /* BCD value representing DMI ver */
115 #define SMBIOS_FL_ISA 0x00000010 /* ISA is supported */
116 #define SMBIOS_FL_PCI 0x00000080 /* PCI is supported */
117 #define SMBIOS_FL_SHADOW 0x00001000 /* BIOS shadowing is allowed */
118 #define SMBIOS_FL_CDBOOT 0x00008000 /* Boot from CD is supported */
119 #define SMBIOS_FL_SELBOOT 0x00010000 /* Selectable Boot supported */
120 #define SMBIOS_FL_EDD 0x00080000 /* EDD Spec is supported */
122 #define SMBIOS_XB1_FL_ACPI 0x00000001 /* ACPI is supported */
124 #define SMBIOS_XB2_FL_BBS 0x00000001 /* BIOS Boot Specification */
125 #define SMBIOS_XB2_FL_VM 0x00000010 /* Virtual Machine */
127 struct smbios_table_type0 {
128 struct smbios_structure header;
129 uint8_t vendor; /* vendor string */
130 uint8_t version; /* version string */
131 uint16_t segment; /* address segment location */
132 uint8_t rel_date; /* release date */
133 uint8_t size; /* rom size */
134 uint64_t cflags; /* characteristics */
135 uint8_t xc_bytes[2]; /* characteristics ext bytes */
136 uint8_t sb_major_rel; /* system bios version */
137 uint8_t sb_minor_rele;
138 uint8_t ecfw_major_rel; /* embedded ctrl fw version */
139 uint8_t ecfw_minor_rel;
145 #define SMBIOS_WAKEUP_SWITCH 0x06 /* power switch */
147 struct smbios_table_type1 {
148 struct smbios_structure header;
149 uint8_t manufacturer; /* manufacturer string */
150 uint8_t product; /* product name string */
151 uint8_t version; /* version string */
152 uint8_t serial; /* serial number string */
153 uint8_t uuid[16]; /* uuid byte array */
154 uint8_t wakeup; /* wake-up event */
155 uint8_t sku; /* sku number string */
156 uint8_t family; /* family name string */
160 * System Enclosure or Chassis
162 #define SMBIOS_CHT_UNKNOWN 0x02 /* unknown */
164 #define SMBIOS_CHST_SAFE 0x03 /* safe */
166 #define SMBIOS_CHSC_NONE 0x03 /* none */
168 struct smbios_table_type3 {
169 struct smbios_structure header;
170 uint8_t manufacturer; /* manufacturer string */
171 uint8_t type; /* type */
172 uint8_t version; /* version string */
173 uint8_t serial; /* serial number string */
174 uint8_t asset; /* asset tag string */
175 uint8_t bustate; /* boot-up state */
176 uint8_t psstate; /* power supply state */
177 uint8_t tstate; /* thermal state */
178 uint8_t security; /* security status */
179 uint8_t uheight; /* height in 'u's */
180 uint8_t cords; /* number of power cords */
181 uint8_t elems; /* number of element records */
182 uint8_t elemlen; /* length of records */
183 uint8_t sku; /* sku number string */
187 * Processor Information
189 #define SMBIOS_PRT_CENTRAL 0x03 /* central processor */
191 #define SMBIOS_PRF_OTHER 0x01 /* other */
193 #define SMBIOS_PRS_PRESENT 0x40 /* socket is populated */
194 #define SMBIOS_PRS_ENABLED 0x1 /* enabled */
196 #define SMBIOS_PRU_NONE 0x06 /* none */
198 #define SMBIOS_PFL_64B 0x04 /* 64-bit capable */
200 struct smbios_table_type4 {
201 struct smbios_structure header;
202 uint8_t socket; /* socket designation string */
203 uint8_t type; /* processor type */
204 uint8_t family; /* processor family */
205 uint8_t manufacturer; /* manufacturer string */
206 uint64_t cpuid; /* processor cpuid */
207 uint8_t version; /* version string */
208 uint8_t voltage; /* voltage */
209 uint16_t clkspeed; /* ext clock speed in mhz */
210 uint16_t maxspeed; /* maximum speed in mhz */
211 uint16_t curspeed; /* current speed in mhz */
212 uint8_t status; /* status */
213 uint8_t upgrade; /* upgrade */
214 uint16_t l1handle; /* l1 cache handle */
215 uint16_t l2handle; /* l2 cache handle */
216 uint16_t l3handle; /* l3 cache handle */
217 uint8_t serial; /* serial number string */
218 uint8_t asset; /* asset tag string */
219 uint8_t part; /* part number string */
220 uint8_t cores; /* cores per socket */
221 uint8_t ecores; /* enabled cores */
222 uint8_t threads; /* threads per socket */
223 uint16_t cflags; /* processor characteristics */
224 uint16_t family2; /* processor family 2 */
228 * Physical Memory Array
230 #define SMBIOS_MAL_SYSMB 0x03 /* system board or motherboard */
232 #define SMBIOS_MAU_SYSTEM 0x03 /* system memory */
234 #define SMBIOS_MAE_NONE 0x03 /* none */
236 struct smbios_table_type16 {
237 struct smbios_structure header;
238 uint8_t location; /* physical device location */
239 uint8_t use; /* device functional purpose */
240 uint8_t ecc; /* err detect/correct method */
241 uint32_t size; /* max mem capacity in kb */
242 uint16_t errhand; /* handle of error (if any) */
243 uint16_t ndevs; /* num of slots or sockets */
244 uint64_t xsize; /* max mem capacity in bytes */
250 #define SMBIOS_MDFF_UNKNOWN 0x02 /* unknown */
252 #define SMBIOS_MDT_UNKNOWN 0x02 /* unknown */
254 #define SMBIOS_MDF_UNKNOWN 0x0004 /* unknown */
256 struct smbios_table_type17 {
257 struct smbios_structure header;
258 uint16_t arrayhand; /* handle of physl mem array */
259 uint16_t errhand; /* handle of mem error data */
260 uint16_t twidth; /* total width in bits */
261 uint16_t dwidth; /* data width in bits */
262 uint16_t size; /* size in kb or mb */
263 uint8_t form; /* form factor */
264 uint8_t set; /* set */
265 uint8_t dloc; /* device locator string */
266 uint8_t bloc; /* phys bank locator string */
267 uint8_t type; /* memory type */
268 uint16_t flags; /* memory characteristics */
269 uint16_t maxspeed; /* maximum speed in mhz */
270 uint8_t manufacturer; /* manufacturer string */
271 uint8_t serial; /* serial number string */
272 uint8_t asset; /* asset tag string */
273 uint8_t part; /* part number string */
274 uint8_t attributes; /* attributes */
275 uint32_t xsize; /* extended size in mb */
276 uint16_t curspeed; /* current speed in mhz */
277 uint16_t minvoltage; /* minimum voltage */
278 uint16_t maxvoltage; /* maximum voltage */
279 uint16_t curvoltage; /* configured voltage */
283 * Memory Array Mapped Address
285 struct smbios_table_type19 {
286 struct smbios_structure header;
287 uint32_t saddr; /* start phys addr in kb */
288 uint32_t eaddr; /* end phys addr in kb */
289 uint16_t arrayhand; /* physical mem array handle */
290 uint8_t width; /* num of dev in row */
291 uint64_t xsaddr; /* start phys addr in bytes */
292 uint64_t xeaddr; /* end phys addr in bytes */
296 * System Boot Information
298 #define SMBIOS_BOOT_NORMAL 0 /* no errors detected */
300 struct smbios_table_type32 {
301 struct smbios_structure header;
303 uint8_t status; /* boot status */
309 struct smbios_table_type127 {
310 struct smbios_structure header;
313 struct smbios_table_type0 smbios_type0_template = {
314 { SMBIOS_TYPE_BIOS, sizeof (struct smbios_table_type0), 0 },
315 1, /* bios vendor string */
316 2, /* bios version string */
317 0xF000, /* bios address segment location */
318 3, /* bios release date */
319 0x0, /* bios size (64k * (n + 1) is the size in bytes) */
320 SMBIOS_FL_ISA | SMBIOS_FL_PCI | SMBIOS_FL_SHADOW |
321 SMBIOS_FL_CDBOOT | SMBIOS_FL_EDD,
322 { SMBIOS_XB1_FL_ACPI, SMBIOS_XB2_FL_BBS | SMBIOS_XB2_FL_VM },
323 0x0, /* bios major release */
324 0x0, /* bios minor release */
325 0xff, /* embedded controller firmware major release */
326 0xff /* embedded controller firmware minor release */
329 const char *smbios_type0_strings[] = {
330 "BHYVE", /* vendor string */
331 FIRMWARE_VERSION, /* bios version string */
332 FIRMWARE_RELEASE_DATE, /* bios release date string */
336 struct smbios_table_type1 smbios_type1_template = {
337 { SMBIOS_TYPE_SYSTEM, sizeof (struct smbios_table_type1), 0 },
338 1, /* manufacturer string */
339 2, /* product string */
340 3, /* version string */
341 4, /* serial number string */
343 SMBIOS_WAKEUP_SWITCH,
345 6 /* family string */
348 static int smbios_type1_initializer(struct smbios_structure *template_entry,
349 const char **template_strings, char *curaddr, char **endaddr,
350 uint16_t *n, uint16_t *size);
352 const char *smbios_type1_strings[] = {
353 "FreeBSD", /* manufacturer string */
354 "BHYVE", /* product name string */
355 "1.0", /* version string */
356 "None", /* serial number string */
357 "None", /* sku string */
358 "Virtual Machine", /* family name string */
362 struct smbios_table_type3 smbios_type3_template = {
363 { SMBIOS_TYPE_CHASSIS, sizeof (struct smbios_table_type3), 0 },
364 1, /* manufacturer string */
366 2, /* version string */
367 3, /* serial number string */
368 4, /* asset tag string */
373 0, /* height in 'u's (0=enclosure height unspecified) */
374 0, /* number of power cords (0=number unspecified) */
375 0, /* number of contained element records */
376 0, /* length of records */
377 5 /* sku number string */
380 const char *smbios_type3_strings[] = {
381 "FreeBSD", /* manufacturer string */
382 "1.0", /* version string */
383 "None", /* serial number string */
384 "None", /* asset tag string */
385 "None", /* sku number string */
389 struct smbios_table_type4 smbios_type4_template = {
390 { SMBIOS_TYPE_PROCESSOR, sizeof (struct smbios_table_type4), 0 },
391 1, /* socket designation string */
394 2, /* manufacturer string */
396 3, /* version string */
398 0, /* external clock frequency in mhz (0=unknown) */
399 0, /* maximum frequency in mhz (0=unknown) */
400 0, /* current frequency in mhz (0=unknown) */
401 SMBIOS_PRS_PRESENT | SMBIOS_PRS_ENABLED,
403 -1, /* l1 cache handle */
404 -1, /* l2 cache handle */
405 -1, /* l3 cache handle */
406 4, /* serial number string */
407 5, /* asset tag string */
408 6, /* part number string */
409 0, /* cores per socket (0=unknown) */
410 0, /* enabled cores per socket (0=unknown) */
411 0, /* threads per socket (0=unknown) */
416 const char *smbios_type4_strings[] = {
417 " ", /* socket designation string */
418 " ", /* manufacturer string */
419 " ", /* version string */
420 "None", /* serial number string */
421 "None", /* asset tag string */
422 "None", /* part number string */
426 static int smbios_type4_initializer(struct smbios_structure *template_entry,
427 const char **template_strings, char *curaddr, char **endaddr,
428 uint16_t *n, uint16_t *size);
430 struct smbios_table_type16 smbios_type16_template = {
431 { SMBIOS_TYPE_MEMARRAY, sizeof (struct smbios_table_type16), 0 },
435 0x80000000, /* max mem capacity in kb (0x80000000=use extended) */
436 -1, /* handle of error (if any) */
437 0, /* number of slots or sockets (TBD) */
438 0 /* extended maximum memory capacity in bytes (TBD) */
441 static int smbios_type16_initializer(struct smbios_structure *template_entry,
442 const char **template_strings, char *curaddr, char **endaddr,
443 uint16_t *n, uint16_t *size);
445 struct smbios_table_type17 smbios_type17_template = {
446 { SMBIOS_TYPE_MEMDEVICE, sizeof (struct smbios_table_type17), 0 },
447 -1, /* handle of physical memory array */
448 -1, /* handle of memory error data */
449 64, /* total width in bits including ecc */
450 64, /* data width in bits */
451 0, /* size in kb or mb (0x7fff=use extended)*/
453 0, /* set (0x00=none, 0xff=unknown) */
454 1, /* device locator string */
455 2, /* physical bank locator string */
458 0, /* maximum memory speed in mhz (0=unknown) */
459 3, /* manufacturer string */
460 4, /* serial number string */
461 5, /* asset tag string */
462 6, /* part number string */
463 0, /* attributes (0=unknown rank information) */
464 0, /* extended size in mb (TBD) */
465 0, /* current speed in mhz (0=unknown) */
466 0, /* minimum voltage in mv (0=unknown) */
467 0, /* maximum voltage in mv (0=unknown) */
468 0 /* configured voltage in mv (0=unknown) */
471 const char *smbios_type17_strings[] = {
472 " ", /* device locator string */
473 " ", /* physical bank locator string */
474 " ", /* manufacturer string */
475 "None", /* serial number string */
476 "None", /* asset tag string */
477 "None", /* part number string */
481 static int smbios_type17_initializer(struct smbios_structure *template_entry,
482 const char **template_strings, char *curaddr, char **endaddr,
483 uint16_t *n, uint16_t *size);
485 struct smbios_table_type19 smbios_type19_template = {
486 { SMBIOS_TYPE_MEMARRAYMAP, sizeof (struct smbios_table_type19), 0 },
487 0xffffffff, /* starting phys addr in kb (0xffffffff=use ext) */
488 0xffffffff, /* ending phys addr in kb (0xffffffff=use ext) */
489 -1, /* physical memory array handle */
490 1, /* number of devices that form a row */
491 0, /* extended starting phys addr in bytes (TDB) */
492 0 /* extended ending phys addr in bytes (TDB) */
495 static int smbios_type19_initializer(struct smbios_structure *template_entry,
496 const char **template_strings, char *curaddr, char **endaddr,
497 uint16_t *n, uint16_t *size);
499 struct smbios_table_type32 smbios_type32_template = {
500 { SMBIOS_TYPE_BOOT, sizeof (struct smbios_table_type32), 0 },
501 { 0, 0, 0, 0, 0, 0 },
505 struct smbios_table_type127 smbios_type127_template = {
506 { SMBIOS_TYPE_EOT, sizeof (struct smbios_table_type127), 0 }
509 static int smbios_generic_initializer(struct smbios_structure *template_entry,
510 const char **template_strings, char *curaddr, char **endaddr,
511 uint16_t *n, uint16_t *size);
513 static struct smbios_template_entry smbios_template[] = {
514 { (struct smbios_structure *)&smbios_type0_template,
515 smbios_type0_strings,
516 smbios_generic_initializer },
517 { (struct smbios_structure *)&smbios_type1_template,
518 smbios_type1_strings,
519 smbios_type1_initializer },
520 { (struct smbios_structure *)&smbios_type3_template,
521 smbios_type3_strings,
522 smbios_generic_initializer },
523 { (struct smbios_structure *)&smbios_type4_template,
524 smbios_type4_strings,
525 smbios_type4_initializer },
526 { (struct smbios_structure *)&smbios_type16_template,
528 smbios_type16_initializer },
529 { (struct smbios_structure *)&smbios_type17_template,
530 smbios_type17_strings,
531 smbios_type17_initializer },
532 { (struct smbios_structure *)&smbios_type19_template,
534 smbios_type19_initializer },
535 { (struct smbios_structure *)&smbios_type32_template,
537 smbios_generic_initializer },
538 { (struct smbios_structure *)&smbios_type127_template,
540 smbios_generic_initializer },
544 static uint64_t guest_lomem, guest_himem;
545 static uint16_t type16_handle;
548 smbios_generic_initializer(struct smbios_structure *template_entry,
549 const char **template_strings, char *curaddr, char **endaddr,
550 uint16_t *n, uint16_t *size)
552 struct smbios_structure *entry;
554 memcpy(curaddr, template_entry, template_entry->length);
555 entry = (struct smbios_structure *)curaddr;
556 entry->handle = *n + 1;
557 curaddr += entry->length;
558 if (template_strings != NULL) {
561 for (i = 0; template_strings[i] != NULL; i++) {
565 string = template_strings[i];
566 len = strlen(string) + 1;
567 memcpy(curaddr, string, len);
573 /* Minimum string section is double nul */
586 smbios_type1_initializer(struct smbios_structure *template_entry,
587 const char **template_strings, char *curaddr, char **endaddr,
588 uint16_t *n, uint16_t *size)
590 struct smbios_table_type1 *type1;
592 smbios_generic_initializer(template_entry, template_strings,
593 curaddr, endaddr, n, size);
594 type1 = (struct smbios_table_type1 *)curaddr;
596 if (guest_uuid_str != NULL) {
600 uuid_from_string(guest_uuid_str, &uuid, &status);
601 if (status != uuid_s_ok)
604 uuid_enc_le(&type1->uuid, &uuid);
608 char hostname[MAXHOSTNAMELEN];
611 * Universally unique and yet reproducible are an
612 * oxymoron, however reproducible is desirable in
615 if (gethostname(hostname, sizeof(hostname)))
619 MD5Update(&mdctx, vmname, strlen(vmname));
620 MD5Update(&mdctx, hostname, sizeof(hostname));
621 MD5Final(digest, &mdctx);
624 * Set the variant and version number.
627 digest[6] |= 0x30; /* version 3 */
631 memcpy(&type1->uuid, digest, sizeof (digest));
638 smbios_type4_initializer(struct smbios_structure *template_entry,
639 const char **template_strings, char *curaddr, char **endaddr,
640 uint16_t *n, uint16_t *size)
644 for (i = 0; i < sockets; i++) {
645 struct smbios_table_type4 *type4;
649 smbios_generic_initializer(template_entry, template_strings,
650 curaddr, endaddr, n, size);
651 type4 = (struct smbios_table_type4 *)curaddr;
652 p = curaddr + sizeof (struct smbios_table_type4);
654 while (p < *endaddr - 1) {
658 len = sprintf(*endaddr - 1, "CPU #%d", i) + 1;
662 type4->socket = nstrings + 1;
663 /* Revise cores and threads after update to smbios 3.0 */
667 type4->cores = cores;
668 /* This threads is total threads in a socket */
669 if ((cores * threads) > 254)
672 type4->threads = (cores * threads);
680 smbios_type16_initializer(struct smbios_structure *template_entry,
681 const char **template_strings, char *curaddr, char **endaddr,
682 uint16_t *n, uint16_t *size)
684 struct smbios_table_type16 *type16;
687 smbios_generic_initializer(template_entry, template_strings,
688 curaddr, endaddr, n, size);
689 type16 = (struct smbios_table_type16 *)curaddr;
690 type16->xsize = guest_lomem + guest_himem;
691 type16->ndevs = guest_himem > 0 ? 2 : 1;
697 smbios_type17_initializer(struct smbios_structure *template_entry,
698 const char **template_strings, char *curaddr, char **endaddr,
699 uint16_t *n, uint16_t *size)
701 struct smbios_table_type17 *type17;
702 uint64_t memsize, size_KB, size_MB;
704 smbios_generic_initializer(template_entry, template_strings,
705 curaddr, endaddr, n, size);
706 type17 = (struct smbios_table_type17 *)curaddr;
707 type17->arrayhand = type16_handle;
709 memsize = guest_lomem + guest_himem;
710 size_KB = memsize / 1024;
711 size_MB = memsize / MB;
713 /* A single Type 17 entry can't represent more than ~2PB RAM */
714 if (size_MB > 0x7FFFFFFF) {
715 printf("Warning: guest memory too big for SMBIOS Type 17 table: "
716 "%luMB greater than max supported 2147483647MB\n", size_MB);
718 size_MB = 0x7FFFFFFF;
721 /* See SMBIOS 2.7.0 section 7.18 - Memory Device (Type 17) */
722 if (size_KB <= 0x7FFF) {
723 /* Can represent up to 32767KB with the top bit set */
724 type17->size = size_KB | (1 << 15);
725 } else if (size_MB < 0x7FFF) {
726 /* Can represent up to 32766MB with the top bit unset */
727 type17->size = size_MB & 0x7FFF;
729 type17->size = 0x7FFF;
731 * Can represent up to 2147483647MB (~2PB)
732 * The top bit is reserved
734 type17->xsize = size_MB & 0x7FFFFFFF;
741 smbios_type19_initializer(struct smbios_structure *template_entry,
742 const char **template_strings, char *curaddr, char **endaddr,
743 uint16_t *n, uint16_t *size)
745 struct smbios_table_type19 *type19;
747 smbios_generic_initializer(template_entry, template_strings,
748 curaddr, endaddr, n, size);
749 type19 = (struct smbios_table_type19 *)curaddr;
750 type19->arrayhand = type16_handle;
752 type19->xeaddr = guest_lomem;
754 if (guest_himem > 0) {
756 smbios_generic_initializer(template_entry, template_strings,
757 curaddr, endaddr, n, size);
758 type19 = (struct smbios_table_type19 *)curaddr;
759 type19->arrayhand = type16_handle;
760 type19->xsaddr = 4*GB;
761 type19->xeaddr = type19->xsaddr + guest_himem;
768 smbios_ep_initializer(struct smbios_entry_point *smbios_ep, uint32_t staddr)
770 memset(smbios_ep, 0, sizeof(*smbios_ep));
771 memcpy(smbios_ep->eanchor, SMBIOS_ENTRY_EANCHOR,
772 SMBIOS_ENTRY_EANCHORLEN);
773 smbios_ep->eplen = 0x1F;
774 assert(sizeof (struct smbios_entry_point) == smbios_ep->eplen);
775 smbios_ep->major = 2;
776 smbios_ep->minor = 6;
777 smbios_ep->revision = 0;
778 memcpy(smbios_ep->ianchor, SMBIOS_ENTRY_IANCHOR,
779 SMBIOS_ENTRY_IANCHORLEN);
780 smbios_ep->staddr = staddr;
781 smbios_ep->bcdrev = (smbios_ep->major & 0xf) << 4 | (smbios_ep->minor & 0xf);
785 smbios_ep_finalizer(struct smbios_entry_point *smbios_ep, uint16_t len,
786 uint16_t num, uint16_t maxssize)
791 smbios_ep->maxssize = maxssize;
792 smbios_ep->stlen = len;
793 smbios_ep->stnum = num;
796 for (i = 0x10; i < 0x1f; i++) {
797 checksum -= ((uint8_t *)smbios_ep)[i];
799 smbios_ep->ichecksum = checksum;
802 for (i = 0; i < 0x1f; i++) {
803 checksum -= ((uint8_t *)smbios_ep)[i];
805 smbios_ep->echecksum = checksum;
809 smbios_build(struct vmctx *ctx)
811 struct smbios_entry_point *smbios_ep;
814 char *curaddr, *startaddr, *ststartaddr;
818 guest_lomem = vm_get_lowmem_size(ctx);
819 guest_himem = vm_get_highmem_size(ctx);
821 startaddr = paddr_guest2host(ctx, SMBIOS_BASE, SMBIOS_MAX_LENGTH);
822 if (startaddr == NULL) {
823 EPRINTLN("smbios table requires mapped mem");
829 smbios_ep = (struct smbios_entry_point *)curaddr;
830 smbios_ep_initializer(smbios_ep, SMBIOS_BASE +
831 sizeof(struct smbios_entry_point));
832 curaddr += sizeof(struct smbios_entry_point);
833 ststartaddr = curaddr;
837 for (i = 0; smbios_template[i].entry != NULL; i++) {
838 struct smbios_structure *entry;
839 const char **strings;
840 initializer_func_t initializer;
844 entry = smbios_template[i].entry;
845 strings = smbios_template[i].strings;
846 initializer = smbios_template[i].initializer;
848 err = (*initializer)(entry, strings, curaddr, &endaddr,
859 assert(curaddr - startaddr < SMBIOS_MAX_LENGTH);
860 smbios_ep_finalizer(smbios_ep, curaddr - ststartaddr, n, maxssize);