xref: /freebsd/usr.sbin/bhyve/smbiostbl.c (revision cbd442efe85d9ae371581565670dfc0287afbf8e)
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause
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/param.h>
30 
31 #include <assert.h>
32 #include <err.h>
33 #include <errno.h>
34 #include <md5.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <sysexits.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 "config.h"
47 #include "debug.h"
48 #include "smbiostbl.h"
49 
50 #define	MB			(1024*1024)
51 #define	GB			(1024ULL*1024*1024)
52 
53 #define SMBIOS_BASE		0xF1000
54 
55 #define	FIRMWARE_VERSION	"14.0"
56 /* The SMBIOS specification defines the date format to be mm/dd/yyyy */
57 #define	FIRMWARE_RELEASE_DATE	"10/17/2021"
58 
59 /* BHYVE_ACPI_BASE - SMBIOS_BASE) */
60 #define	SMBIOS_MAX_LENGTH	(0xF2400 - 0xF1000)
61 
62 #define	SMBIOS_TYPE_BIOS	0
63 #define	SMBIOS_TYPE_SYSTEM	1
64 #define	SMBIOS_TYPE_BOARD	2
65 #define	SMBIOS_TYPE_CHASSIS	3
66 #define	SMBIOS_TYPE_PROCESSOR	4
67 #define	SMBIOS_TYPE_OEM		11
68 #define	SMBIOS_TYPE_MEMARRAY	16
69 #define	SMBIOS_TYPE_MEMDEVICE	17
70 #define	SMBIOS_TYPE_MEMARRAYMAP	19
71 #define	SMBIOS_TYPE_BOOT	32
72 #define	SMBIOS_TYPE_EOT		127
73 
74 struct smbios_structure {
75 	uint8_t		type;
76 	uint8_t		length;
77 	uint16_t	handle;
78 } __packed;
79 
80 struct smbios_string {
81 	const char *node;
82 	const char *value;
83 };
84 
85 typedef int (*initializer_func_t)(const struct smbios_structure *template_entry,
86     const struct smbios_string *template_strings, char *curaddr, char **endaddr,
87     uint16_t *n);
88 
89 struct smbios_template_entry {
90 	const struct smbios_structure	*entry;
91 	const struct smbios_string 	*strings;
92 	initializer_func_t		initializer;
93 };
94 
95 /*
96  * SMBIOS Structure Table Entry Point
97  */
98 #define	SMBIOS_ENTRY_EANCHOR	"_SM_"
99 #define	SMBIOS_ENTRY_EANCHORLEN	4
100 #define	SMBIOS_ENTRY_IANCHOR	"_DMI_"
101 #define	SMBIOS_ENTRY_IANCHORLEN	5
102 
103 struct smbios_entry_point {
104 	char		eanchor[4];	/* anchor tag */
105 	uint8_t		echecksum;	/* checksum of entry point structure */
106 	uint8_t		eplen;		/* length in bytes of entry point */
107 	uint8_t		major;		/* major version of the SMBIOS spec */
108 	uint8_t		minor;		/* minor version of the SMBIOS spec */
109 	uint16_t	maxssize;	/* maximum size in bytes of a struct */
110 	uint8_t		revision;	/* entry point structure revision */
111 	uint8_t		format[5];	/* entry point rev-specific data */
112 	char		ianchor[5];	/* intermediate anchor tag */
113 	uint8_t		ichecksum;	/* intermediate checksum */
114 	uint16_t	stlen;		/* len in bytes of structure table */
115 	uint32_t	staddr;		/* physical addr of structure table */
116 	uint16_t	stnum;		/* number of structure table entries */
117 	uint8_t		bcdrev;		/* BCD value representing DMI ver */
118 } __packed;
119 
120 /*
121  * BIOS Information
122  */
123 #define	SMBIOS_FL_ISA		0x00000010	/* ISA is supported */
124 #define	SMBIOS_FL_PCI		0x00000080	/* PCI is supported */
125 #define	SMBIOS_FL_SHADOW	0x00001000	/* BIOS shadowing is allowed */
126 #define	SMBIOS_FL_CDBOOT	0x00008000	/* Boot from CD is supported */
127 #define	SMBIOS_FL_SELBOOT	0x00010000	/* Selectable Boot supported */
128 #define	SMBIOS_FL_EDD		0x00080000	/* EDD Spec is supported */
129 
130 #define	SMBIOS_XB1_FL_ACPI	0x00000001	/* ACPI is supported */
131 
132 #define	SMBIOS_XB2_FL_BBS	0x00000001	/* BIOS Boot Specification */
133 #define	SMBIOS_XB2_FL_VM	0x00000010	/* Virtual Machine */
134 
135 struct smbios_table_type0 {
136 	struct smbios_structure	header;
137 	uint8_t			vendor;		/* vendor string */
138 	uint8_t			version;	/* version string */
139 	uint16_t		segment;	/* address segment location */
140 	uint8_t			rel_date;	/* release date */
141 	uint8_t			size;		/* rom size */
142 	uint64_t		cflags;		/* characteristics */
143 	uint8_t			xc_bytes[2];	/* characteristics ext bytes */
144 	uint8_t			sb_major_rel;	/* system bios version */
145 	uint8_t			sb_minor_rele;
146 	uint8_t			ecfw_major_rel;	/* embedded ctrl fw version */
147 	uint8_t			ecfw_minor_rel;
148 } __packed;
149 
150 /*
151  * System Information
152  */
153 #define	SMBIOS_WAKEUP_SWITCH	0x06	/* power switch */
154 
155 struct smbios_table_type1 {
156 	struct smbios_structure	header;
157 	uint8_t			manufacturer;	/* manufacturer string */
158 	uint8_t			product;	/* product name string */
159 	uint8_t			version;	/* version string */
160 	uint8_t			serial;		/* serial number string */
161 	uint8_t			uuid[16];	/* uuid byte array */
162 	uint8_t			wakeup;		/* wake-up event */
163 	uint8_t			sku;		/* sku number string */
164 	uint8_t			family;		/* family name string */
165 } __packed;
166 
167 /*
168  * Baseboard (or Module) Information
169  */
170 #define SMBIOS_BRF_HOSTING	0x1
171 #define SMBIOS_BRT_MOTHERBOARD	0xa
172 
173 struct smbios_table_type2 {
174 	struct smbios_structure	header;
175 	uint8_t			manufacturer;	/* manufacturer string */
176 	uint8_t			product;	/* product name string */
177 	uint8_t			version;	/* version string */
178 	uint8_t			serial;		/* serial number string */
179 	uint8_t			asset;		/* asset tag string */
180 	uint8_t			fflags;		/* feature flags */
181 	uint8_t			location;	/* location in chassis */
182 	uint16_t		chandle;	/* chassis handle */
183 	uint8_t			type;		/* board type */
184 	uint8_t			n_objs;		/* number of contained object handles */
185 } __packed;
186 
187 /*
188  * System Enclosure or Chassis
189  */
190 #define	SMBIOS_CHT_UNKNOWN	0x02	/* unknown */
191 #define	SMBIOS_CHT_DESKTOP	0x03	/* desktop */
192 
193 #define	SMBIOS_CHST_SAFE	0x03	/* safe */
194 
195 #define	SMBIOS_CHSC_NONE	0x03	/* none */
196 
197 struct smbios_table_type3 {
198 	struct smbios_structure	header;
199 	uint8_t			manufacturer;	/* manufacturer string */
200 	uint8_t			type;		/* type */
201 	uint8_t			version;	/* version string */
202 	uint8_t			serial;		/* serial number string */
203 	uint8_t			asset;		/* asset tag string */
204 	uint8_t			bustate;	/* boot-up state */
205 	uint8_t			psstate;	/* power supply state */
206 	uint8_t			tstate;		/* thermal state */
207 	uint8_t			security;	/* security status */
208 	uint32_t		oemdata;	/* OEM-specific data */
209 	uint8_t			uheight;	/* height in 'u's */
210 	uint8_t			cords;		/* number of power cords */
211 	uint8_t			elems;		/* number of element records */
212 	uint8_t			elemlen;	/* length of records */
213 	uint8_t			sku;		/* sku number string */
214 } __packed;
215 
216 /*
217  * Processor Information
218  */
219 #define	SMBIOS_PRT_CENTRAL	0x03	/* central processor */
220 
221 #define	SMBIOS_PRF_OTHER	0x01	/* other */
222 
223 #define	SMBIOS_PRS_PRESENT	0x40	/* socket is populated */
224 #define	SMBIOS_PRS_ENABLED	0x1	/* enabled */
225 
226 #define	SMBIOS_PRU_NONE		0x06	/* none */
227 
228 #define	SMBIOS_PFL_64B	0x04	/* 64-bit capable */
229 
230 struct smbios_table_type4 {
231 	struct smbios_structure	header;
232 	uint8_t			socket;		/* socket designation string */
233 	uint8_t			type;		/* processor type */
234 	uint8_t			family;		/* processor family */
235 	uint8_t			manufacturer;	/* manufacturer string */
236 	uint64_t		cpuid;		/* processor cpuid */
237 	uint8_t			version;	/* version string */
238 	uint8_t			voltage;	/* voltage */
239 	uint16_t		clkspeed;	/* ext clock speed in mhz */
240 	uint16_t		maxspeed;	/* maximum speed in mhz */
241 	uint16_t		curspeed;	/* current speed in mhz */
242 	uint8_t			status;		/* status */
243 	uint8_t			upgrade;	/* upgrade */
244 	uint16_t		l1handle;	/* l1 cache handle */
245 	uint16_t		l2handle;	/* l2 cache handle */
246 	uint16_t		l3handle;	/* l3 cache handle */
247 	uint8_t			serial;		/* serial number string */
248 	uint8_t			asset;		/* asset tag string */
249 	uint8_t			part;		/* part number string */
250 	uint8_t			cores;		/* cores per socket */
251 	uint8_t			ecores;		/* enabled cores */
252 	uint8_t			threads;	/* threads per socket */
253 	uint16_t		cflags;		/* processor characteristics */
254 	uint16_t		family2;	/* processor family 2 */
255 } __packed;
256 
257 #define SMBIOS_TYPE11_MAX_COUNT	255
258 
259 struct smbios_table_type11 {
260 	struct smbios_structure header;
261 	uint8_t                 nstrings;       /* number of oem strings to follow */
262 } __packed;
263 
264 /*
265  * Physical Memory Array
266  */
267 #define	SMBIOS_MAL_SYSMB	0x03	/* system board or motherboard */
268 
269 #define	SMBIOS_MAU_SYSTEM	0x03	/* system memory */
270 
271 #define	SMBIOS_MAE_NONE		0x03	/* none */
272 
273 struct smbios_table_type16 {
274 	struct smbios_structure	header;
275 	uint8_t			location;	/* physical device location */
276 	uint8_t			use;		/* device functional purpose */
277 	uint8_t			ecc;		/* err detect/correct method */
278 	uint32_t		size;		/* max mem capacity in kb */
279 	uint16_t		errhand;	/* handle of error (if any) */
280 	uint16_t		ndevs;		/* num of slots or sockets */
281 	uint64_t		xsize;		/* max mem capacity in bytes */
282 } __packed;
283 
284 /*
285  * Memory Device
286  */
287 #define	SMBIOS_MDFF_UNKNOWN	0x02	/* unknown */
288 
289 #define	SMBIOS_MDT_UNKNOWN	0x02	/* unknown */
290 
291 #define	SMBIOS_MDF_UNKNOWN	0x0004	/* unknown */
292 
293 struct smbios_table_type17 {
294 	struct smbios_structure	header;
295 	uint16_t		arrayhand;	/* handle of physl mem array */
296 	uint16_t		errhand;	/* handle of mem error data */
297 	uint16_t		twidth;		/* total width in bits */
298 	uint16_t		dwidth;		/* data width in bits */
299 	uint16_t		size;		/* size in kb or mb */
300 	uint8_t			form;		/* form factor */
301 	uint8_t			set;		/* set */
302 	uint8_t			dloc;		/* device locator string */
303 	uint8_t			bloc;		/* phys bank locator string */
304 	uint8_t			type;		/* memory type */
305 	uint16_t		flags;		/* memory characteristics */
306 	uint16_t		maxspeed;	/* maximum speed in mhz */
307 	uint8_t			manufacturer;	/* manufacturer string */
308 	uint8_t			serial;		/* serial number string */
309 	uint8_t			asset;		/* asset tag string */
310 	uint8_t			part;		/* part number string */
311 	uint8_t			attributes;	/* attributes */
312 	uint32_t		xsize;		/* extended size in mb */
313 	uint16_t		curspeed;	/* current speed in mhz */
314 	uint16_t		minvoltage;	/* minimum voltage */
315 	uint16_t		maxvoltage;	/* maximum voltage */
316 	uint16_t		curvoltage;	/* configured voltage */
317 } __packed;
318 
319 /*
320  * Memory Array Mapped Address
321  */
322 struct smbios_table_type19 {
323 	struct smbios_structure	header;
324 	uint32_t		saddr;		/* start phys addr in kb */
325 	uint32_t		eaddr;		/* end phys addr in kb */
326 	uint16_t		arrayhand;	/* physical mem array handle */
327 	uint8_t			width;		/* num of dev in row */
328 	uint64_t		xsaddr;		/* start phys addr in bytes */
329 	uint64_t		xeaddr;		/* end phys addr in bytes */
330 } __packed;
331 
332 /*
333  * System Boot Information
334  */
335 #define	SMBIOS_BOOT_NORMAL	0	/* no errors detected */
336 
337 struct smbios_table_type32 {
338 	struct smbios_structure	header;
339 	uint8_t			reserved[6];
340 	uint8_t			status;		/* boot status */
341 } __packed;
342 
343 /*
344  * End-of-Table
345  */
346 struct smbios_table_type127 {
347 	struct smbios_structure	header;
348 } __packed;
349 
350 static const struct smbios_table_type0 smbios_type0_template = {
351 	{ SMBIOS_TYPE_BIOS, sizeof (struct smbios_table_type0), 0 },
352 	1,	/* bios vendor string */
353 	2,	/* bios version string */
354 	0xF000,	/* bios address segment location */
355 	3,	/* bios release date */
356 	0x0,	/* bios size (64k * (n + 1) is the size in bytes) */
357 	SMBIOS_FL_ISA | SMBIOS_FL_PCI | SMBIOS_FL_SHADOW |
358 	    SMBIOS_FL_CDBOOT | SMBIOS_FL_EDD,
359 	{ SMBIOS_XB1_FL_ACPI, SMBIOS_XB2_FL_BBS | SMBIOS_XB2_FL_VM },
360 	0x0,	/* bios major release */
361 	0x0,	/* bios minor release */
362 	0xff,	/* embedded controller firmware major release */
363 	0xff	/* embedded controller firmware minor release */
364 };
365 
366 static const struct smbios_string smbios_type0_strings[] = {
367 	{ "bios.vendor", "BHYVE" },			/* vendor string */
368 	{ "bios.version", FIRMWARE_VERSION },		/* bios version string */
369 	{ "bios.release_date", FIRMWARE_RELEASE_DATE },	/* bios release date string */
370 	{ 0 }
371 };
372 
373 static const struct smbios_table_type1 smbios_type1_template = {
374 	{ SMBIOS_TYPE_SYSTEM, sizeof (struct smbios_table_type1), 0 },
375 	1,		/* manufacturer string */
376 	2,		/* product string */
377 	3,		/* version string */
378 	4,		/* serial number string */
379 	{ 0 },
380 	SMBIOS_WAKEUP_SWITCH,
381 	5,		/* sku string */
382 	6		/* family string */
383 };
384 
385 static int smbios_type1_initializer(const struct smbios_structure *template_entry,
386     const struct smbios_string *template_strings, char *curaddr, char **endaddr,
387     uint16_t *n);
388 
389 static const struct smbios_string smbios_type1_strings[] = {
390 	{ "system.manufacturer", "FreeBSD" },	     /* manufacturer string */
391 	{ "system.product_name", "BHYVE" },	     /* product string */
392 	{ "system.version", "1.0" },		     /* version string */
393 	{ "system.serial_number", "None" },	     /* serial number string */
394 	{ "system.sku", "None" },		     /* sku string */
395 	{ "system.family_name", "Virtual Machine" }, /* family string */
396 	{ 0 }
397 };
398 
399 static const struct smbios_table_type2 smbios_type2_template = {
400 	{ SMBIOS_TYPE_BOARD, sizeof (struct smbios_table_type2), 0 },
401 	1,			/* manufacturer string */
402 	2,			/* product string */
403 	3,			/* version string */
404 	4,			/* serial number string */
405 	5,			/* asset tag string */
406 	SMBIOS_BRF_HOSTING,	/* feature flags */
407 	6,			/* location string */
408 	SMBIOS_CHT_DESKTOP,	/* chassis handle */
409 	SMBIOS_BRT_MOTHERBOARD,	/* board type */
410 	0
411 };
412 
413 static const struct smbios_string smbios_type2_strings[] = {
414 	{ "board.manufacturer", "FreeBSD" },	/* manufacturer string */
415 	{ "board.product_name", "BHYVE" },	/* product name string */
416 	{ "board.version", "1.0" },		/* version string */
417 	{ "board.serial_number", "None" },	/* serial number string */
418 	{ "board.asset_tag", "None" },		/* asset tag string */
419 	{ "board.location", "None" },		/* location string */
420 	{ 0 }
421 };
422 
423 static const struct smbios_table_type3 smbios_type3_template = {
424 	{ SMBIOS_TYPE_CHASSIS, sizeof (struct smbios_table_type3), 0 },
425 	1,		/* manufacturer string */
426 	SMBIOS_CHT_UNKNOWN,
427 	2,		/* version string */
428 	3,		/* serial number string */
429 	4,		/* asset tag string */
430 	SMBIOS_CHST_SAFE,
431 	SMBIOS_CHST_SAFE,
432 	SMBIOS_CHST_SAFE,
433 	SMBIOS_CHSC_NONE,
434 	0,		/* OEM specific data, we have none */
435 	0,		/* height in 'u's (0=enclosure height unspecified) */
436 	0,		/* number of power cords (0=number unspecified) */
437 	0,		/* number of contained element records */
438 	0,		/* length of records */
439 	5		/* sku number string */
440 };
441 
442 static const struct smbios_string smbios_type3_strings[] = {
443 	{ "chassis.manufacturer", "FreeBSD" },	/* manufacturer string */
444 	{ "chassis.version", "1.0" },		/* version string */
445 	{ "chassis.serial_number", "None" },	/* serial number string */
446 	{ "chassis.asset_tag", "None" },	/* asset tag string */
447 	{ "chassis.sku", "None" },		/* sku number string */
448 	{ 0 }
449 };
450 
451 static const struct smbios_table_type4 smbios_type4_template = {
452 	{ SMBIOS_TYPE_PROCESSOR, sizeof (struct smbios_table_type4), 0 },
453 	1,		/* socket designation string */
454 	SMBIOS_PRT_CENTRAL,
455 	SMBIOS_PRF_OTHER,
456 	2,		/* manufacturer string */
457 	0,		/* cpuid */
458 	3,		/* version string */
459 	0,		/* voltage */
460 	0,		/* external clock frequency in mhz (0=unknown) */
461 	0,		/* maximum frequency in mhz (0=unknown) */
462 	0,		/* current frequency in mhz (0=unknown) */
463 	SMBIOS_PRS_PRESENT | SMBIOS_PRS_ENABLED,
464 	SMBIOS_PRU_NONE,
465 	-1,		/* l1 cache handle */
466 	-1,		/* l2 cache handle */
467 	-1,		/* l3 cache handle */
468 	4,		/* serial number string */
469 	5,		/* asset tag string */
470 	6,		/* part number string */
471 	0,		/* cores per socket (0=unknown) */
472 	0,		/* enabled cores per socket (0=unknown) */
473 	0,		/* threads per socket (0=unknown) */
474 	SMBIOS_PFL_64B,
475 	SMBIOS_PRF_OTHER
476 };
477 
478 static const struct smbios_string smbios_type4_strings[] = {
479 	{ NULL, " " },		/* socket designation string */
480 	{ NULL, " " },		/* manufacturer string */
481 	{ NULL, " " },		/* version string */
482 	{ NULL, "None" },	/* serial number string */
483 	{ NULL, "None" },	/* asset tag string */
484 	{ NULL, "None" },	/* part number string */
485 	{ 0 }
486 };
487 
488 static int smbios_type4_initializer(
489     const struct smbios_structure *template_entry,
490     const struct smbios_string *template_strings, char *curaddr, char **endaddr,
491     uint16_t *n);
492 
493 static const struct smbios_table_type11 smbios_type11_template = {
494 	{ SMBIOS_TYPE_OEM, sizeof(struct smbios_table_type11),  0 },
495 	0               /* first string */
496 };
497 
498 static int smbios_type11_initializer(const struct smbios_structure *template_entry,
499     const struct smbios_string *template_strings, char *curaddr, char **endaddr,
500     uint16_t *n);
501 
502 static const struct smbios_table_type16 smbios_type16_template = {
503 	{ SMBIOS_TYPE_MEMARRAY, sizeof (struct smbios_table_type16),  0 },
504 	SMBIOS_MAL_SYSMB,
505 	SMBIOS_MAU_SYSTEM,
506 	SMBIOS_MAE_NONE,
507 	0x80000000,	/* max mem capacity in kb (0x80000000=use extended) */
508 	-1,		/* handle of error (if any) */
509 	0,		/* number of slots or sockets (TBD) */
510 	0		/* extended maximum memory capacity in bytes (TBD) */
511 };
512 
513 static int smbios_type16_initializer(
514     const struct smbios_structure *template_entry,
515     const struct smbios_string *template_strings, char *curaddr, char **endaddr,
516     uint16_t *n);
517 
518 static const struct smbios_table_type17 smbios_type17_template = {
519 	{ SMBIOS_TYPE_MEMDEVICE, sizeof (struct smbios_table_type17),  0 },
520 	-1,		/* handle of physical memory array */
521 	-1,		/* handle of memory error data */
522 	64,		/* total width in bits including ecc */
523 	64,		/* data width in bits */
524 	0,		/* size in kb or mb (0x7fff=use extended)*/
525 	SMBIOS_MDFF_UNKNOWN,
526 	0,		/* set (0x00=none, 0xff=unknown) */
527 	1,		/* device locator string */
528 	2,		/* physical bank locator string */
529 	SMBIOS_MDT_UNKNOWN,
530 	SMBIOS_MDF_UNKNOWN,
531 	0,		/* maximum memory speed in mhz (0=unknown) */
532 	3,		/* manufacturer string */
533 	4,		/* serial number string */
534 	5,		/* asset tag string */
535 	6,		/* part number string */
536 	0,		/* attributes (0=unknown rank information) */
537 	0,		/* extended size in mb (TBD) */
538 	0,		/* current speed in mhz (0=unknown) */
539 	0,		/* minimum voltage in mv (0=unknown) */
540 	0,		/* maximum voltage in mv (0=unknown) */
541 	0		/* configured voltage in mv (0=unknown) */
542 };
543 
544 static const struct smbios_string smbios_type17_strings[] = {
545 	{ NULL, " " },		/* device locator string */
546 	{ NULL, " " },		/* physical bank locator string */
547 	{ NULL, " " },		/* manufacturer string */
548 	{ NULL, "None" },	/* serial number string */
549 	{ NULL, "None" },	/* asset tag string */
550 	{ NULL, "None" },	/* part number string */
551 	{ 0 }
552 };
553 
554 static int smbios_type17_initializer(
555     const struct smbios_structure *template_entry,
556     const struct smbios_string *template_strings, char *curaddr, char **endaddr,
557     uint16_t *n);
558 
559 static const struct smbios_table_type19 smbios_type19_template = {
560 	{ SMBIOS_TYPE_MEMARRAYMAP, sizeof (struct smbios_table_type19),  0 },
561 	0xffffffff,	/* starting phys addr in kb (0xffffffff=use ext) */
562 	0xffffffff,	/* ending phys addr in kb (0xffffffff=use ext) */
563 	-1,		/* physical memory array handle */
564 	1,		/* number of devices that form a row */
565 	0,		/* extended starting phys addr in bytes (TDB) */
566 	0		/* extended ending phys addr in bytes (TDB) */
567 };
568 
569 static int smbios_type19_initializer(
570     const struct smbios_structure *template_entry,
571     const struct smbios_string *template_strings, char *curaddr, char **endaddr,
572     uint16_t *n);
573 
574 static struct smbios_table_type32 smbios_type32_template = {
575 	{ SMBIOS_TYPE_BOOT, sizeof (struct smbios_table_type32),  0 },
576 	{ 0, 0, 0, 0, 0, 0 },
577 	SMBIOS_BOOT_NORMAL
578 };
579 
580 static const struct smbios_table_type127 smbios_type127_template = {
581 	{ SMBIOS_TYPE_EOT, sizeof (struct smbios_table_type127),  0 }
582 };
583 
584 static int smbios_generic_initializer(
585     const struct smbios_structure *template_entry,
586     const struct smbios_string *template_strings, char *curaddr, char **endaddr,
587     uint16_t *n);
588 
589 static struct smbios_template_entry smbios_template[] = {
590 	{ (const struct smbios_structure *)&smbios_type0_template,
591 	  smbios_type0_strings,
592 	  smbios_generic_initializer },
593 	{ (const struct smbios_structure *)&smbios_type1_template,
594 	  smbios_type1_strings,
595 	  smbios_type1_initializer },
596 	{ (const struct smbios_structure *)&smbios_type2_template,
597 	  smbios_type2_strings,
598 	  smbios_generic_initializer },
599 	{ (const struct smbios_structure *)&smbios_type3_template,
600 	  smbios_type3_strings,
601 	  smbios_generic_initializer },
602 	{ (const struct smbios_structure *)&smbios_type4_template,
603 	  smbios_type4_strings,
604 	  smbios_type4_initializer },
605 	{ (const struct smbios_structure *)&smbios_type11_template,
606 	  NULL,
607 	  smbios_type11_initializer },
608 	{ (const struct smbios_structure *)&smbios_type16_template,
609 	  NULL,
610 	  smbios_type16_initializer },
611 	{ (const struct smbios_structure *)&smbios_type17_template,
612 	  smbios_type17_strings,
613 	  smbios_type17_initializer },
614 	{ (const struct smbios_structure *)&smbios_type19_template,
615 	  NULL,
616 	  smbios_type19_initializer },
617 	{ (const struct smbios_structure *)&smbios_type32_template,
618 	  NULL,
619 	  smbios_generic_initializer },
620 	{ (const struct smbios_structure *)&smbios_type127_template,
621 	  NULL,
622 	  smbios_generic_initializer },
623 	{ NULL,NULL, NULL }
624 };
625 
626 static uint64_t guest_lomem, guest_himem, guest_himem_base;
627 static uint16_t type16_handle;
628 
629 static int
smbios_generic_initializer(const struct smbios_structure * template_entry,const struct smbios_string * template_strings,char * curaddr,char ** endaddr,uint16_t * n)630 smbios_generic_initializer(const struct smbios_structure *template_entry,
631     const struct smbios_string *template_strings, char *curaddr, char **endaddr,
632     uint16_t *n)
633 {
634 	struct smbios_structure *entry;
635 
636 	memcpy(curaddr, template_entry, template_entry->length);
637 	entry = (struct smbios_structure *)curaddr;
638 	entry->handle = *n + 1;
639 	curaddr += entry->length;
640 	if (template_strings != NULL) {
641 		int	i;
642 
643 		for (i = 0; template_strings[i].value != NULL; i++) {
644 			const char *string;
645 			int len;
646 
647 			if (template_strings[i].node == NULL) {
648 				string = template_strings[i].value;
649 			} else {
650 				set_config_value_if_unset(
651 				    template_strings[i].node,
652 				    template_strings[i].value);
653 				string = get_config_value(
654 				    template_strings[i].node);
655 			}
656 
657 			len = strlen(string) + 1;
658 			memcpy(curaddr, string, len);
659 			curaddr += len;
660 		}
661 		*curaddr = '\0';
662 		curaddr++;
663 	} else {
664 		/* Minimum string section is double nul */
665 		*curaddr = '\0';
666 		curaddr++;
667 		*curaddr = '\0';
668 		curaddr++;
669 	}
670 	(*n)++;
671 	*endaddr = curaddr;
672 
673 	return (0);
674 }
675 
676 static int
smbios_type1_initializer(const struct smbios_structure * template_entry,const struct smbios_string * template_strings,char * curaddr,char ** endaddr,uint16_t * n)677 smbios_type1_initializer(const struct smbios_structure *template_entry,
678     const struct smbios_string *template_strings, char *curaddr, char **endaddr,
679     uint16_t *n)
680 {
681 	struct smbios_table_type1 *type1;
682 	const char *guest_uuid_str;
683 
684 	smbios_generic_initializer(template_entry, template_strings,
685 	    curaddr, endaddr, n);
686 	type1 = (struct smbios_table_type1 *)curaddr;
687 
688 	guest_uuid_str = get_config_value("uuid");
689 	if (guest_uuid_str != NULL) {
690 		uuid_t		uuid;
691 		uint32_t	status;
692 
693 		uuid_from_string(guest_uuid_str, &uuid, &status);
694 		if (status != uuid_s_ok) {
695 			EPRINTLN("Invalid UUID");
696 			return (-1);
697 		}
698 
699 		uuid_enc_le(&type1->uuid, &uuid);
700 	} else {
701 		MD5_CTX		mdctx;
702 		u_char		digest[16];
703 		char		hostname[MAXHOSTNAMELEN];
704 		const char	*vmname;
705 
706 		/*
707 		 * Universally unique and yet reproducible are an
708 		 * oxymoron, however reproducible is desirable in
709 		 * this case.
710 		 */
711 		if (gethostname(hostname, sizeof(hostname)))
712 			return (-1);
713 
714 		MD5Init(&mdctx);
715 		vmname = get_config_value("name");
716 		MD5Update(&mdctx, vmname, strlen(vmname));
717 		MD5Update(&mdctx, hostname, sizeof(hostname));
718 		MD5Final(digest, &mdctx);
719 
720 		/*
721 		 * Set the variant and version number.
722 		 */
723 		digest[6] &= 0x0F;
724 		digest[6] |= 0x30;	/* version 3 */
725 		digest[8] &= 0x3F;
726 		digest[8] |= 0x80;
727 
728 		memcpy(&type1->uuid, digest, sizeof (digest));
729 	}
730 
731 	return (0);
732 }
733 
734 static int
smbios_type4_initializer(const struct smbios_structure * template_entry,const struct smbios_string * template_strings,char * curaddr,char ** endaddr,uint16_t * n)735 smbios_type4_initializer(const struct smbios_structure *template_entry,
736     const struct smbios_string *template_strings, char *curaddr, char **endaddr,
737     uint16_t *n)
738 {
739 	int i;
740 
741 	for (i = 0; i < cpu_sockets; i++) {
742 		struct smbios_table_type4 *type4;
743 		char *p;
744 		int nstrings, len;
745 
746 		smbios_generic_initializer(template_entry, template_strings,
747 		    curaddr, endaddr, n);
748 		type4 = (struct smbios_table_type4 *)curaddr;
749 		p = curaddr + sizeof (struct smbios_table_type4);
750 		nstrings = 0;
751 		while (p < *endaddr - 1) {
752 			if (*p++ == '\0')
753 				nstrings++;
754 		}
755 		len = sprintf(*endaddr - 1, "CPU #%d", i) + 1;
756 		*endaddr += len - 1;
757 		*(*endaddr) = '\0';
758 		(*endaddr)++;
759 		type4->socket = nstrings + 1;
760 		/* Revise cores and threads after update to smbios 3.0 */
761 		if (cpu_cores > 254)
762 			type4->cores = 0;
763 		else
764 			type4->cores = cpu_cores;
765 		/* This threads is total threads in a socket */
766 		if (cpu_cores * cpu_threads > 254)
767 			type4->threads = 0;
768 		else
769 			type4->threads = cpu_cores * cpu_threads;
770 		curaddr = *endaddr;
771 	}
772 
773 	return (0);
774 }
775 
776 /*
777  * Gather oemstring values from oemstring node of config kvlist
778  *
779  * Notes: The keys must be numeric and greater than zero.
780  *
781  *        Any missing number keys will be added with a value
782  *        of "N/A"
783  *
784  *        The maximum number of strings allowed is 255
785  */
786 
787 static struct smbios_string *
smbios_gather_type11_strings(void)788 smbios_gather_type11_strings(void)
789 {
790 	const char *na = "N/A";
791 	struct smbios_string *strings;
792 	const char *name;
793 	char *np;
794 	void *cookie = NULL;
795 	nvlist_t *node;
796 	long maxnumber = 0;
797 	long number;
798 	char keystr[4];		/* SMBIOS_TYPE11_MAX_COUNT is a 3 digit number */
799 	char canonical[4];
800 	int key, type;
801 
802 	/* find any oemstrings */
803 	node = find_config_node("oemstring");
804 	/* nothing to do if none */
805 	if (!node)
806 		return NULL;
807 
808 	while ((name = nvlist_next(node, &type, &cookie)) != NULL) {
809 		if (type != NV_TYPE_STRING)
810 			errx(BHYVE_EXIT_ERROR, "Unexpected entry type for %s", name);
811 
812 		errno = 0;
813 		number = strtol(name, &np, 10);
814 		if ((*np != '\0') || (errno == EINVAL))
815 			errx(BHYVE_EXIT_ERROR, "Invalid format: %s should be a decimal number", name);
816 		if (number <= 0 || number > SMBIOS_TYPE11_MAX_COUNT)
817 			errx(BHYVE_EXIT_ERROR, "Invalid range: %s should be in 1-%d", name,
818 			    SMBIOS_TYPE11_MAX_COUNT);
819 		/* strtol accepts leading zeros and signed values which will break search */
820 		snprintf(canonical, sizeof(canonical), "%ld", number);
821 		if (strcmp(name, canonical) != 0)
822 			errx(BHYVE_EXIT_ERROR, "Invalid format: %s should be %s", name, canonical);
823 		if (number > maxnumber)
824 			maxnumber = number;
825 	}
826 	strings = calloc(maxnumber + 1, sizeof(struct smbios_string));
827 	if (strings == NULL)
828 		err(BHYVE_EXIT_ERROR, "oemstring allocation failed");
829 
830 	/*
831 	 * The returned smbios_string should leave the node field as NULL to
832 	 * avoid creating a new node in the config tree.
833 	 */
834 	for (key = 1; key <= maxnumber; key++) {
835 		const char *vp;
836 
837 		snprintf(keystr, sizeof(keystr), "%d", key);
838 		if (nvlist_exists(node, keystr))
839 			vp = nvlist_get_string(node, keystr);
840 		else
841 			vp = na;
842 		strings[key - 1].value = strdup(vp);
843 		if (strings[key - 1].value == NULL)
844 			err(BHYVE_EXIT_ERROR, "oemstring value allocation failed");
845 	}
846 
847 	/* return data */
848 	return (strings);
849 }
850 
851 static int
smbios_type11_initializer(const struct smbios_structure * template_entry,const struct smbios_string * template_strings __unused,char * curaddr,char ** endaddr,uint16_t * n)852 smbios_type11_initializer(const struct smbios_structure *template_entry,
853     const struct smbios_string *template_strings __unused, char *curaddr,
854     char **endaddr, uint16_t *n)
855 {
856 	struct smbios_table_type11 *type11;
857 	struct smbios_string *type11_strings;
858 	int i = 0;
859 
860 	type11_strings = smbios_gather_type11_strings();
861 
862 	smbios_generic_initializer(template_entry, type11_strings, curaddr,
863 	    endaddr, n);
864 
865 	if (type11_strings != NULL) {
866 		/* count up strings */
867 		type11 = (struct smbios_table_type11 *)curaddr;
868 		for (i = 0; type11_strings[i].value != NULL; i++) {
869 			free(__DECONST(char *, type11_strings[i].value));
870 		}
871 		type11->nstrings = i;
872 	}
873 	free(type11_strings);
874 	return (0);
875 }
876 
877 static int
smbios_type16_initializer(const struct smbios_structure * template_entry,const struct smbios_string * template_strings,char * curaddr,char ** endaddr,uint16_t * n)878 smbios_type16_initializer(const struct smbios_structure *template_entry,
879     const struct smbios_string *template_strings, char *curaddr, char **endaddr,
880     uint16_t *n)
881 {
882 	struct smbios_table_type16 *type16;
883 
884 	type16_handle = *n;
885 	smbios_generic_initializer(template_entry, template_strings,
886 	    curaddr, endaddr, n);
887 	type16 = (struct smbios_table_type16 *)curaddr;
888 	type16->xsize = guest_lomem + guest_himem;
889 	type16->ndevs = guest_himem > 0 ? 2 : 1;
890 
891 	return (0);
892 }
893 
894 static int
smbios_type17_initializer(const struct smbios_structure * template_entry,const struct smbios_string * template_strings,char * curaddr,char ** endaddr,uint16_t * n)895 smbios_type17_initializer(const struct smbios_structure *template_entry,
896     const struct smbios_string *template_strings, char *curaddr, char **endaddr,
897     uint16_t *n)
898 {
899 	struct smbios_table_type17 *type17;
900 	uint64_t memsize, size_KB, size_MB;
901 
902 	smbios_generic_initializer(template_entry, template_strings,
903 	    curaddr, endaddr, n);
904 	type17 = (struct smbios_table_type17 *)curaddr;
905 	type17->arrayhand = type16_handle;
906 
907 	memsize = guest_lomem + guest_himem;
908 	size_KB = memsize / 1024;
909 	size_MB = memsize / MB;
910 
911 	/* A single Type 17 entry can't represent more than ~2PB RAM */
912 	if (size_MB > 0x7FFFFFFF) {
913 		printf("Warning: guest memory too big for SMBIOS Type 17 table: "
914 			"%luMB greater than max supported 2147483647MB\n", size_MB);
915 
916 		size_MB = 0x7FFFFFFF;
917 	}
918 
919 	/* See SMBIOS 2.7.0 section 7.18 - Memory Device (Type 17) */
920 	if (size_KB <= 0x7FFF) {
921 		/* Can represent up to 32767KB with the top bit set */
922 		type17->size = size_KB | (1 << 15);
923 	} else if (size_MB < 0x7FFF) {
924 		/* Can represent up to 32766MB with the top bit unset */
925 		type17->size = size_MB & 0x7FFF;
926 	} else {
927 		type17->size = 0x7FFF;
928 		/*
929 		 * Can represent up to 2147483647MB (~2PB)
930 		 * The top bit is reserved
931 		 */
932 		type17->xsize = size_MB & 0x7FFFFFFF;
933 	}
934 
935 	return (0);
936 }
937 
938 static int
smbios_type19_initializer(const struct smbios_structure * template_entry,const struct smbios_string * template_strings,char * curaddr,char ** endaddr,uint16_t * n)939 smbios_type19_initializer(const struct smbios_structure *template_entry,
940     const struct smbios_string *template_strings, char *curaddr, char **endaddr,
941     uint16_t *n)
942 {
943 	struct smbios_table_type19 *type19;
944 
945 	smbios_generic_initializer(template_entry, template_strings,
946 	    curaddr, endaddr, n);
947 	type19 = (struct smbios_table_type19 *)curaddr;
948 	type19->arrayhand = type16_handle;
949 	type19->xsaddr = 0;
950 	type19->xeaddr = guest_lomem;
951 
952 	if (guest_himem > 0) {
953 		curaddr = *endaddr;
954 		smbios_generic_initializer(template_entry, template_strings,
955 		    curaddr, endaddr, n);
956 		type19 = (struct smbios_table_type19 *)curaddr;
957 		type19->arrayhand = type16_handle;
958 		type19->xsaddr = guest_himem_base;
959 		type19->xeaddr = guest_himem_base + guest_himem;
960 	}
961 
962 	return (0);
963 }
964 
965 static void
smbios_ep_initializer(struct smbios_entry_point * smbios_ep,uint32_t staddr)966 smbios_ep_initializer(struct smbios_entry_point *smbios_ep, uint32_t staddr)
967 {
968 	memset(smbios_ep, 0, sizeof(*smbios_ep));
969 	memcpy(smbios_ep->eanchor, SMBIOS_ENTRY_EANCHOR,
970 	    SMBIOS_ENTRY_EANCHORLEN);
971 	smbios_ep->eplen = 0x1F;
972 	assert(sizeof (struct smbios_entry_point) == smbios_ep->eplen);
973 	smbios_ep->major = 2;
974 	smbios_ep->minor = 6;
975 	smbios_ep->revision = 0;
976 	memcpy(smbios_ep->ianchor, SMBIOS_ENTRY_IANCHOR,
977 	    SMBIOS_ENTRY_IANCHORLEN);
978 	smbios_ep->staddr = staddr;
979 	smbios_ep->bcdrev = (smbios_ep->major & 0xf) << 4 | (smbios_ep->minor & 0xf);
980 }
981 
982 static void
smbios_ep_finalizer(struct smbios_entry_point * smbios_ep,uint16_t len,uint16_t num,uint16_t maxssize)983 smbios_ep_finalizer(struct smbios_entry_point *smbios_ep, uint16_t len,
984     uint16_t num, uint16_t maxssize)
985 {
986 	uint8_t	checksum;
987 	int	i;
988 
989 	smbios_ep->maxssize = maxssize;
990 	smbios_ep->stlen = len;
991 	smbios_ep->stnum = num;
992 
993 	checksum = 0;
994 	for (i = 0x10; i < 0x1f; i++) {
995 		checksum -= ((uint8_t *)smbios_ep)[i];
996 	}
997 	smbios_ep->ichecksum = checksum;
998 
999 	checksum = 0;
1000 	for (i = 0; i < 0x1f; i++) {
1001 		checksum -= ((uint8_t *)smbios_ep)[i];
1002 	}
1003 	smbios_ep->echecksum = checksum;
1004 }
1005 
1006 int
smbios_build(struct vmctx * ctx)1007 smbios_build(struct vmctx *ctx)
1008 {
1009 	struct smbios_entry_point	*smbios_ep;
1010 	uint16_t			n;
1011 	uint16_t			maxssize;
1012 	char				*curaddr, *startaddr, *ststartaddr;
1013 	int				i;
1014 	int				err;
1015 
1016 	guest_lomem = vm_get_lowmem_size(ctx);
1017 	guest_himem = vm_get_highmem_size(ctx);
1018 	guest_himem_base = vm_get_highmem_base(ctx);
1019 
1020 	startaddr = paddr_guest2host(ctx, SMBIOS_BASE, SMBIOS_MAX_LENGTH);
1021 	if (startaddr == NULL) {
1022 		EPRINTLN("smbios table requires mapped mem");
1023 		return (ENOMEM);
1024 	}
1025 
1026 	curaddr = startaddr;
1027 
1028 	smbios_ep = (struct smbios_entry_point *)curaddr;
1029 	smbios_ep_initializer(smbios_ep, SMBIOS_BASE +
1030 	    sizeof(struct smbios_entry_point));
1031 	curaddr += sizeof(struct smbios_entry_point);
1032 	ststartaddr = curaddr;
1033 
1034 	n = 0;
1035 	maxssize = 0;
1036 	for (i = 0; smbios_template[i].entry != NULL; i++) {
1037 		const struct smbios_structure	*entry;
1038 		const struct smbios_string	*strings;
1039 		initializer_func_t      initializer;
1040 		char			*endaddr;
1041 		size_t			size;
1042 
1043 		entry = smbios_template[i].entry;
1044 		strings = smbios_template[i].strings;
1045 		initializer = smbios_template[i].initializer;
1046 
1047 		err = (*initializer)(entry, strings, curaddr, &endaddr, &n);
1048 		if (err != 0)
1049 			return (err);
1050 
1051 		size = endaddr - curaddr;
1052 		assert(size <= UINT16_MAX);
1053 		if (size > maxssize)
1054 			maxssize = (uint16_t)size;
1055 		curaddr = endaddr;
1056 	}
1057 
1058 	assert(curaddr - startaddr < SMBIOS_MAX_LENGTH);
1059 	smbios_ep_finalizer(smbios_ep, curaddr - ststartaddr, n, maxssize);
1060 
1061 	return (0);
1062 }
1063