]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/bhyve/smbiostbl.c
Optionally bind ktls threads to NUMA domains
[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 /* The SMBIOS specification defines the date format to be mm/dd/yyyy */
56 #define FIRMWARE_RELEASE_DATE   "11/10/2020"
57
58 /* BHYVE_ACPI_BASE - SMBIOS_BASE) */
59 #define SMBIOS_MAX_LENGTH       (0xF2400 - 0xF1000)
60
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
70
71 struct smbios_structure {
72         uint8_t         type;
73         uint8_t         length;
74         uint16_t        handle;
75 } __packed;
76
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);
80
81 struct smbios_template_entry {
82         struct smbios_structure *entry;
83         const char              **strings;
84         initializer_func_t      initializer;
85 };
86
87 /*
88  * SMBIOS Structure Table Entry Point
89  */
90 #define SMBIOS_ENTRY_EANCHOR    "_SM_"
91 #define SMBIOS_ENTRY_EANCHORLEN 4
92 #define SMBIOS_ENTRY_IANCHOR    "_DMI_"
93 #define SMBIOS_ENTRY_IANCHORLEN 5
94
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 */
110 } __packed;
111
112 /*
113  * BIOS Information
114  */
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 */
121
122 #define SMBIOS_XB1_FL_ACPI      0x00000001      /* ACPI is supported */
123
124 #define SMBIOS_XB2_FL_BBS       0x00000001      /* BIOS Boot Specification */
125 #define SMBIOS_XB2_FL_VM        0x00000010      /* Virtual Machine */
126
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;
140 } __packed;
141
142 /*
143  * System Information
144  */
145 #define SMBIOS_WAKEUP_SWITCH    0x06    /* power switch */
146
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 */
157 } __packed;
158
159 /*
160  * System Enclosure or Chassis
161  */
162 #define SMBIOS_CHT_UNKNOWN      0x02    /* unknown */
163
164 #define SMBIOS_CHST_SAFE        0x03    /* safe */
165
166 #define SMBIOS_CHSC_NONE        0x03    /* none */
167
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 */
184 } __packed;
185
186 /*
187  * Processor Information
188  */
189 #define SMBIOS_PRT_CENTRAL      0x03    /* central processor */
190
191 #define SMBIOS_PRF_OTHER        0x01    /* other */
192
193 #define SMBIOS_PRS_PRESENT      0x40    /* socket is populated */
194 #define SMBIOS_PRS_ENABLED      0x1     /* enabled */
195
196 #define SMBIOS_PRU_NONE         0x06    /* none */
197
198 #define SMBIOS_PFL_64B  0x04    /* 64-bit capable */
199
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 */
225 } __packed;
226
227 /*
228  * Physical Memory Array
229  */
230 #define SMBIOS_MAL_SYSMB        0x03    /* system board or motherboard */
231
232 #define SMBIOS_MAU_SYSTEM       0x03    /* system memory */
233
234 #define SMBIOS_MAE_NONE         0x03    /* none */
235
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 */
245 } __packed;
246
247 /*
248  * Memory Device
249  */
250 #define SMBIOS_MDFF_UNKNOWN     0x02    /* unknown */
251
252 #define SMBIOS_MDT_UNKNOWN      0x02    /* unknown */
253
254 #define SMBIOS_MDF_UNKNOWN      0x0004  /* unknown */
255
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 */
280 } __packed;
281
282 /*
283  * Memory Array Mapped Address
284  */
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 */
293 } __packed;
294
295 /*
296  * System Boot Information
297  */
298 #define SMBIOS_BOOT_NORMAL      0       /* no errors detected */
299
300 struct smbios_table_type32 {
301         struct smbios_structure header;
302         uint8_t                 reserved[6];
303         uint8_t                 status;         /* boot status */
304 } __packed;
305
306 /*
307  * End-of-Table
308  */
309 struct smbios_table_type127 {
310         struct smbios_structure header;
311 } __packed;
312
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 */
327 };
328
329 const char *smbios_type0_strings[] = {
330         "BHYVE",                /* vendor string */
331         FIRMWARE_VERSION,       /* bios version string */
332         FIRMWARE_RELEASE_DATE,  /* bios release date string */
333         NULL
334 };
335
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 */
342         { 0 },
343         SMBIOS_WAKEUP_SWITCH,
344         5,              /* sku string */
345         6               /* family string */
346 };
347
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);
351
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 */
359         NULL
360 };
361
362 struct smbios_table_type3 smbios_type3_template = {
363         { SMBIOS_TYPE_CHASSIS, sizeof (struct smbios_table_type3), 0 },
364         1,              /* manufacturer string */
365         SMBIOS_CHT_UNKNOWN,
366         2,              /* version string */
367         3,              /* serial number string */
368         4,              /* asset tag string */
369         SMBIOS_CHST_SAFE,
370         SMBIOS_CHST_SAFE,
371         SMBIOS_CHST_SAFE,
372         SMBIOS_CHSC_NONE,
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 */
378 };
379
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 */
386         NULL
387 };
388
389 struct smbios_table_type4 smbios_type4_template = {
390         { SMBIOS_TYPE_PROCESSOR, sizeof (struct smbios_table_type4), 0 },
391         1,              /* socket designation string */
392         SMBIOS_PRT_CENTRAL,
393         SMBIOS_PRF_OTHER,
394         2,              /* manufacturer string */
395         0,              /* cpuid */
396         3,              /* version string */
397         0,              /* voltage */
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,
402         SMBIOS_PRU_NONE,
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) */
412         SMBIOS_PFL_64B,
413         SMBIOS_PRF_OTHER
414 };
415
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 */
423         NULL
424 };
425
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);
429
430 struct smbios_table_type16 smbios_type16_template = {
431         { SMBIOS_TYPE_MEMARRAY, sizeof (struct smbios_table_type16),  0 },
432         SMBIOS_MAL_SYSMB,
433         SMBIOS_MAU_SYSTEM,
434         SMBIOS_MAE_NONE,
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) */
439 };
440
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);
444
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)*/
452         SMBIOS_MDFF_UNKNOWN,
453         0,              /* set (0x00=none, 0xff=unknown) */
454         1,              /* device locator string */
455         2,              /* physical bank locator string */
456         SMBIOS_MDT_UNKNOWN,
457         SMBIOS_MDF_UNKNOWN,
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) */
469 };
470
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 */
478         NULL
479 };
480
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);
484
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) */
493 };
494
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);
498
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 },
502         SMBIOS_BOOT_NORMAL
503 };
504
505 struct smbios_table_type127 smbios_type127_template = {
506         { SMBIOS_TYPE_EOT, sizeof (struct smbios_table_type127),  0 }
507 };
508
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);
512
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,
527           NULL,
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,
533           NULL,
534           smbios_type19_initializer },
535         { (struct smbios_structure *)&smbios_type32_template,
536           NULL,
537           smbios_generic_initializer },
538         { (struct smbios_structure *)&smbios_type127_template,
539           NULL,
540           smbios_generic_initializer },
541         { NULL,NULL, NULL }
542 };
543
544 static uint64_t guest_lomem, guest_himem;
545 static uint16_t type16_handle;
546
547 static int
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)
551 {
552         struct smbios_structure *entry;
553
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) {
559                 int     i;
560
561                 for (i = 0; template_strings[i] != NULL; i++) {
562                         const char *string;
563                         int len;
564
565                         string = template_strings[i];
566                         len = strlen(string) + 1;
567                         memcpy(curaddr, string, len);
568                         curaddr += len;
569                 }
570                 *curaddr = '\0';
571                 curaddr++;
572         } else {
573                 /* Minimum string section is double nul */
574                 *curaddr = '\0';
575                 curaddr++;
576                 *curaddr = '\0';
577                 curaddr++;
578         }
579         (*n)++;
580         *endaddr = curaddr;
581
582         return (0);
583 }
584
585 static int
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)
589 {
590         struct smbios_table_type1 *type1;
591
592         smbios_generic_initializer(template_entry, template_strings,
593             curaddr, endaddr, n, size);
594         type1 = (struct smbios_table_type1 *)curaddr;
595
596         if (guest_uuid_str != NULL) {
597                 uuid_t          uuid;
598                 uint32_t        status;
599
600                 uuid_from_string(guest_uuid_str, &uuid, &status);
601                 if (status != uuid_s_ok)
602                         return (-1);
603
604                 uuid_enc_le(&type1->uuid, &uuid);
605         } else {
606                 MD5_CTX         mdctx;
607                 u_char          digest[16];
608                 char            hostname[MAXHOSTNAMELEN];
609
610                 /*
611                  * Universally unique and yet reproducible are an
612                  * oxymoron, however reproducible is desirable in
613                  * this case.
614                  */
615                 if (gethostname(hostname, sizeof(hostname)))
616                         return (-1);
617
618                 MD5Init(&mdctx);
619                 MD5Update(&mdctx, vmname, strlen(vmname));
620                 MD5Update(&mdctx, hostname, sizeof(hostname));
621                 MD5Final(digest, &mdctx);
622
623                 /*
624                  * Set the variant and version number.
625                  */
626                 digest[6] &= 0x0F;
627                 digest[6] |= 0x30;      /* version 3 */
628                 digest[8] &= 0x3F;
629                 digest[8] |= 0x80;
630
631                 memcpy(&type1->uuid, digest, sizeof (digest));
632         }
633
634         return (0);
635 }
636
637 static int
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)
641 {
642         int i;
643
644         for (i = 0; i < sockets; i++) {
645                 struct smbios_table_type4 *type4;
646                 char *p;
647                 int nstrings, len;
648
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);
653                 nstrings = 0;
654                 while (p < *endaddr - 1) {
655                         if (*p++ == '\0')
656                                 nstrings++;
657                 }
658                 len = sprintf(*endaddr - 1, "CPU #%d", i) + 1;
659                 *endaddr += len - 1;
660                 *(*endaddr) = '\0';
661                 (*endaddr)++;
662                 type4->socket = nstrings + 1;
663                 /* Revise cores and threads after update to smbios 3.0 */
664                 if (cores > 254)
665                         type4->cores = 0;
666                 else
667                         type4->cores = cores;
668                 /* This threads is total threads in a socket */
669                 if ((cores * threads) > 254)
670                         type4->threads = 0;
671                 else
672                         type4->threads = (cores * threads);
673                 curaddr = *endaddr;
674         }
675
676         return (0);
677 }
678
679 static int
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)
683 {
684         struct smbios_table_type16 *type16;
685
686         type16_handle = *n;
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;
692
693         return (0);
694 }
695
696 static int
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)
700 {
701         struct smbios_table_type17 *type17;
702         uint64_t memsize, size_KB, size_MB;
703
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;
708
709         memsize = guest_lomem + guest_himem;
710         size_KB = memsize / 1024;
711         size_MB = memsize / MB;
712
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);
717
718                 size_MB = 0x7FFFFFFF;
719         }
720
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;
728         } else {
729                 type17->size = 0x7FFF;
730                 /*
731                  * Can represent up to 2147483647MB (~2PB)
732                  * The top bit is reserved
733                  */
734                 type17->xsize = size_MB & 0x7FFFFFFF;
735         }
736
737         return (0);
738 }
739
740 static int
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)
744 {
745         struct smbios_table_type19 *type19;
746
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;
751         type19->xsaddr = 0;
752         type19->xeaddr = guest_lomem;
753
754         if (guest_himem > 0) {
755                 curaddr = *endaddr;
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;
762         }
763
764         return (0);
765 }
766
767 static void
768 smbios_ep_initializer(struct smbios_entry_point *smbios_ep, uint32_t staddr)
769 {
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);
782 }
783
784 static void
785 smbios_ep_finalizer(struct smbios_entry_point *smbios_ep, uint16_t len,
786     uint16_t num, uint16_t maxssize)
787 {
788         uint8_t checksum;
789         int     i;
790
791         smbios_ep->maxssize = maxssize;
792         smbios_ep->stlen = len;
793         smbios_ep->stnum = num;
794
795         checksum = 0;
796         for (i = 0x10; i < 0x1f; i++) {
797                 checksum -= ((uint8_t *)smbios_ep)[i];
798         }
799         smbios_ep->ichecksum = checksum;
800
801         checksum = 0;
802         for (i = 0; i < 0x1f; i++) {
803                 checksum -= ((uint8_t *)smbios_ep)[i];
804         }
805         smbios_ep->echecksum = checksum;
806 }
807
808 int
809 smbios_build(struct vmctx *ctx)
810 {
811         struct smbios_entry_point       *smbios_ep;
812         uint16_t                        n;
813         uint16_t                        maxssize;
814         char                            *curaddr, *startaddr, *ststartaddr;
815         int                             i;
816         int                             err;
817
818         guest_lomem = vm_get_lowmem_size(ctx);
819         guest_himem = vm_get_highmem_size(ctx);
820
821         startaddr = paddr_guest2host(ctx, SMBIOS_BASE, SMBIOS_MAX_LENGTH);
822         if (startaddr == NULL) {
823                 EPRINTLN("smbios table requires mapped mem");
824                 return (ENOMEM);
825         }
826
827         curaddr = startaddr;
828
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;
834
835         n = 0;
836         maxssize = 0;
837         for (i = 0; smbios_template[i].entry != NULL; i++) {
838                 struct smbios_structure *entry;
839                 const char              **strings;
840                 initializer_func_t      initializer;
841                 char                    *endaddr;
842                 uint16_t                size;
843
844                 entry = smbios_template[i].entry;
845                 strings = smbios_template[i].strings;
846                 initializer = smbios_template[i].initializer;
847
848                 err = (*initializer)(entry, strings, curaddr, &endaddr,
849                     &n, &size);
850                 if (err != 0)
851                         return (err);
852
853                 if (size > maxssize)
854                         maxssize = size;
855
856                 curaddr = endaddr;
857         }
858
859         assert(curaddr - startaddr < SMBIOS_MAX_LENGTH);
860         smbios_ep_finalizer(smbios_ep, curaddr - ststartaddr, n, maxssize);
861
862         return (0);
863 }