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.4/sys/i386/bios/smbios.c 130312 2004-06-10 20:31:00Z jhb $");
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/vm_param.h>
44 #include <vm/pmap.h>
45 #include <machine/md_var.h>
46 #include <machine/pc/bios.h>
47
48 /*
49 * SMBIOS Entry Point Structure
50 */
51 struct smbios_eps {
52 u_int8_t Anchor[4]; /* '_SM_' */
53 u_int8_t Checksum;
54 u_int8_t Length;
55
56 u_int8_t SMBIOS_Major;
57 u_int8_t SMBIOS_Minor;
58 u_int8_t Max_Size;
59 u_int8_t Revision;
60 u_int8_t Formatted_Area;
61
62 u_int8_t Intermediate_Anchor[5]; /* '_DMI_' */
63 u_int8_t Intermediate_Checksum;
64
65 u_int16_t Structure_Table_Length;
66 u_int32_t Structure_Table_Address;
67 u_int16_t Structure_Count;
68
69 u_int8_t SMBIOS_BCD_Revision;
70 } __packed;
71
72 struct smbios_softc {
73 device_t dev;
74 struct resource * res;
75 int rid;
76
77 struct smbios_eps * eps;
78 };
79
80 #define SMBIOS_START 0xf0000
81 #define SMBIOS_STEP 0x10
82 #define SMBIOS_OFF 0
83 #define SMBIOS_LEN 4
84 #define SMBIOS_SIG "_SM_"
85
86 #define RES2EPS(res) ((struct smbios_eps *)rman_get_virtual(res))
87 #define ADDR2EPS(addr) ((struct smbios_eps *)BIOS_PADDRTOVADDR(addr))
88
89 static devclass_t smbios_devclass;
90
91 static void smbios_identify (driver_t *, device_t);
92 static int smbios_probe (device_t);
93 static int smbios_attach (device_t);
94 static int smbios_detach (device_t);
95 static int smbios_modevent (module_t, int, void *);
96
97 static int smbios_cksum (struct smbios_eps *);
98
99 static void
100 smbios_identify (driver_t *driver, device_t parent)
101 {
102 device_t child;
103 u_int32_t addr;
104 int length;
105 int rid;
106
107 if (!device_is_alive(parent))
108 return;
109
110 addr = bios_sigsearch(SMBIOS_START, SMBIOS_SIG, SMBIOS_LEN,
111 SMBIOS_STEP, SMBIOS_OFF);
112 if (addr != 0) {
113 rid = 0;
114 length = ADDR2EPS(addr)->Length;
115
116 child = BUS_ADD_CHILD(parent, 0, "smbios", -1);
117 device_set_driver(child, driver);
118 bus_set_resource(child, SYS_RES_MEMORY, rid, addr, length);
119 device_set_desc(child, "System Management BIOS");
120 }
121
122 return;
123 }
124
125 static int
126 smbios_probe (device_t dev)
127 {
128 struct resource *res;
129 int rid;
130 int error;
131
132 error = 0;
133 rid = 0;
134 res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, 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_any(dev, SYS_RES_MEMORY, &sc->rid,
165 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: b402e0c1e2a4d769f934cbb7bfd19d6a
|