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