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