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