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