2 * Copyright (c) 2005, 2006 Jung-uk Kim <jkim@FreeBSD.org>
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
31 #include <bootstrap.h>
37 * Detect SMBIOS and export information about the SMBIOS into the
40 * System Management BIOS Reference Specification, v2.4 Final
41 * http://www.dmtf.org/standards/published_documents/DSP0134.pdf
45 * Spec. 2.1.1 SMBIOS Structure Table Entry Point
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.'
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_"
58 static uint8_t smbios_enabled_sockets = 0;
59 static uint8_t smbios_populated_sockets = 0;
61 static uint8_t *smbios_parse_table(const uint8_t *dmi);
62 static void smbios_setenv(const char *name, const uint8_t *dmi,
64 static uint8_t smbios_checksum(const caddr_t addr, const uint8_t len);
65 static uint8_t *smbios_sigsearch(const caddr_t addr, const uint32_t len);
67 #ifdef SMBIOS_SERIAL_NUMBERS
68 static void smbios_setuuid(const char *name, const uint8_t *dmi,
75 uint8_t *smbios, *dmi, *addr;
76 uint16_t i, length, count;
80 /* locate and validate the SMBIOS */
81 smbios = smbios_sigsearch(PTOV(SMBIOS_START), SMBIOS_LENGTH);
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 */
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);
99 smbios_parse_table(const uint8_t *dmi)
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);
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 SMBIOS_SERIAL_NUMBERS
115 smbios_setenv("smbios.system.serial", dmi, 0x07);
116 smbios_setuuid("smbios.system.uuid", dmi, 0x08);
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 SMBIOS_SERIAL_NUMBERS
125 smbios_setenv("smbios.planar.serial", dmi, 0x07);
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 SMBIOS_SERIAL_NUMBERS
133 smbios_setenv("smbios.chassis.serial", dmi, 0x07);
134 smbios_setenv("smbios.chassis.tag", dmi, 0x08);
138 case 4: /* Type 4: Processor Information */
140 * Offset 18h: Processor Status
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
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
156 if ((dmi[0x18] & 0x07) == 1)
157 smbios_enabled_sockets++;
158 if (dmi[0x18] & 0x40)
159 smbios_populated_sockets++;
162 default: /* skip other types */
166 /* find structure terminator */
167 dp = __DECONST(uint8_t *, dmi + dmi[1]);
168 while (dp[0] != 0 || dp[1] != 0)
175 smbios_setenv(const char *name, const uint8_t *dmi, const int offset)
177 char *cp = __DECONST(char *, dmi + dmi[1]);
180 /* skip undefined string */
181 if (dmi[offset] == 0)
184 for (i = 0; i < dmi[offset] - 1; i++)
185 cp += strlen(cp) + 1;
190 smbios_checksum(const caddr_t addr, const uint8_t len)
192 const uint8_t *cp = addr;
196 for (sum = 0, i = 0; i < len; i++)
203 smbios_sigsearch(const caddr_t addr, const uint32_t len)
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)))
213 if (strncmp(cp + 0x10, SMBIOS_DMI_SIG, 5))
215 if (smbios_checksum(cp + 0x10, 0x0f))
225 #ifdef SMBIOS_SERIAL_NUMBERS
227 smbios_setuuid(const char *name, const uint8_t *dmi, const int offset)
229 const uint8_t *idp = dmi + offset;
233 for (i = 0; i < 16; i++) {
236 else if (idp[i] == 0x00)
241 if (f != 16 && z != 16) {
242 sprintf(uuid, "%02x%02x%02x%02x-"
243 "%02x%02x-%02x%02x-%02x%02x-"
244 "%02x%02x%02x%02x%02x%02x",
245 idp[0], idp[1], idp[2], idp[3],
246 idp[4], idp[5], idp[6], idp[7], idp[8], idp[9],
247 idp[10], idp[11], idp[12], idp[13], idp[14], idp[15]);
248 setenv(name, uuid, 1);