smbios.c revision 156519
1/*-
2 * Copyright (c) 2005, 2006 Jung-uk Kim <jkim@FreeBSD.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *	notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *	notice, this list of conditions and the following disclaimer in the
12 *	documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD: head/sys/boot/i386/libi386/smbios.c 156519 2006-03-09 22:49:44Z jkim $");
29
30#include <stand.h>
31#include <bootstrap.h>
32
33#include "btxv86.h"
34#include "libi386.h"
35
36/*
37 * Detect SMBIOS and export information about the SMBIOS into the
38 * environment.
39 *
40 * System Management BIOS Reference Specification, v2.4 Final
41 * http://www.dmtf.org/standards/published_documents/DSP0134.pdf
42 */
43
44/*
45 * Spec. 2.1.1 SMBIOS Structure Table Entry Point
46 *
47 * 'The SMBIOS Entry Point structure, described below, can be located by
48 * application software by searching for the anchor-string on paragraph
49 * (16-byte) boundaries within the physical memory address range
50 * 000F0000h to 000FFFFFh.'
51 */
52#define	SMBIOS_START		0xf0000
53#define	SMBIOS_LENGTH		0x10000
54#define	SMBIOS_STEP		0x10
55#define	SMBIOS_SIG		"_SM_"
56#define	SMBIOS_DMI_SIG		"_DMI_"
57
58static uint8_t	smbios_enabled_sockets = 0;
59static uint8_t	smbios_populated_sockets = 0;
60
61static uint8_t	*smbios_parse_table(const uint8_t *dmi);
62static void	smbios_setenv(const char *name, const uint8_t *dmi,
63		    const int offset);
64static uint8_t	smbios_checksum(const caddr_t addr, const uint8_t len);
65static uint8_t	*smbios_sigsearch(const caddr_t addr, const uint32_t len);
66
67#ifdef SHOW_SENSITIVE_INFO
68static void	smbios_setuuid(const char *name, const uint8_t *dmi,
69		    const int offset);
70#endif
71
72void
73smbios_detect(void)
74{
75	uint8_t		*smbios, *dmi, *addr;
76	uint16_t	i, length, count;
77	uint32_t	paddr;
78	char		buf[4];
79
80	/* locate and validate the SMBIOS */
81	smbios = smbios_sigsearch(PTOV(SMBIOS_START), SMBIOS_LENGTH);
82	if (smbios == NULL)
83		return;
84
85	length = *(uint16_t *)(smbios + 0x16);	/* Structure Table Length */
86	paddr = *(uint32_t *)(smbios + 0x18);	/* Structure Table Address */
87	count = *(uint16_t *)(smbios + 0x1c);	/* No of SMBIOS Structures */
88
89	for (dmi = addr = PTOV(paddr), i = 0;
90	     dmi - addr < length && i < count; i++)
91		dmi = smbios_parse_table(dmi);
92	sprintf(buf, "%d", smbios_enabled_sockets);
93	setenv("smbios.socket.enabled", buf, 1);
94	sprintf(buf, "%d", smbios_populated_sockets);
95	setenv("smbios.socket.populated", buf, 1);
96}
97
98static uint8_t *
99smbios_parse_table(const uint8_t *dmi)
100{
101	uint8_t		*dp;
102
103	switch(dmi[0]) {
104	case 0:		/* Type 0: BIOS */
105		smbios_setenv("smbios.bios.vendor", dmi, 0x04);
106		smbios_setenv("smbios.bios.version", dmi, 0x05);
107		smbios_setenv("smbios.bios.reldate", dmi, 0x08);
108		break;
109
110	case 1:		/* Type 1: System */
111		smbios_setenv("smbios.system.maker", dmi, 0x04);
112		smbios_setenv("smbios.system.product", dmi, 0x05);
113		smbios_setenv("smbios.system.version", dmi, 0x06);
114#ifdef SHOW_SENSITIVE_INFO
115		smbios_setenv("smbios.system.serial", dmi, 0x07);
116		smbios_setuuid("smbios.system.uuid", dmi, 0x08);
117#endif
118		break;
119
120	case 2:		/* Type 2: Base Board (or Module) */
121		smbios_setenv("smbios.planar.maker", dmi, 0x04);
122		smbios_setenv("smbios.planar.product", dmi, 0x05);
123		smbios_setenv("smbios.planar.version", dmi, 0x06);
124#ifdef SHOW_SENSITIVE_INFO
125		smbios_setenv("smbios.planar.serial", dmi, 0x07);
126#endif
127		break;
128
129	case 3:		/* Type 3: System Enclosure or Chassis */
130		smbios_setenv("smbios.chassis.maker", dmi, 0x04);
131		smbios_setenv("smbios.chassis.version", dmi, 0x06);
132#ifdef SHOW_SENSITIVE_INFO
133		smbios_setenv("smbios.chassis.serial", dmi, 0x07);
134		smbios_setenv("smbios.chassis.tag", dmi, 0x08);
135#endif
136		break;
137
138	case 4:		/* Type 4: Processor Information */
139		/*
140		 * Offset 18h: Processor Status
141		 *
142		 * Bit 7	Reserved, must be 0
143		 * Bit 6	CPU Socket Populated
144		 *		1 - CPU Socket Populated
145		 *		0 - CPU Socket Unpopulated
146		 * Bit 5:3	Reserved, must be zero
147		 * Bit 2:0	CPU Status
148		 *		0h - Unknown
149		 *		1h - CPU Enabled
150		 *		2h - CPU Disabled by User via BIOS Setup
151		 *		3h - CPU Disabled by BIOS (POST Error)
152		 *		4h - CPU is Idle, waiting to be enabled
153		 *		5-6h - Reserved
154		 *		7h - Other
155		 */
156		if ((dmi[0x18] & 0x07) == 1)
157			smbios_enabled_sockets++;
158		if (dmi[0x18] & 0x40)
159			smbios_populated_sockets++;
160		break;
161
162	default: /* skip other types */
163		break;
164	}
165
166	/* find structure terminator */
167	dp = __DECONST(uint8_t *, dmi + dmi[1]);
168	while (dp[0] != 0 || dp[1] != 0)
169		dp++;
170
171	return(dp + 2);
172}
173
174static void
175smbios_setenv(const char *name, const uint8_t *dmi, const int offset)
176{
177	char		*cp = __DECONST(char *, dmi + dmi[1]);
178	int		i;
179
180	/* skip undefined string */
181	if (dmi[offset] == 0)
182		return;
183
184	for (i = 0; i < dmi[offset] - 1; i++)
185		cp += strlen(cp) + 1;
186	setenv(name, cp, 1);
187}
188
189static uint8_t
190smbios_checksum(const caddr_t addr, const uint8_t len)
191{
192	const uint8_t	*cp = addr;
193	uint8_t		sum;
194	int		i;
195
196	for (sum = 0, i = 0; i < len; i++)
197		sum += cp[i];
198
199	return(sum);
200}
201
202static uint8_t *
203smbios_sigsearch(const caddr_t addr, const uint32_t len)
204{
205	caddr_t		cp;
206
207	/* search on 16-byte boundaries */
208	for (cp = addr; cp < addr + len; cp += SMBIOS_STEP) {
209		/* compare signature, validate checksum */
210		if (!strncmp(cp, SMBIOS_SIG, 4)) {
211			if (smbios_checksum(cp, *(uint8_t *)(cp + 0x05)))
212				continue;
213			if (strncmp(cp + 0x10, SMBIOS_DMI_SIG, 5))
214				continue;
215			if (smbios_checksum(cp + 0x10, 0x0f))
216				continue;
217
218			return(cp);
219		}
220	}
221
222	return(NULL);
223}
224
225#ifdef SHOW_SENSITIVE_INFO
226static void
227smbios_setuuid(const char *name, const uint8_t *dmi, const int offset)
228{
229	const uint8_t	*idp = dmi + offset;
230	int		i, f = 0, z = 0;
231	char		uuid[37];
232
233	for (i = 0; i < 16; i++) {
234		if (idp[i] == 0xff)
235			f++;
236		if (idp[i] == 0x00)
237			z++;
238	}
239	if (f != 16 && z != 16) {
240		sprintf(uuid, "%02X%02X%02X%02X-"
241		    "%02X%02X-%02X%02X-%02X%02X-"
242		    "%02X%02X%02X%02X%02X%02X",
243		    idp[0], idp[1], idp[2], idp[3],
244		    idp[4], idp[5], idp[6], idp[7], idp[8], idp[9],
245		    idp[10], idp[11], idp[12], idp[13], idp[14], idp[15]);
246		setenv(name, uuid, 1);
247	}
248}
249#endif
250