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