FreeBSD/Linux Kernel Cross Reference
sys/i386/bios/smbios.c
1 /*-
2 * Copyright (c) 2003 Matthew N. Dodd <winter@jurai.net>
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: releng/5.2/sys/i386/bios/smbios.c 115679 2003-06-02 06:02:49Z obrien $");
29
30 #include <sys/param.h>
31 #include <sys/systm.h>
32 #include <sys/kernel.h>
33 #include <sys/socket.h>
34
35 #include <sys/module.h>
36 #include <sys/bus.h>
37
38 #include <machine/bus.h>
39 #include <machine/resource.h>
40 #include <sys/rman.h>
41
42 #include <vm/vm.h>
43 #include <vm/pmap.h>
44 #include <machine/md_var.h>
45 #include <machine/pc/bios.h>
46
47 /*
48 * SMBIOS Entry Point Structure
49 */
50 struct smbios_eps {
51 u_int8_t Anchor[4]; /* '_SM_' */
52 u_int8_t Checksum;
53 u_int8_t Length;
54
55 u_int8_t SMBIOS_Major;
56 u_int8_t SMBIOS_Minor;
57 u_int8_t Max_Size;
58 u_int8_t Revision;
59 u_int8_t Formatted_Area;
60
61 u_int8_t Intermediate_Anchor[5]; /* '_DMI_' */
62 u_int8_t Intermediate_Checksum;
63
64 u_int16_t Structure_Table_Length;
65 u_int32_t Structure_Table_Address;
66 u_int16_t Structure_Count;
67
68 u_int8_t SMBIOS_BCD_Revision;
69 } __packed;
70
71 struct smbios_softc {
72 device_t dev;
73 struct resource * res;
74 int rid;
75
76 struct smbios_eps * eps;
77 };
78
79 #define SMBIOS_START 0xf0000
80 #define SMBIOS_STEP 0x10
81 #define SMBIOS_OFF 0
82 #define SMBIOS_LEN 4
83 #define SMBIOS_SIG "_SM_"
84
85 #define RES2EPS(res) ((struct smbios_eps *)rman_get_virtual(res))
86 #define ADDR2EPS(addr) ((struct smbios_eps *)BIOS_PADDRTOVADDR(addr))
87
88 static devclass_t smbios_devclass;
89
90 static void smbios_identify (driver_t *, device_t);
91 static int smbios_probe (device_t);
92 static int smbios_attach (device_t);
93 static int smbios_detach (device_t);
94 static int smbios_modevent (module_t, int, void *);
95
96 static int smbios_cksum (struct smbios_eps *);
97
98 static void
99 smbios_identify (driver_t *driver, device_t parent)
100 {
101 device_t child;
102 u_int32_t addr;
103 int length;
104 int rid;
105
106 if (!device_is_alive(parent))
107 return;
108
109 addr = bios_sigsearch(SMBIOS_START, SMBIOS_SIG, SMBIOS_LEN,
110 SMBIOS_STEP, SMBIOS_OFF);
111 if (addr != 0) {
112 rid = 0;
113 length = ADDR2EPS(addr)->Length;
114
115 child = BUS_ADD_CHILD(parent, 0, "smbios", -1);
116 device_set_driver(child, driver);
117 bus_set_resource(child, SYS_RES_MEMORY, rid, addr, length);
118 device_set_desc(child, "System Management BIOS");
119 }
120
121 return;
122 }
123
124 static int
125 smbios_probe (device_t dev)
126 {
127 struct resource *res;
128 int rid;
129 int error;
130
131 error = 0;
132 rid = 0;
133 res = bus_alloc_resource(dev, SYS_RES_MEMORY, &rid,
134 0ul, ~0ul, 1, RF_ACTIVE);
135 if (res == NULL) {
136 device_printf(dev, "Unable to allocate memory resource.\n");
137 error = ENOMEM;
138 goto bad;
139 }
140
141 if (smbios_cksum(RES2EPS(res))) {
142 device_printf(dev, "SMBIOS checksum failed.\n");
143 error = ENXIO;
144 goto bad;
145 }
146
147 bad:
148 if (res)
149 bus_release_resource(dev, SYS_RES_MEMORY, rid, res);
150 return (error);
151 }
152
153 static int
154 smbios_attach (device_t dev)
155 {
156 struct smbios_softc *sc;
157 int error;
158
159 sc = device_get_softc(dev);
160 error = 0;
161
162 sc->dev = dev;
163 sc->rid = 0;
164 sc->res = bus_alloc_resource(dev, SYS_RES_MEMORY, &sc->rid,
165 0ul, ~0ul, 1, RF_ACTIVE);
166 if (sc->res == NULL) {
167 device_printf(dev, "Unable to allocate memory resource.\n");
168 error = ENOMEM;
169 goto bad;
170 }
171 sc->eps = RES2EPS(sc->res);
172
173 device_printf(dev, "Version: %d.%02d",
174 sc->eps->SMBIOS_Major, sc->eps->SMBIOS_Minor);
175 if (bcd2bin(sc->eps->SMBIOS_BCD_Revision))
176 printf(", Revision: %d.%02d",
177 bcd2bin(sc->eps->SMBIOS_BCD_Revision >> 4),
178 bcd2bin(sc->eps->SMBIOS_BCD_Revision & 0x0f));
179 printf("\n");
180
181 return (0);
182 bad:
183 if (sc->res)
184 bus_release_resource(dev, SYS_RES_MEMORY, sc->rid, sc->res);
185 return (error);
186 }
187
188 static int
189 smbios_detach (device_t dev)
190 {
191 struct smbios_softc *sc;
192
193 sc = device_get_softc(dev);
194
195 if (sc->res)
196 bus_release_resource(dev, SYS_RES_MEMORY, sc->rid, sc->res);
197
198 return (0);
199 }
200
201 static int
202 smbios_modevent (mod, what, arg)
203 module_t mod;
204 int what;
205 void * arg;
206 {
207 device_t * devs;
208 int count;
209 int i;
210
211 switch (what) {
212 case MOD_LOAD:
213 break;
214 case MOD_UNLOAD:
215 devclass_get_devices(smbios_devclass, &devs, &count);
216 for (i = 0; i < count; i++) {
217 device_delete_child(device_get_parent(devs[i]), devs[i]);
218 }
219 break;
220 default:
221 break;
222 }
223
224 return (0);
225 }
226
227 static device_method_t smbios_methods[] = {
228 /* Device interface */
229 DEVMETHOD(device_identify, smbios_identify),
230 DEVMETHOD(device_probe, smbios_probe),
231 DEVMETHOD(device_attach, smbios_attach),
232 DEVMETHOD(device_detach, smbios_detach),
233 { 0, 0 }
234 };
235
236 static driver_t smbios_driver = {
237 "smbios",
238 smbios_methods,
239 sizeof(struct smbios_softc),
240 };
241
242 DRIVER_MODULE(smbios, nexus, smbios_driver, smbios_devclass, smbios_modevent, 0);
243 MODULE_VERSION(smbios, 1);
244
245 static int
246 smbios_cksum (struct smbios_eps *e)
247 {
248 u_int8_t *ptr;
249 u_int8_t cksum;
250 int i;
251
252 ptr = (u_int8_t *)e;
253 cksum = 0;
254 for (i = 0; i < e->Length; i++) {
255 cksum += ptr[i];
256 }
257
258 return (cksum);
259 }
Cache object: 3b6c631bb55d6fbdc9bf4932701e7e60
|