Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
7143 | serge | 1 | #include |
2 | #include |
||
3 | #include |
||
4 | #include |
||
5 | #include |
||
6 | #include |
||
7 | #include |
||
8 | #include |
||
9 | #include |
||
10 | #include |
||
11 | #include |
||
12 | |||
13 | struct kobject *dmi_kobj; |
||
14 | EXPORT_SYMBOL_GPL(dmi_kobj); |
||
15 | |||
16 | /* |
||
17 | * DMI stands for "Desktop Management Interface". It is part |
||
18 | * of and an antecedent to, SMBIOS, which stands for System |
||
19 | * Management BIOS. See further: http://www.dmtf.org/standards |
||
20 | */ |
||
21 | static const char dmi_empty_string[] = " "; |
||
22 | |||
23 | static u32 dmi_ver __initdata; |
||
24 | static u32 dmi_len; |
||
25 | static u16 dmi_num; |
||
26 | static u8 smbios_entry_point[32]; |
||
27 | static int smbios_entry_point_size; |
||
28 | |||
29 | /* |
||
30 | * Catch too early calls to dmi_check_system(): |
||
31 | */ |
||
32 | static int dmi_initialized; |
||
33 | |||
34 | /* DMI system identification string used during boot */ |
||
35 | static char dmi_ids_string[128] __initdata; |
||
36 | |||
37 | static struct dmi_memdev_info { |
||
38 | const char *device; |
||
39 | const char *bank; |
||
40 | u16 handle; |
||
41 | } *dmi_memdev; |
||
42 | static int dmi_memdev_nr; |
||
43 | |||
44 | static const char * __init dmi_string_nosave(const struct dmi_header *dm, u8 s) |
||
45 | { |
||
46 | const u8 *bp = ((u8 *) dm) + dm->length; |
||
47 | |||
48 | if (s) { |
||
49 | s--; |
||
50 | while (s > 0 && *bp) { |
||
51 | bp += strlen(bp) + 1; |
||
52 | s--; |
||
53 | } |
||
54 | |||
55 | if (*bp != 0) { |
||
56 | size_t len = strlen(bp)+1; |
||
57 | size_t cmp_len = len > 8 ? 8 : len; |
||
58 | |||
59 | if (!memcmp(bp, dmi_empty_string, cmp_len)) |
||
60 | return dmi_empty_string; |
||
61 | return bp; |
||
62 | } |
||
63 | } |
||
64 | |||
65 | return ""; |
||
66 | } |
||
67 | |||
68 | static const char * __init dmi_string(const struct dmi_header *dm, u8 s) |
||
69 | { |
||
70 | const char *bp = dmi_string_nosave(dm, s); |
||
71 | char *str; |
||
72 | size_t len; |
||
73 | |||
74 | if (bp == dmi_empty_string) |
||
75 | return dmi_empty_string; |
||
76 | |||
77 | len = strlen(bp) + 1; |
||
78 | str = dmi_alloc(len); |
||
79 | if (str != NULL) |
||
80 | strcpy(str, bp); |
||
81 | |||
82 | return str; |
||
83 | } |
||
84 | |||
85 | /* |
||
86 | * We have to be cautious here. We have seen BIOSes with DMI pointers |
||
87 | * pointing to completely the wrong place for example |
||
88 | */ |
||
89 | static void dmi_decode_table(u8 *buf, |
||
90 | void (*decode)(const struct dmi_header *, void *), |
||
91 | void *private_data) |
||
92 | { |
||
93 | u8 *data = buf; |
||
94 | int i = 0; |
||
95 | |||
96 | /* |
||
97 | * Stop when we have seen all the items the table claimed to have |
||
98 | * (SMBIOS < 3.0 only) OR we reach an end-of-table marker (SMBIOS |
||
99 | * >= 3.0 only) OR we run off the end of the table (should never |
||
100 | * happen but sometimes does on bogus implementations.) |
||
101 | */ |
||
102 | while ((!dmi_num || i < dmi_num) && |
||
103 | (data - buf + sizeof(struct dmi_header)) <= dmi_len) { |
||
104 | const struct dmi_header *dm = (const struct dmi_header *)data; |
||
105 | |||
106 | /* |
||
107 | * We want to know the total length (formatted area and |
||
108 | * strings) before decoding to make sure we won't run off the |
||
109 | * table in dmi_decode or dmi_string |
||
110 | */ |
||
111 | data += dm->length; |
||
112 | while ((data - buf < dmi_len - 1) && (data[0] || data[1])) |
||
113 | data++; |
||
114 | if (data - buf < dmi_len - 1) |
||
115 | decode(dm, private_data); |
||
116 | |||
117 | data += 2; |
||
118 | i++; |
||
119 | |||
120 | /* |
||
121 | * 7.45 End-of-Table (Type 127) [SMBIOS reference spec v3.0.0] |
||
122 | * For tables behind a 64-bit entry point, we have no item |
||
123 | * count and no exact table length, so stop on end-of-table |
||
124 | * marker. For tables behind a 32-bit entry point, we have |
||
125 | * seen OEM structures behind the end-of-table marker on |
||
126 | * some systems, so don't trust it. |
||
127 | */ |
||
128 | if (!dmi_num && dm->type == DMI_ENTRY_END_OF_TABLE) |
||
129 | break; |
||
130 | } |
||
131 | |||
132 | /* Trim DMI table length if needed */ |
||
133 | if (dmi_len > data - buf) |
||
134 | dmi_len = data - buf; |
||
135 | } |
||
136 | |||
137 | static phys_addr_t dmi_base; |
||
138 | |||
139 | static int __init dmi_walk_early(void (*decode)(const struct dmi_header *, |
||
140 | void *)) |
||
141 | { |
||
142 | u8 *buf; |
||
143 | u32 orig_dmi_len = dmi_len; |
||
144 | |||
145 | buf = dmi_early_remap(dmi_base, orig_dmi_len); |
||
146 | if (buf == NULL) |
||
147 | return -1; |
||
148 | |||
149 | dmi_decode_table(buf, decode, NULL); |
||
150 | |||
151 | add_device_randomness(buf, dmi_len); |
||
152 | |||
153 | dmi_early_unmap(buf, orig_dmi_len); |
||
154 | return 0; |
||
155 | } |
||
156 | |||
157 | static int __init dmi_checksum(const u8 *buf, u8 len) |
||
158 | { |
||
159 | u8 sum = 0; |
||
160 | int a; |
||
161 | |||
162 | for (a = 0; a < len; a++) |
||
163 | sum += buf[a]; |
||
164 | |||
165 | return sum == 0; |
||
166 | } |
||
167 | |||
168 | static const char *dmi_ident[DMI_STRING_MAX]; |
||
169 | static LIST_HEAD(dmi_devices); |
||
170 | int dmi_available; |
||
171 | |||
172 | /* |
||
173 | * Save a DMI string |
||
174 | */ |
||
175 | static void __init dmi_save_ident(const struct dmi_header *dm, int slot, |
||
176 | int string) |
||
177 | { |
||
178 | const char *d = (const char *) dm; |
||
179 | const char *p; |
||
180 | |||
181 | if (dmi_ident[slot]) |
||
182 | return; |
||
183 | |||
184 | p = dmi_string(dm, d[string]); |
||
185 | if (p == NULL) |
||
186 | return; |
||
187 | |||
188 | dmi_ident[slot] = p; |
||
189 | } |
||
190 | |||
191 | static void __init dmi_save_uuid(const struct dmi_header *dm, int slot, |
||
192 | int index) |
||
193 | { |
||
194 | const u8 *d = (u8 *) dm + index; |
||
195 | char *s; |
||
196 | int is_ff = 1, is_00 = 1, i; |
||
197 | |||
198 | if (dmi_ident[slot]) |
||
199 | return; |
||
200 | |||
201 | for (i = 0; i < 16 && (is_ff || is_00); i++) { |
||
202 | if (d[i] != 0x00) |
||
203 | is_00 = 0; |
||
204 | if (d[i] != 0xFF) |
||
205 | is_ff = 0; |
||
206 | } |
||
207 | |||
208 | if (is_ff || is_00) |
||
209 | return; |
||
210 | |||
211 | s = dmi_alloc(16*2+4+1); |
||
212 | if (!s) |
||
213 | return; |
||
214 | |||
215 | /* |
||
216 | * As of version 2.6 of the SMBIOS specification, the first 3 fields of |
||
217 | * the UUID are supposed to be little-endian encoded. The specification |
||
218 | * says that this is the defacto standard. |
||
219 | */ |
||
220 | if (dmi_ver >= 0x020600) |
||
221 | sprintf(s, "%pUL", d); |
||
222 | else |
||
223 | sprintf(s, "%pUB", d); |
||
224 | |||
225 | dmi_ident[slot] = s; |
||
226 | } |
||
227 | |||
228 | static void __init dmi_save_type(const struct dmi_header *dm, int slot, |
||
229 | int index) |
||
230 | { |
||
231 | const u8 *d = (u8 *) dm + index; |
||
232 | char *s; |
||
233 | |||
234 | if (dmi_ident[slot]) |
||
235 | return; |
||
236 | |||
237 | s = dmi_alloc(4); |
||
238 | if (!s) |
||
239 | return; |
||
240 | |||
241 | sprintf(s, "%u", *d & 0x7F); |
||
242 | dmi_ident[slot] = s; |
||
243 | } |
||
244 | |||
245 | static void __init dmi_save_one_device(int type, const char *name) |
||
246 | { |
||
247 | struct dmi_device *dev; |
||
248 | |||
249 | /* No duplicate device */ |
||
250 | if (dmi_find_device(type, name, NULL)) |
||
251 | return; |
||
252 | |||
253 | dev = dmi_alloc(sizeof(*dev) + strlen(name) + 1); |
||
254 | if (!dev) |
||
255 | return; |
||
256 | |||
257 | dev->type = type; |
||
258 | strcpy((char *)(dev + 1), name); |
||
259 | dev->name = (char *)(dev + 1); |
||
260 | dev->device_data = NULL; |
||
261 | list_add(&dev->list, &dmi_devices); |
||
262 | } |
||
263 | |||
264 | static void __init dmi_save_devices(const struct dmi_header *dm) |
||
265 | { |
||
266 | int i, count = (dm->length - sizeof(struct dmi_header)) / 2; |
||
267 | |||
268 | for (i = 0; i < count; i++) { |
||
269 | const char *d = (char *)(dm + 1) + (i * 2); |
||
270 | |||
271 | /* Skip disabled device */ |
||
272 | if ((*d & 0x80) == 0) |
||
273 | continue; |
||
274 | |||
275 | dmi_save_one_device(*d & 0x7f, dmi_string_nosave(dm, *(d + 1))); |
||
276 | } |
||
277 | } |
||
278 | |||
279 | static void __init dmi_save_oem_strings_devices(const struct dmi_header *dm) |
||
280 | { |
||
281 | int i, count = *(u8 *)(dm + 1); |
||
282 | struct dmi_device *dev; |
||
283 | |||
284 | for (i = 1; i <= count; i++) { |
||
285 | const char *devname = dmi_string(dm, i); |
||
286 | |||
287 | if (devname == dmi_empty_string) |
||
288 | continue; |
||
289 | |||
290 | dev = dmi_alloc(sizeof(*dev)); |
||
291 | if (!dev) |
||
292 | break; |
||
293 | |||
294 | dev->type = DMI_DEV_TYPE_OEM_STRING; |
||
295 | dev->name = devname; |
||
296 | dev->device_data = NULL; |
||
297 | |||
298 | list_add(&dev->list, &dmi_devices); |
||
299 | } |
||
300 | } |
||
301 | |||
302 | static void __init dmi_save_ipmi_device(const struct dmi_header *dm) |
||
303 | { |
||
304 | struct dmi_device *dev; |
||
305 | void *data; |
||
306 | |||
307 | data = dmi_alloc(dm->length); |
||
308 | if (data == NULL) |
||
309 | return; |
||
310 | |||
311 | memcpy(data, dm, dm->length); |
||
312 | |||
313 | dev = dmi_alloc(sizeof(*dev)); |
||
314 | if (!dev) |
||
315 | return; |
||
316 | |||
317 | dev->type = DMI_DEV_TYPE_IPMI; |
||
318 | dev->name = "IPMI controller"; |
||
319 | dev->device_data = data; |
||
320 | |||
321 | list_add_tail(&dev->list, &dmi_devices); |
||
322 | } |
||
323 | |||
324 | static void __init dmi_save_dev_pciaddr(int instance, int segment, int bus, |
||
325 | int devfn, const char *name, int type) |
||
326 | { |
||
327 | struct dmi_dev_onboard *dev; |
||
328 | |||
329 | /* Ignore invalid values */ |
||
330 | if (type == DMI_DEV_TYPE_DEV_SLOT && |
||
331 | segment == 0xFFFF && bus == 0xFF && devfn == 0xFF) |
||
332 | return; |
||
333 | |||
334 | dev = dmi_alloc(sizeof(*dev) + strlen(name) + 1); |
||
335 | if (!dev) |
||
336 | return; |
||
337 | |||
338 | dev->instance = instance; |
||
339 | dev->segment = segment; |
||
340 | dev->bus = bus; |
||
341 | dev->devfn = devfn; |
||
342 | |||
343 | strcpy((char *)&dev[1], name); |
||
344 | dev->dev.type = type; |
||
345 | dev->dev.name = (char *)&dev[1]; |
||
346 | dev->dev.device_data = dev; |
||
347 | |||
348 | list_add(&dev->dev.list, &dmi_devices); |
||
349 | } |
||
350 | |||
351 | static void __init dmi_save_extended_devices(const struct dmi_header *dm) |
||
352 | { |
||
353 | const char *name; |
||
354 | const u8 *d = (u8 *)dm; |
||
355 | |||
356 | /* Skip disabled device */ |
||
357 | if ((d[0x5] & 0x80) == 0) |
||
358 | return; |
||
359 | |||
360 | name = dmi_string_nosave(dm, d[0x4]); |
||
361 | dmi_save_dev_pciaddr(d[0x6], *(u16 *)(d + 0x7), d[0x9], d[0xA], name, |
||
362 | DMI_DEV_TYPE_DEV_ONBOARD); |
||
363 | dmi_save_one_device(d[0x5] & 0x7f, name); |
||
364 | } |
||
365 | |||
366 | static void __init dmi_save_system_slot(const struct dmi_header *dm) |
||
367 | { |
||
368 | const u8 *d = (u8 *)dm; |
||
369 | |||
370 | /* Need SMBIOS 2.6+ structure */ |
||
371 | if (dm->length < 0x11) |
||
372 | return; |
||
373 | dmi_save_dev_pciaddr(*(u16 *)(d + 0x9), *(u16 *)(d + 0xD), d[0xF], |
||
374 | d[0x10], dmi_string_nosave(dm, d[0x4]), |
||
375 | DMI_DEV_TYPE_DEV_SLOT); |
||
376 | } |
||
377 | |||
378 | static void __init count_mem_devices(const struct dmi_header *dm, void *v) |
||
379 | { |
||
380 | if (dm->type != DMI_ENTRY_MEM_DEVICE) |
||
381 | return; |
||
382 | dmi_memdev_nr++; |
||
383 | } |
||
384 | |||
385 | static void __init save_mem_devices(const struct dmi_header *dm, void *v) |
||
386 | { |
||
387 | const char *d = (const char *)dm; |
||
388 | static int nr; |
||
389 | |||
390 | if (dm->type != DMI_ENTRY_MEM_DEVICE) |
||
391 | return; |
||
392 | if (nr >= dmi_memdev_nr) { |
||
393 | pr_warn(FW_BUG "Too many DIMM entries in SMBIOS table\n"); |
||
394 | return; |
||
395 | } |
||
396 | dmi_memdev[nr].handle = get_unaligned(&dm->handle); |
||
397 | dmi_memdev[nr].device = dmi_string(dm, d[0x10]); |
||
398 | dmi_memdev[nr].bank = dmi_string(dm, d[0x11]); |
||
399 | nr++; |
||
400 | } |
||
401 | |||
402 | void __init dmi_memdev_walk(void) |
||
403 | { |
||
404 | if (!dmi_available) |
||
405 | return; |
||
406 | |||
407 | if (dmi_walk_early(count_mem_devices) == 0 && dmi_memdev_nr) { |
||
408 | dmi_memdev = dmi_alloc(sizeof(*dmi_memdev) * dmi_memdev_nr); |
||
409 | if (dmi_memdev) |
||
410 | dmi_walk_early(save_mem_devices); |
||
411 | } |
||
412 | } |
||
413 | |||
414 | /* |
||
415 | * Process a DMI table entry. Right now all we care about are the BIOS |
||
416 | * and machine entries. For 2.5 we should pull the smbus controller info |
||
417 | * out of here. |
||
418 | */ |
||
419 | static void __init dmi_decode(const struct dmi_header *dm, void *dummy) |
||
420 | { |
||
421 | switch (dm->type) { |
||
422 | case 0: /* BIOS Information */ |
||
423 | dmi_save_ident(dm, DMI_BIOS_VENDOR, 4); |
||
424 | dmi_save_ident(dm, DMI_BIOS_VERSION, 5); |
||
425 | dmi_save_ident(dm, DMI_BIOS_DATE, 8); |
||
426 | break; |
||
427 | case 1: /* System Information */ |
||
428 | dmi_save_ident(dm, DMI_SYS_VENDOR, 4); |
||
429 | dmi_save_ident(dm, DMI_PRODUCT_NAME, 5); |
||
430 | dmi_save_ident(dm, DMI_PRODUCT_VERSION, 6); |
||
431 | dmi_save_ident(dm, DMI_PRODUCT_SERIAL, 7); |
||
432 | dmi_save_uuid(dm, DMI_PRODUCT_UUID, 8); |
||
433 | break; |
||
434 | case 2: /* Base Board Information */ |
||
435 | dmi_save_ident(dm, DMI_BOARD_VENDOR, 4); |
||
436 | dmi_save_ident(dm, DMI_BOARD_NAME, 5); |
||
437 | dmi_save_ident(dm, DMI_BOARD_VERSION, 6); |
||
438 | dmi_save_ident(dm, DMI_BOARD_SERIAL, 7); |
||
439 | dmi_save_ident(dm, DMI_BOARD_ASSET_TAG, 8); |
||
440 | break; |
||
441 | case 3: /* Chassis Information */ |
||
442 | dmi_save_ident(dm, DMI_CHASSIS_VENDOR, 4); |
||
443 | dmi_save_type(dm, DMI_CHASSIS_TYPE, 5); |
||
444 | dmi_save_ident(dm, DMI_CHASSIS_VERSION, 6); |
||
445 | dmi_save_ident(dm, DMI_CHASSIS_SERIAL, 7); |
||
446 | dmi_save_ident(dm, DMI_CHASSIS_ASSET_TAG, 8); |
||
447 | break; |
||
448 | case 9: /* System Slots */ |
||
449 | dmi_save_system_slot(dm); |
||
450 | break; |
||
451 | case 10: /* Onboard Devices Information */ |
||
452 | dmi_save_devices(dm); |
||
453 | break; |
||
454 | case 11: /* OEM Strings */ |
||
455 | dmi_save_oem_strings_devices(dm); |
||
456 | break; |
||
457 | case 38: /* IPMI Device Information */ |
||
458 | dmi_save_ipmi_device(dm); |
||
459 | break; |
||
460 | case 41: /* Onboard Devices Extended Information */ |
||
461 | dmi_save_extended_devices(dm); |
||
462 | } |
||
463 | } |
||
464 | |||
465 | static int __init print_filtered(char *buf, size_t len, const char *info) |
||
466 | { |
||
467 | int c = 0; |
||
468 | const char *p; |
||
469 | |||
470 | if (!info) |
||
471 | return c; |
||
472 | |||
473 | for (p = info; *p; p++) |
||
474 | if (isprint(*p)) |
||
475 | c += scnprintf(buf + c, len - c, "%c", *p); |
||
476 | else |
||
477 | c += scnprintf(buf + c, len - c, "\\x%02x", *p & 0xff); |
||
478 | return c; |
||
479 | } |
||
480 | |||
481 | static void __init dmi_format_ids(char *buf, size_t len) |
||
482 | { |
||
483 | int c = 0; |
||
484 | const char *board; /* Board Name is optional */ |
||
485 | |||
486 | c += print_filtered(buf + c, len - c, |
||
487 | dmi_get_system_info(DMI_SYS_VENDOR)); |
||
488 | c += scnprintf(buf + c, len - c, " "); |
||
489 | c += print_filtered(buf + c, len - c, |
||
490 | dmi_get_system_info(DMI_PRODUCT_NAME)); |
||
491 | |||
492 | board = dmi_get_system_info(DMI_BOARD_NAME); |
||
493 | if (board) { |
||
494 | c += scnprintf(buf + c, len - c, "/"); |
||
495 | c += print_filtered(buf + c, len - c, board); |
||
496 | } |
||
497 | c += scnprintf(buf + c, len - c, ", BIOS "); |
||
498 | c += print_filtered(buf + c, len - c, |
||
499 | dmi_get_system_info(DMI_BIOS_VERSION)); |
||
500 | c += scnprintf(buf + c, len - c, " "); |
||
501 | c += print_filtered(buf + c, len - c, |
||
502 | dmi_get_system_info(DMI_BIOS_DATE)); |
||
503 | } |
||
504 | |||
505 | /* |
||
506 | * Check for DMI/SMBIOS headers in the system firmware image. Any |
||
507 | * SMBIOS header must start 16 bytes before the DMI header, so take a |
||
508 | * 32 byte buffer and check for DMI at offset 16 and SMBIOS at offset |
||
509 | * 0. If the DMI header is present, set dmi_ver accordingly (SMBIOS |
||
510 | * takes precedence) and return 0. Otherwise return 1. |
||
511 | */ |
||
512 | static int __init dmi_present(const u8 *buf) |
||
513 | { |
||
514 | u32 smbios_ver; |
||
515 | |||
516 | if (memcmp(buf, "_SM_", 4) == 0 && |
||
517 | buf[5] < 32 && dmi_checksum(buf, buf[5])) { |
||
518 | smbios_ver = get_unaligned_be16(buf + 6); |
||
519 | smbios_entry_point_size = buf[5]; |
||
520 | memcpy(smbios_entry_point, buf, smbios_entry_point_size); |
||
521 | |||
522 | /* Some BIOS report weird SMBIOS version, fix that up */ |
||
523 | switch (smbios_ver) { |
||
524 | case 0x021F: |
||
525 | case 0x0221: |
||
526 | pr_debug("SMBIOS version fixup (2.%d->2.%d)\n", |
||
527 | smbios_ver & 0xFF, 3); |
||
528 | smbios_ver = 0x0203; |
||
529 | break; |
||
530 | case 0x0233: |
||
531 | pr_debug("SMBIOS version fixup (2.%d->2.%d)\n", 51, 6); |
||
532 | smbios_ver = 0x0206; |
||
533 | break; |
||
534 | } |
||
535 | } else { |
||
536 | smbios_ver = 0; |
||
537 | } |
||
538 | |||
539 | buf += 16; |
||
540 | |||
541 | if (memcmp(buf, "_DMI_", 5) == 0 && dmi_checksum(buf, 15)) { |
||
542 | if (smbios_ver) |
||
543 | dmi_ver = smbios_ver; |
||
544 | else |
||
545 | dmi_ver = (buf[14] & 0xF0) << 4 | (buf[14] & 0x0F); |
||
546 | dmi_ver <<= 8; |
||
547 | dmi_num = get_unaligned_le16(buf + 12); |
||
548 | dmi_len = get_unaligned_le16(buf + 6); |
||
549 | dmi_base = get_unaligned_le32(buf + 8); |
||
550 | |||
551 | if (dmi_walk_early(dmi_decode) == 0) { |
||
552 | if (smbios_ver) { |
||
553 | pr_info("SMBIOS %d.%d present.\n", |
||
554 | dmi_ver >> 16, (dmi_ver >> 8) & 0xFF); |
||
555 | } else { |
||
556 | smbios_entry_point_size = 15; |
||
557 | memcpy(smbios_entry_point, buf, |
||
558 | smbios_entry_point_size); |
||
559 | pr_info("Legacy DMI %d.%d present.\n", |
||
560 | dmi_ver >> 16, (dmi_ver >> 8) & 0xFF); |
||
561 | } |
||
562 | dmi_format_ids(dmi_ids_string, sizeof(dmi_ids_string)); |
||
563 | printk(KERN_DEBUG "DMI: %s\n", dmi_ids_string); |
||
564 | return 0; |
||
565 | } |
||
566 | } |
||
567 | |||
568 | return 1; |
||
569 | } |
||
570 | |||
571 | /* |
||
572 | * Check for the SMBIOS 3.0 64-bit entry point signature. Unlike the legacy |
||
573 | * 32-bit entry point, there is no embedded DMI header (_DMI_) in here. |
||
574 | */ |
||
575 | static int __init dmi_smbios3_present(const u8 *buf) |
||
576 | { |
||
577 | if (memcmp(buf, "_SM3_", 5) == 0 && |
||
578 | buf[6] < 32 && dmi_checksum(buf, buf[6])) { |
||
579 | dmi_ver = get_unaligned_be32(buf + 6) & 0xFFFFFF; |
||
580 | dmi_num = 0; /* No longer specified */ |
||
581 | dmi_len = get_unaligned_le32(buf + 12); |
||
582 | dmi_base = get_unaligned_le64(buf + 16); |
||
583 | smbios_entry_point_size = buf[6]; |
||
584 | memcpy(smbios_entry_point, buf, smbios_entry_point_size); |
||
585 | |||
586 | if (dmi_walk_early(dmi_decode) == 0) { |
||
587 | pr_info("SMBIOS %d.%d.%d present.\n", |
||
588 | dmi_ver >> 16, (dmi_ver >> 8) & 0xFF, |
||
589 | dmi_ver & 0xFF); |
||
590 | dmi_format_ids(dmi_ids_string, sizeof(dmi_ids_string)); |
||
591 | pr_debug("DMI: %s\n", dmi_ids_string); |
||
592 | return 0; |
||
593 | } |
||
594 | } |
||
595 | return 1; |
||
596 | } |
||
597 | |||
598 | void __init dmi_scan_machine(void) |
||
599 | { |
||
600 | char __iomem *p, *q; |
||
601 | char buf[32]; |
||
602 | |||
603 | if (efi_enabled(EFI_CONFIG_TABLES)) { |
||
604 | /* |
||
605 | * According to the DMTF SMBIOS reference spec v3.0.0, it is |
||
606 | * allowed to define both the 64-bit entry point (smbios3) and |
||
607 | * the 32-bit entry point (smbios), in which case they should |
||
608 | * either both point to the same SMBIOS structure table, or the |
||
609 | * table pointed to by the 64-bit entry point should contain a |
||
610 | * superset of the table contents pointed to by the 32-bit entry |
||
611 | * point (section 5.2) |
||
612 | * This implies that the 64-bit entry point should have |
||
613 | * precedence if it is defined and supported by the OS. If we |
||
614 | * have the 64-bit entry point, but fail to decode it, fall |
||
615 | * back to the legacy one (if available) |
||
616 | */ |
||
617 | if (efi.smbios3 != EFI_INVALID_TABLE_ADDR) { |
||
618 | p = dmi_early_remap(efi.smbios3, 32); |
||
619 | if (p == NULL) |
||
620 | goto error; |
||
621 | memcpy_fromio(buf, p, 32); |
||
622 | dmi_early_unmap(p, 32); |
||
623 | |||
624 | if (!dmi_smbios3_present(buf)) { |
||
625 | dmi_available = 1; |
||
626 | goto out; |
||
627 | } |
||
628 | } |
||
629 | if (efi.smbios == EFI_INVALID_TABLE_ADDR) |
||
630 | goto error; |
||
631 | |||
632 | /* This is called as a core_initcall() because it isn't |
||
633 | * needed during early boot. This also means we can |
||
634 | * iounmap the space when we're done with it. |
||
635 | */ |
||
636 | p = dmi_early_remap(efi.smbios, 32); |
||
637 | if (p == NULL) |
||
638 | goto error; |
||
639 | memcpy_fromio(buf, p, 32); |
||
640 | dmi_early_unmap(p, 32); |
||
641 | |||
642 | if (!dmi_present(buf)) { |
||
643 | dmi_available = 1; |
||
644 | goto out; |
||
645 | } |
||
646 | } else if (IS_ENABLED(CONFIG_DMI_SCAN_MACHINE_NON_EFI_FALLBACK)) { |
||
647 | p = dmi_early_remap(0xF0000, 0x10000); |
||
648 | if (p == NULL) |
||
649 | goto error; |
||
650 | |||
651 | /* |
||
652 | * Iterate over all possible DMI header addresses q. |
||
653 | * Maintain the 32 bytes around q in buf. On the |
||
654 | * first iteration, substitute zero for the |
||
655 | * out-of-range bytes so there is no chance of falsely |
||
656 | * detecting an SMBIOS header. |
||
657 | */ |
||
658 | memset(buf, 0, 16); |
||
659 | for (q = p; q < p + 0x10000; q += 16) { |
||
660 | memcpy_fromio(buf + 16, q, 16); |
||
661 | if (!dmi_smbios3_present(buf) || !dmi_present(buf)) { |
||
662 | dmi_available = 1; |
||
663 | dmi_early_unmap(p, 0x10000); |
||
664 | goto out; |
||
665 | } |
||
666 | memcpy(buf, buf + 16, 16); |
||
667 | } |
||
668 | dmi_early_unmap(p, 0x10000); |
||
669 | } |
||
670 | error: |
||
671 | pr_info("DMI not present or invalid.\n"); |
||
672 | out: |
||
673 | dmi_initialized = 1; |
||
674 | } |
||
675 | |||
676 | static ssize_t raw_table_read(struct file *file, struct kobject *kobj, |
||
677 | struct bin_attribute *attr, char *buf, |
||
678 | loff_t pos, size_t count) |
||
679 | { |
||
680 | memcpy(buf, attr->private + pos, count); |
||
681 | return count; |
||
682 | } |
||
683 | |||
684 | static BIN_ATTR(smbios_entry_point, S_IRUSR, raw_table_read, NULL, 0); |
||
685 | static BIN_ATTR(DMI, S_IRUSR, raw_table_read, NULL, 0); |
||
686 | |||
687 | static int __init dmi_init(void) |
||
688 | { |
||
689 | struct kobject *tables_kobj; |
||
690 | u8 *dmi_table; |
||
691 | int ret = -ENOMEM; |
||
692 | |||
693 | if (!dmi_available) { |
||
694 | ret = -ENODATA; |
||
695 | goto err; |
||
696 | } |
||
697 | |||
698 | /* |
||
699 | * Set up dmi directory at /sys/firmware/dmi. This entry should stay |
||
700 | * even after farther error, as it can be used by other modules like |
||
701 | * dmi-sysfs. |
||
702 | */ |
||
703 | dmi_kobj = kobject_create_and_add("dmi", firmware_kobj); |
||
704 | if (!dmi_kobj) |
||
705 | goto err; |
||
706 | |||
707 | tables_kobj = kobject_create_and_add("tables", dmi_kobj); |
||
708 | if (!tables_kobj) |
||
709 | goto err; |
||
710 | |||
711 | dmi_table = dmi_remap(dmi_base, dmi_len); |
||
712 | if (!dmi_table) |
||
713 | goto err_tables; |
||
714 | |||
715 | bin_attr_smbios_entry_point.size = smbios_entry_point_size; |
||
716 | bin_attr_smbios_entry_point.private = smbios_entry_point; |
||
717 | ret = sysfs_create_bin_file(tables_kobj, &bin_attr_smbios_entry_point); |
||
718 | if (ret) |
||
719 | goto err_unmap; |
||
720 | |||
721 | bin_attr_DMI.size = dmi_len; |
||
722 | bin_attr_DMI.private = dmi_table; |
||
723 | ret = sysfs_create_bin_file(tables_kobj, &bin_attr_DMI); |
||
724 | if (!ret) |
||
725 | return 0; |
||
726 | |||
727 | sysfs_remove_bin_file(tables_kobj, |
||
728 | &bin_attr_smbios_entry_point); |
||
729 | err_unmap: |
||
730 | dmi_unmap(dmi_table); |
||
731 | err_tables: |
||
732 | kobject_del(tables_kobj); |
||
733 | kobject_put(tables_kobj); |
||
734 | err: |
||
735 | pr_err("dmi: Firmware registration failed.\n"); |
||
736 | |||
737 | return ret; |
||
738 | } |
||
739 | subsys_initcall(dmi_init); |
||
740 | |||
741 | /** |
||
742 | * dmi_set_dump_stack_arch_desc - set arch description for dump_stack() |
||
743 | * |
||
744 | * Invoke dump_stack_set_arch_desc() with DMI system information so that |
||
745 | * DMI identifiers are printed out on task dumps. Arch boot code should |
||
746 | * call this function after dmi_scan_machine() if it wants to print out DMI |
||
747 | * identifiers on task dumps. |
||
748 | */ |
||
749 | void __init dmi_set_dump_stack_arch_desc(void) |
||
750 | { |
||
751 | dump_stack_set_arch_desc("%s", dmi_ids_string); |
||
752 | } |
||
753 | |||
754 | /** |
||
755 | * dmi_matches - check if dmi_system_id structure matches system DMI data |
||
756 | * @dmi: pointer to the dmi_system_id structure to check |
||
757 | */ |
||
758 | static bool dmi_matches(const struct dmi_system_id *dmi) |
||
759 | { |
||
760 | int i; |
||
761 | |||
762 | WARN(!dmi_initialized, KERN_ERR "dmi check: not initialized yet.\n"); |
||
763 | |||
764 | for (i = 0; i < ARRAY_SIZE(dmi->matches); i++) { |
||
765 | int s = dmi->matches[i].slot; |
||
766 | if (s == DMI_NONE) |
||
767 | break; |
||
768 | if (dmi_ident[s]) { |
||
769 | if (!dmi->matches[i].exact_match && |
||
770 | strstr(dmi_ident[s], dmi->matches[i].substr)) |
||
771 | continue; |
||
772 | else if (dmi->matches[i].exact_match && |
||
773 | !strcmp(dmi_ident[s], dmi->matches[i].substr)) |
||
774 | continue; |
||
775 | } |
||
776 | |||
777 | /* No match */ |
||
778 | return false; |
||
779 | } |
||
780 | return true; |
||
781 | } |
||
782 | |||
783 | /** |
||
784 | * dmi_is_end_of_table - check for end-of-table marker |
||
785 | * @dmi: pointer to the dmi_system_id structure to check |
||
786 | */ |
||
787 | static bool dmi_is_end_of_table(const struct dmi_system_id *dmi) |
||
788 | { |
||
789 | return dmi->matches[0].slot == DMI_NONE; |
||
790 | } |
||
791 | |||
792 | /** |
||
793 | * dmi_check_system - check system DMI data |
||
794 | * @list: array of dmi_system_id structures to match against |
||
795 | * All non-null elements of the list must match |
||
796 | * their slot's (field index's) data (i.e., each |
||
797 | * list string must be a substring of the specified |
||
798 | * DMI slot's string data) to be considered a |
||
799 | * successful match. |
||
800 | * |
||
801 | * Walk the blacklist table running matching functions until someone |
||
802 | * returns non zero or we hit the end. Callback function is called for |
||
803 | * each successful match. Returns the number of matches. |
||
804 | */ |
||
805 | int dmi_check_system(const struct dmi_system_id *list) |
||
806 | { |
||
807 | int count = 0; |
||
808 | const struct dmi_system_id *d; |
||
809 | |||
810 | for (d = list; !dmi_is_end_of_table(d); d++) |
||
811 | if (dmi_matches(d)) { |
||
812 | count++; |
||
813 | if (d->callback && d->callback(d)) |
||
814 | break; |
||
815 | } |
||
816 | |||
817 | return count; |
||
818 | } |
||
819 | EXPORT_SYMBOL(dmi_check_system); |
||
820 | |||
821 | /** |
||
822 | * dmi_first_match - find dmi_system_id structure matching system DMI data |
||
823 | * @list: array of dmi_system_id structures to match against |
||
824 | * All non-null elements of the list must match |
||
825 | * their slot's (field index's) data (i.e., each |
||
826 | * list string must be a substring of the specified |
||
827 | * DMI slot's string data) to be considered a |
||
828 | * successful match. |
||
829 | * |
||
830 | * Walk the blacklist table until the first match is found. Return the |
||
831 | * pointer to the matching entry or NULL if there's no match. |
||
832 | */ |
||
833 | const struct dmi_system_id *dmi_first_match(const struct dmi_system_id *list) |
||
834 | { |
||
835 | const struct dmi_system_id *d; |
||
836 | |||
837 | for (d = list; !dmi_is_end_of_table(d); d++) |
||
838 | if (dmi_matches(d)) |
||
839 | return d; |
||
840 | |||
841 | return NULL; |
||
842 | } |
||
843 | EXPORT_SYMBOL(dmi_first_match); |
||
844 | |||
845 | /** |
||
846 | * dmi_get_system_info - return DMI data value |
||
847 | * @field: data index (see enum dmi_field) |
||
848 | * |
||
849 | * Returns one DMI data value, can be used to perform |
||
850 | * complex DMI data checks. |
||
851 | */ |
||
852 | const char *dmi_get_system_info(int field) |
||
853 | { |
||
854 | return dmi_ident[field]; |
||
855 | } |
||
856 | EXPORT_SYMBOL(dmi_get_system_info); |
||
857 | |||
858 | /** |
||
859 | * dmi_name_in_serial - Check if string is in the DMI product serial information |
||
860 | * @str: string to check for |
||
861 | */ |
||
862 | int dmi_name_in_serial(const char *str) |
||
863 | { |
||
864 | int f = DMI_PRODUCT_SERIAL; |
||
865 | if (dmi_ident[f] && strstr(dmi_ident[f], str)) |
||
866 | return 1; |
||
867 | return 0; |
||
868 | } |
||
869 | |||
870 | /** |
||
871 | * dmi_name_in_vendors - Check if string is in the DMI system or board vendor name |
||
872 | * @str: Case sensitive Name |
||
873 | */ |
||
874 | int dmi_name_in_vendors(const char *str) |
||
875 | { |
||
876 | static int fields[] = { DMI_SYS_VENDOR, DMI_BOARD_VENDOR, DMI_NONE }; |
||
877 | int i; |
||
878 | for (i = 0; fields[i] != DMI_NONE; i++) { |
||
879 | int f = fields[i]; |
||
880 | if (dmi_ident[f] && strstr(dmi_ident[f], str)) |
||
881 | return 1; |
||
882 | } |
||
883 | return 0; |
||
884 | } |
||
885 | EXPORT_SYMBOL(dmi_name_in_vendors); |
||
886 | |||
887 | /** |
||
888 | * dmi_find_device - find onboard device by type/name |
||
889 | * @type: device type or %DMI_DEV_TYPE_ANY to match all device types |
||
890 | * @name: device name string or %NULL to match all |
||
891 | * @from: previous device found in search, or %NULL for new search. |
||
892 | * |
||
893 | * Iterates through the list of known onboard devices. If a device is |
||
894 | * found with a matching @type and @name, a pointer to its device |
||
895 | * structure is returned. Otherwise, %NULL is returned. |
||
896 | * A new search is initiated by passing %NULL as the @from argument. |
||
897 | * If @from is not %NULL, searches continue from next device. |
||
898 | */ |
||
899 | const struct dmi_device *dmi_find_device(int type, const char *name, |
||
900 | const struct dmi_device *from) |
||
901 | { |
||
902 | const struct list_head *head = from ? &from->list : &dmi_devices; |
||
903 | struct list_head *d; |
||
904 | |||
905 | for (d = head->next; d != &dmi_devices; d = d->next) { |
||
906 | const struct dmi_device *dev = |
||
907 | list_entry(d, struct dmi_device, list); |
||
908 | |||
909 | if (((type == DMI_DEV_TYPE_ANY) || (dev->type == type)) && |
||
910 | ((name == NULL) || (strcmp(dev->name, name) == 0))) |
||
911 | return dev; |
||
912 | } |
||
913 | |||
914 | return NULL; |
||
915 | } |
||
916 | EXPORT_SYMBOL(dmi_find_device); |
||
917 | |||
918 | /** |
||
919 | * dmi_get_date - parse a DMI date |
||
920 | * @field: data index (see enum dmi_field) |
||
921 | * @yearp: optional out parameter for the year |
||
922 | * @monthp: optional out parameter for the month |
||
923 | * @dayp: optional out parameter for the day |
||
924 | * |
||
925 | * The date field is assumed to be in the form resembling |
||
926 | * [mm[/dd]]/yy[yy] and the result is stored in the out |
||
927 | * parameters any or all of which can be omitted. |
||
928 | * |
||
929 | * If the field doesn't exist, all out parameters are set to zero |
||
930 | * and false is returned. Otherwise, true is returned with any |
||
931 | * invalid part of date set to zero. |
||
932 | * |
||
933 | * On return, year, month and day are guaranteed to be in the |
||
934 | * range of [0,9999], [0,12] and [0,31] respectively. |
||
935 | */ |
||
936 | bool dmi_get_date(int field, int *yearp, int *monthp, int *dayp) |
||
937 | { |
||
938 | int year = 0, month = 0, day = 0; |
||
939 | bool exists; |
||
940 | const char *s, *y; |
||
941 | char *e; |
||
942 | |||
943 | s = dmi_get_system_info(field); |
||
944 | exists = s; |
||
945 | if (!exists) |
||
946 | goto out; |
||
947 | |||
948 | /* |
||
949 | * Determine year first. We assume the date string resembles |
||
950 | * mm/dd/yy[yy] but the original code extracted only the year |
||
951 | * from the end. Keep the behavior in the spirit of no |
||
952 | * surprises. |
||
953 | */ |
||
954 | y = strrchr(s, '/'); |
||
955 | if (!y) |
||
956 | goto out; |
||
957 | |||
958 | y++; |
||
959 | year = simple_strtoul(y, &e, 10); |
||
960 | if (y != e && year < 100) { /* 2-digit year */ |
||
961 | year += 1900; |
||
962 | if (year < 1996) /* no dates < spec 1.0 */ |
||
963 | year += 100; |
||
964 | } |
||
965 | if (year > 9999) /* year should fit in %04d */ |
||
966 | year = 0; |
||
967 | |||
968 | /* parse the mm and dd */ |
||
969 | month = simple_strtoul(s, &e, 10); |
||
970 | if (s == e || *e != '/' || !month || month > 12) { |
||
971 | month = 0; |
||
972 | goto out; |
||
973 | } |
||
974 | |||
975 | s = e + 1; |
||
976 | day = simple_strtoul(s, &e, 10); |
||
977 | if (s == y || s == e || *e != '/' || day > 31) |
||
978 | day = 0; |
||
979 | out: |
||
980 | if (yearp) |
||
981 | *yearp = year; |
||
982 | if (monthp) |
||
983 | *monthp = month; |
||
984 | if (dayp) |
||
985 | *dayp = day; |
||
986 | return exists; |
||
987 | } |
||
988 | EXPORT_SYMBOL(dmi_get_date); |
||
989 | |||
990 | /** |
||
991 | * dmi_walk - Walk the DMI table and get called back for every record |
||
992 | * @decode: Callback function |
||
993 | * @private_data: Private data to be passed to the callback function |
||
994 | * |
||
995 | * Returns -1 when the DMI table can't be reached, 0 on success. |
||
996 | */ |
||
997 | int dmi_walk(void (*decode)(const struct dmi_header *, void *), |
||
998 | void *private_data) |
||
999 | { |
||
1000 | u8 *buf; |
||
1001 | |||
1002 | if (!dmi_available) |
||
1003 | return -1; |
||
1004 | |||
1005 | buf = dmi_remap(dmi_base, dmi_len); |
||
1006 | if (buf == NULL) |
||
1007 | return -1; |
||
1008 | |||
1009 | dmi_decode_table(buf, decode, private_data); |
||
1010 | |||
1011 | dmi_unmap(buf); |
||
1012 | return 0; |
||
1013 | } |
||
1014 | EXPORT_SYMBOL_GPL(dmi_walk); |
||
1015 | |||
1016 | /** |
||
1017 | * dmi_match - compare a string to the dmi field (if exists) |
||
1018 | * @f: DMI field identifier |
||
1019 | * @str: string to compare the DMI field to |
||
1020 | * |
||
1021 | * Returns true if the requested field equals to the str (including NULL). |
||
1022 | */ |
||
1023 | bool dmi_match(enum dmi_field f, const char *str) |
||
1024 | { |
||
1025 | const char *info = dmi_get_system_info(f); |
||
1026 | |||
1027 | if (info == NULL || str == NULL) |
||
1028 | return info == str; |
||
1029 | |||
1030 | return !strcmp(info, str); |
||
1031 | } |
||
1032 | EXPORT_SYMBOL_GPL(dmi_match); |
||
1033 | |||
1034 | void dmi_memdev_name(u16 handle, const char **bank, const char **device) |
||
1035 | { |
||
1036 | int n; |
||
1037 | |||
1038 | if (dmi_memdev == NULL) |
||
1039 | return; |
||
1040 | |||
1041 | for (n = 0; n < dmi_memdev_nr; n++) { |
||
1042 | if (handle == dmi_memdev[n].handle) { |
||
1043 | *bank = dmi_memdev[n].bank; |
||
1044 | *device = dmi_memdev[n].device; |
||
1045 | break; |
||
1046 | } |
||
1047 | } |
||
1048 | } |
||
1049 | EXPORT_SYMBOL_GPL(dmi_memdev_name);>>>>>>>=><=>><>>>=>>>>>>=>>> |