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