]> CyberLeo.Net >> Repos - FreeBSD/releng/7.2.git/blob - sys/boot/i386/libi386/smbios.c
Create releng/7.2 from stable/7 in preparation for 7.2-RELEASE.
[FreeBSD/releng/7.2.git] / sys / boot / i386 / libi386 / smbios.c
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$");
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
58 static uint8_t  smbios_enabled_sockets = 0;
59 static uint8_t  smbios_populated_sockets = 0;
60
61 static uint8_t  *smbios_parse_table(const uint8_t *dmi);
62 static void     smbios_setenv(const char *name, const uint8_t *dmi,
63                     const int offset);
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);
66
67 #ifdef SMBIOS_SERIAL_NUMBERS
68 static void     smbios_setuuid(const char *name, const uint8_t *dmi,
69                     const int offset);
70 #endif
71
72 void
73 smbios_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
98 static uint8_t *
99 smbios_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 SMBIOS_SERIAL_NUMBERS
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 SMBIOS_SERIAL_NUMBERS
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 SMBIOS_SERIAL_NUMBERS
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
174 static void
175 smbios_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
189 static uint8_t
190 smbios_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
202 static uint8_t *
203 smbios_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 SMBIOS_SERIAL_NUMBERS
226 static void
227 smbios_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                 else if (idp[i] == 0x00)
237                         z++;
238                 else
239                         break;
240         }
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);
249         }
250 }
251 #endif