1 | /* ----------------------------------------------------------------------- * |
---|
2 | * |
---|
3 | * Copyright 2006 Erwan Velu - All Rights Reserved |
---|
4 | * |
---|
5 | * Permission is hereby granted, free of charge, to any person |
---|
6 | * obtaining a copy of this software and associated documentation |
---|
7 | * files (the "Software"), to deal in the Software without |
---|
8 | * restriction, including without limitation the rights to use, |
---|
9 | * copy, modify, merge, publish, distribute, sublicense, and/or |
---|
10 | * sell copies of the Software, and to permit persons to whom |
---|
11 | * the Software is furnished to do so, subject to the following |
---|
12 | * conditions: |
---|
13 | * |
---|
14 | * The above copyright notice and this permission notice shall |
---|
15 | * be included in all copies or substantial portions of the Software. |
---|
16 | * |
---|
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, |
---|
18 | * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES |
---|
19 | * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND |
---|
20 | * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT |
---|
21 | * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, |
---|
22 | * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
---|
23 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR |
---|
24 | * OTHER DEALINGS IN THE SOFTWARE. |
---|
25 | * |
---|
26 | * ----------------------------------------------------------------------- |
---|
27 | */ |
---|
28 | |
---|
29 | #include <stdio.h> |
---|
30 | #include <string.h> |
---|
31 | #include "dmi/dmi.h" |
---|
32 | |
---|
33 | const char *out_of_spec = "<OUT OF SPEC>"; |
---|
34 | const char *bad_index = "<BAD INDEX>"; |
---|
35 | |
---|
36 | /* |
---|
37 | * Misc. util stuff |
---|
38 | */ |
---|
39 | |
---|
40 | /* |
---|
41 | * 3.3.11 On Board Devices Information (Type 10) |
---|
42 | */ |
---|
43 | |
---|
44 | static const char *dmi_on_board_devices_type(uint8_t code) |
---|
45 | { |
---|
46 | /* 3.3.11.1 */ |
---|
47 | static const char *type[] = { |
---|
48 | "Other", /* 0x01 */ |
---|
49 | "Unknown", |
---|
50 | "Video", |
---|
51 | "SCSI Controller", |
---|
52 | "Ethernet", |
---|
53 | "Token Ring", |
---|
54 | "Sound", |
---|
55 | "PATA Controller", |
---|
56 | "SATA Controller", |
---|
57 | "SAS Controller" /* 0x0A */ |
---|
58 | }; |
---|
59 | |
---|
60 | if (code >= 0x01 && code <= 0x0A) |
---|
61 | return type[code - 0x01]; |
---|
62 | return out_of_spec; |
---|
63 | } |
---|
64 | |
---|
65 | static void dmi_on_board_devices(struct dmi_header *h, s_dmi * dmi) |
---|
66 | { |
---|
67 | uint8_t *p = h->data + 4; |
---|
68 | uint8_t count = (h->length - 0x04) / 2; |
---|
69 | unsigned int i; |
---|
70 | |
---|
71 | for (i = 0; |
---|
72 | i < count |
---|
73 | && i < |
---|
74 | sizeof dmi->base_board.devices_information / |
---|
75 | sizeof *dmi->base_board.devices_information; i++) { |
---|
76 | strlcpy(dmi->base_board.devices_information[i].type, |
---|
77 | dmi_on_board_devices_type(p[2 * i] & 0x7F), |
---|
78 | sizeof dmi->base_board.devices_information[i].type); |
---|
79 | dmi->base_board.devices_information[i].status = p[2 * i] & 0x80; |
---|
80 | strlcpy(dmi->base_board.devices_information[i].description, |
---|
81 | dmi_string(h, p[2 * i + 1]), |
---|
82 | sizeof dmi->base_board.devices_information[i].description); |
---|
83 | } |
---|
84 | } |
---|
85 | |
---|
86 | /* |
---|
87 | * 3.3.24 System Reset (Type 23) |
---|
88 | */ |
---|
89 | |
---|
90 | static const char *dmi_system_reset_boot_option(uint8_t code) |
---|
91 | { |
---|
92 | static const char *option[] = { |
---|
93 | "Operating System", /* 0x1 */ |
---|
94 | "System Utilities", |
---|
95 | "Do Not Reboot" /* 0x3 */ |
---|
96 | }; |
---|
97 | |
---|
98 | if (code >= 0x1) |
---|
99 | return option[code - 0x1]; |
---|
100 | return out_of_spec; |
---|
101 | } |
---|
102 | |
---|
103 | static void dmi_system_reset_count(uint16_t code, char *array) |
---|
104 | { |
---|
105 | if (code == 0xFFFF) |
---|
106 | strlcpy(array, "Unknown", sizeof array); |
---|
107 | else |
---|
108 | snprintf(array, sizeof array, "%u", code); |
---|
109 | } |
---|
110 | |
---|
111 | static void dmi_system_reset_timer(uint16_t code, char *array) |
---|
112 | { |
---|
113 | if (code == 0xFFFF) |
---|
114 | strlcpy(array, "Unknown", sizeof array); |
---|
115 | else |
---|
116 | snprintf(array, sizeof array, "%u min", code); |
---|
117 | } |
---|
118 | |
---|
119 | /* |
---|
120 | * 3.3.25 Hardware Security (Type 24) |
---|
121 | */ |
---|
122 | |
---|
123 | static const char *dmi_hardware_security_status(uint8_t code) |
---|
124 | { |
---|
125 | static const char *status[] = { |
---|
126 | "Disabled", /* 0x00 */ |
---|
127 | "Enabled", |
---|
128 | "Not Implemented", |
---|
129 | "Unknown" /* 0x03 */ |
---|
130 | }; |
---|
131 | |
---|
132 | return status[code]; |
---|
133 | } |
---|
134 | |
---|
135 | /* |
---|
136 | * 3.3.12 OEM Strings (Type 11) |
---|
137 | */ |
---|
138 | |
---|
139 | static void dmi_oem_strings(struct dmi_header *h, const char *prefix, |
---|
140 | s_dmi * dmi) |
---|
141 | { |
---|
142 | uint8_t *p = h->data + 4; |
---|
143 | uint8_t count = p[0x00]; |
---|
144 | int i; |
---|
145 | |
---|
146 | for (i = 1; i <= count; i++) |
---|
147 | snprintf(dmi->oem_strings, OEM_STRINGS_SIZE, "%s %s %s\n", |
---|
148 | dmi->oem_strings, prefix, dmi_string(h, i)); |
---|
149 | } |
---|
150 | |
---|
151 | /* |
---|
152 | * 3.3.13 System Configuration Options (Type 12) |
---|
153 | */ |
---|
154 | static void dmi_system_configuration_options(struct dmi_header *h, |
---|
155 | const char *prefix, s_dmi * dmi) |
---|
156 | { |
---|
157 | uint8_t *p = h->data + 4; |
---|
158 | uint8_t count = p[0x00]; |
---|
159 | int i; |
---|
160 | |
---|
161 | for (i = 1; i <= count; i++) |
---|
162 | snprintf(dmi->system.configuration_options, |
---|
163 | SYSTEM_CONFIGURATION_OPTIONS_SIZE, "%s %s %s\n", |
---|
164 | dmi->system.configuration_options, prefix, dmi_string(h, i)); |
---|
165 | } |
---|
166 | |
---|
167 | static void dmi_system_boot_status(uint8_t code, char *array) |
---|
168 | { |
---|
169 | static const char *status[] = { |
---|
170 | "No errors detected", /* 0 */ |
---|
171 | "No bootable media", |
---|
172 | "Operating system failed to load", |
---|
173 | "Firmware-detected hardware failure", |
---|
174 | "Operating system-detected hardware failure", |
---|
175 | "User-requested boot", |
---|
176 | "System security violation", |
---|
177 | "Previously-requested image", |
---|
178 | "System watchdog timer expired" /* 8 */ |
---|
179 | }; |
---|
180 | |
---|
181 | if (code <= 8) |
---|
182 | strlcpy(array, status[code], SYSTEM_BOOT_STATUS_SIZE); |
---|
183 | if (code >= 128 && code <= 191) |
---|
184 | strlcpy(array, "OEM-specific", SYSTEM_BOOT_STATUS_SIZE); |
---|
185 | if (code >= 192) |
---|
186 | strlcpy(array, "Product-specific", SYSTEM_BOOT_STATUS_SIZE); |
---|
187 | } |
---|
188 | |
---|
189 | void dmi_bios_runtime_size(uint32_t code, s_dmi * dmi) |
---|
190 | { |
---|
191 | if (code & 0x000003FF) { |
---|
192 | dmi->bios.runtime_size = code; |
---|
193 | strlcpy(dmi->bios.runtime_size_unit, "bytes", |
---|
194 | sizeof(dmi->bios.runtime_size_unit)); |
---|
195 | } else { |
---|
196 | dmi->bios.runtime_size = code >> 10; |
---|
197 | strlcpy(dmi->bios.runtime_size_unit, "KB", |
---|
198 | sizeof(dmi->bios.runtime_size_unit)); |
---|
199 | |
---|
200 | } |
---|
201 | } |
---|
202 | |
---|
203 | void dmi_bios_characteristics(uint64_t code, s_dmi * dmi) |
---|
204 | { |
---|
205 | int i; |
---|
206 | /* |
---|
207 | * This isn't very clear what this bit is supposed to mean |
---|
208 | */ |
---|
209 | //if(code.l&(1<<3)) |
---|
210 | if (code && (1 << 3)) { |
---|
211 | ((bool *) (&dmi->bios.characteristics))[0] = true; |
---|
212 | return; |
---|
213 | } |
---|
214 | |
---|
215 | for (i = 4; i <= 31; i++) |
---|
216 | //if(code.l&(1<<i)) |
---|
217 | if (code & (1 << i)) |
---|
218 | ((bool *) (&dmi->bios.characteristics))[i - 3] = true; |
---|
219 | } |
---|
220 | |
---|
221 | void dmi_bios_characteristics_x1(uint8_t code, s_dmi * dmi) |
---|
222 | { |
---|
223 | int i; |
---|
224 | |
---|
225 | for (i = 0; i <= 7; i++) |
---|
226 | if (code & (1 << i)) |
---|
227 | ((bool *) (&dmi->bios.characteristics_x1))[i] = true; |
---|
228 | } |
---|
229 | |
---|
230 | void dmi_bios_characteristics_x2(uint8_t code, s_dmi * dmi) |
---|
231 | { |
---|
232 | int i; |
---|
233 | |
---|
234 | for (i = 0; i <= 2; i++) |
---|
235 | if (code & (1 << i)) |
---|
236 | ((bool *) (&dmi->bios.characteristics_x2))[i] = true; |
---|
237 | } |
---|
238 | |
---|
239 | void dmi_system_uuid(uint8_t * p, s_dmi * dmi) |
---|
240 | { |
---|
241 | int only0xFF = 1, only0x00 = 1; |
---|
242 | int i; |
---|
243 | |
---|
244 | for (i = 0; i < 16 && (only0x00 || only0xFF); i++) { |
---|
245 | if (p[i] != 0x00) |
---|
246 | only0x00 = 0; |
---|
247 | if (p[i] != 0xFF) |
---|
248 | only0xFF = 0; |
---|
249 | } |
---|
250 | |
---|
251 | if (only0xFF) { |
---|
252 | sprintf(dmi->system.uuid, "Not Present"); |
---|
253 | return; |
---|
254 | } |
---|
255 | if (only0x00) { |
---|
256 | sprintf(dmi->system.uuid, "Not Settable"); |
---|
257 | return; |
---|
258 | } |
---|
259 | |
---|
260 | sprintf(dmi->system.uuid, |
---|
261 | "%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X", |
---|
262 | p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7], p[8], p[9], p[10], |
---|
263 | p[11], p[12], p[13], p[14], p[15]); |
---|
264 | } |
---|
265 | |
---|
266 | void dmi_system_wake_up_type(uint8_t code, s_dmi * dmi) |
---|
267 | { |
---|
268 | /* 3.3.2.1 */ |
---|
269 | static const char *type[] = { |
---|
270 | "Reserved", /* 0x00 */ |
---|
271 | "Other", |
---|
272 | "Unknown", |
---|
273 | "APM Timer", |
---|
274 | "Modem Ring", |
---|
275 | "LAN Remote", |
---|
276 | "Power Switch", |
---|
277 | "PCI PME#", |
---|
278 | "AC Power Restored" /* 0x08 */ |
---|
279 | }; |
---|
280 | |
---|
281 | if (code <= 0x08) { |
---|
282 | strlcpy(dmi->system.wakeup_type, type[code], |
---|
283 | sizeof(dmi->system.wakeup_type)); |
---|
284 | } else { |
---|
285 | strlcpy(dmi->system.wakeup_type, out_of_spec, |
---|
286 | sizeof(dmi->system.wakeup_type)); |
---|
287 | } |
---|
288 | return; |
---|
289 | } |
---|
290 | |
---|
291 | static void dmi_base_board_features(uint8_t code, s_dmi * dmi) |
---|
292 | { |
---|
293 | if ((code & 0x1F) != 0) { |
---|
294 | int i; |
---|
295 | |
---|
296 | for (i = 0; i <= 4; i++) |
---|
297 | if (code & (1 << i)) |
---|
298 | ((bool *) (&dmi->base_board.features))[i] = true; |
---|
299 | } |
---|
300 | } |
---|
301 | |
---|
302 | static void dmi_base_board_type(uint8_t code, s_dmi * dmi) |
---|
303 | { |
---|
304 | /* 3.3.3.2 */ |
---|
305 | static const char *type[] = { |
---|
306 | "Unknown", /* 0x01 */ |
---|
307 | "Other", |
---|
308 | "Server Blade", |
---|
309 | "Connectivity Switch", |
---|
310 | "System Management Module", |
---|
311 | "Processor Module", |
---|
312 | "I/O Module", |
---|
313 | "Memory Module", |
---|
314 | "Daughter Board", |
---|
315 | "Motherboard", |
---|
316 | "Processor+Memory Module", |
---|
317 | "Processor+I/O Module", |
---|
318 | "Interconnect Board" /* 0x0D */ |
---|
319 | }; |
---|
320 | |
---|
321 | if (code >= 0x01 && code <= 0x0D) { |
---|
322 | strlcpy(dmi->base_board.type, type[code], |
---|
323 | sizeof(dmi->base_board.type)); |
---|
324 | } else { |
---|
325 | strlcpy(dmi->base_board.type, out_of_spec, |
---|
326 | sizeof(dmi->base_board.type)); |
---|
327 | } |
---|
328 | return; |
---|
329 | } |
---|
330 | |
---|
331 | static void dmi_processor_voltage(uint8_t code, s_dmi * dmi) |
---|
332 | { |
---|
333 | /* 3.3.5.4 */ |
---|
334 | static const uint16_t voltage[] = { |
---|
335 | 5000, |
---|
336 | 3300, |
---|
337 | 2900 |
---|
338 | }; |
---|
339 | int i; |
---|
340 | |
---|
341 | if (code & 0x80) |
---|
342 | dmi->processor.voltage_mv = (code & 0x7f) * 100; |
---|
343 | else { |
---|
344 | for (i = 0; i <= 2; i++) |
---|
345 | if (code & (1 << i)) |
---|
346 | dmi->processor.voltage_mv = voltage[i]; |
---|
347 | } |
---|
348 | } |
---|
349 | |
---|
350 | static void dmi_processor_id(uint8_t type, uint8_t * p, const char *version, |
---|
351 | s_dmi * dmi) |
---|
352 | { |
---|
353 | /* |
---|
354 | * Extra flags are now returned in the ECX register when one calls |
---|
355 | * the CPUID instruction. Their meaning is explained in table 6, but |
---|
356 | * DMI doesn't support this yet. |
---|
357 | */ |
---|
358 | uint32_t eax, edx; |
---|
359 | int sig = 0; |
---|
360 | |
---|
361 | /* |
---|
362 | * This might help learn about new processors supporting the |
---|
363 | * CPUID instruction or another form of identification. |
---|
364 | */ |
---|
365 | sprintf(dmi->processor.id, "ID: %02X %02X %02X %02X %02X %02X %02X %02X\n", |
---|
366 | p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]); |
---|
367 | |
---|
368 | if (type == 0x05) { /* 80386 */ |
---|
369 | uint16_t dx = WORD(p); |
---|
370 | /* |
---|
371 | * 80386 have a different signature. |
---|
372 | */ |
---|
373 | dmi->processor.signature.type = (dx >> 12); |
---|
374 | dmi->processor.signature.family = ((dx >> 8) & 0xF); |
---|
375 | dmi->processor.signature.stepping = (dx >> 4) & 0xF; |
---|
376 | dmi->processor.signature.minor_stepping = (dx & 0xF); |
---|
377 | return; |
---|
378 | } |
---|
379 | if (type == 0x06) { /* 80486 */ |
---|
380 | uint16_t dx = WORD(p); |
---|
381 | /* |
---|
382 | * Not all 80486 CPU support the CPUID instruction, we have to find |
---|
383 | * wether the one we have here does or not. Note that this trick |
---|
384 | * works only because we know that 80486 must be little-endian. |
---|
385 | */ |
---|
386 | if ((dx & 0x0F00) == 0x0400 |
---|
387 | && ((dx & 0x00F0) == 0x0040 || (dx & 0x00F0) >= 0x0070) |
---|
388 | && ((dx & 0x000F) >= 0x0003)) |
---|
389 | sig = 1; |
---|
390 | else { |
---|
391 | dmi->processor.signature.type = ((dx >> 12) & 0x3); |
---|
392 | dmi->processor.signature.family = ((dx >> 8) & 0xF); |
---|
393 | dmi->processor.signature.model = ((dx >> 4) & 0xF); |
---|
394 | dmi->processor.signature.stepping = (dx & 0xF); |
---|
395 | return; |
---|
396 | } |
---|
397 | } else if ((type >= 0x0B && type <= 0x13) /* Intel, Cyrix */ |
---|
398 | ||(type >= 0xB0 && type <= 0xB3) /* Intel */ |
---|
399 | ||type == 0xB5 /* Intel */ |
---|
400 | || type == 0xB9) /* Intel */ |
---|
401 | sig = 1; |
---|
402 | else if ((type >= 0x18 && type <= 0x1D) /* AMD */ |
---|
403 | ||type == 0x1F /* AMD */ |
---|
404 | || (type >= 0xB6 && type <= 0xB7) /* AMD */ |
---|
405 | ||(type >= 0x83 && type <= 0x85)) /* AMD */ |
---|
406 | sig = 2; |
---|
407 | else if (type == 0x01 || type == 0x02) { |
---|
408 | /* |
---|
409 | * Some X86-class CPU have family "Other" or "Unknown". In this case, |
---|
410 | * we use the version string to determine if they are known to |
---|
411 | * support the CPUID instruction. |
---|
412 | */ |
---|
413 | if (strncmp(version, "Pentium III MMX", 15) == 0) |
---|
414 | sig = 1; |
---|
415 | else if (strncmp(version, "AMD Athlon(TM)", 14) == 0 |
---|
416 | || strncmp(version, "AMD Opteron(tm)", 15) == 0) |
---|
417 | sig = 2; |
---|
418 | else |
---|
419 | return; |
---|
420 | } else /* not X86-class */ |
---|
421 | return; |
---|
422 | |
---|
423 | eax = DWORD(p); |
---|
424 | edx = DWORD(p + 4); |
---|
425 | switch (sig) { |
---|
426 | case 1: /* Intel */ |
---|
427 | dmi->processor.signature.type = ((eax >> 12) & 0x3); |
---|
428 | dmi->processor.signature.family = |
---|
429 | (((eax >> 16) & 0xFF0) + ((eax >> 8) & 0x00F)); |
---|
430 | dmi->processor.signature.model = |
---|
431 | (((eax >> 12) & 0xF0) + ((eax >> 4) & 0x0F)); |
---|
432 | dmi->processor.signature.stepping = (eax & 0xF); |
---|
433 | break; |
---|
434 | case 2: /* AMD */ |
---|
435 | dmi->processor.signature.family = |
---|
436 | (((eax >> 8) & 0xF) == 0xF ? (eax >> 20) & 0xFF : (eax >> 8) & 0xF); |
---|
437 | dmi->processor.signature.model = |
---|
438 | (((eax >> 4) & 0xF) == 0xF ? (eax >> 16) & 0xF : (eax >> 4) & 0xF); |
---|
439 | dmi->processor.signature.stepping = (eax & 0xF); |
---|
440 | break; |
---|
441 | } |
---|
442 | |
---|
443 | edx = DWORD(p + 4); |
---|
444 | if ((edx & 0x3FF7FDFF) != 0) { |
---|
445 | int i; |
---|
446 | for (i = 0; i <= 31; i++) |
---|
447 | if (cpu_flags_strings[i] != NULL && edx & (1 << i)) |
---|
448 | ((bool *) (&dmi->processor.cpu_flags))[i] = true; |
---|
449 | } |
---|
450 | } |
---|
451 | |
---|
452 | void to_dmi_header(struct dmi_header *h, uint8_t * data) |
---|
453 | { |
---|
454 | h->type = data[0]; |
---|
455 | h->length = data[1]; |
---|
456 | h->handle = WORD(data + 2); |
---|
457 | h->data = data; |
---|
458 | } |
---|
459 | |
---|
460 | const char *dmi_string(struct dmi_header *dm, uint8_t s) |
---|
461 | { |
---|
462 | char *bp = (char *)dm->data; |
---|
463 | size_t i, len; |
---|
464 | |
---|
465 | if (s == 0) |
---|
466 | return "Not Specified"; |
---|
467 | |
---|
468 | bp += dm->length; |
---|
469 | while (s > 1 && *bp) { |
---|
470 | bp += strlen(bp); |
---|
471 | bp++; |
---|
472 | s--; |
---|
473 | } |
---|
474 | |
---|
475 | if (!*bp) |
---|
476 | return bad_index; |
---|
477 | |
---|
478 | /* ASCII filtering */ |
---|
479 | len = strlen(bp); |
---|
480 | for (i = 0; i < len; i++) |
---|
481 | if (bp[i] < 32 || bp[i] == 127) |
---|
482 | bp[i] = '.'; |
---|
483 | |
---|
484 | return bp; |
---|
485 | } |
---|
486 | |
---|
487 | int checksum(uint8_t * buf, int len) |
---|
488 | { |
---|
489 | uint8_t sum = 0; |
---|
490 | int a; |
---|
491 | |
---|
492 | for (a = 0; a < len; a++) |
---|
493 | sum += buf[a]; |
---|
494 | return (sum == 0); |
---|
495 | } |
---|
496 | |
---|
497 | static int smbios_decode(s_dmi * dmi, uint8_t * buf) |
---|
498 | { |
---|
499 | |
---|
500 | dmi->dmitable.ver = (buf[0x06] << 8) + buf[0x07]; |
---|
501 | /* Some BIOS report weird SMBIOS version, fix that up */ |
---|
502 | switch (dmi->dmitable.ver) { |
---|
503 | case 0x021F: |
---|
504 | dmi->dmitable.ver = 0x0203; |
---|
505 | break; |
---|
506 | case 0x0233: |
---|
507 | dmi->dmitable.ver = 0x0206; |
---|
508 | break; |
---|
509 | } |
---|
510 | dmi->dmitable.major_version = dmi->dmitable.ver >> 8; |
---|
511 | dmi->dmitable.minor_version = dmi->dmitable.ver & 0xFF; |
---|
512 | |
---|
513 | return DMI_TABLE_PRESENT; |
---|
514 | } |
---|
515 | |
---|
516 | static int legacy_decode(s_dmi * dmi, uint8_t * buf) |
---|
517 | { |
---|
518 | dmi->dmitable.num = buf[13] << 8 | buf[12]; |
---|
519 | dmi->dmitable.len = buf[7] << 8 | buf[6]; |
---|
520 | dmi->dmitable.base = buf[11] << 24 | buf[10] << 16 | buf[9] << 8 | buf[8]; |
---|
521 | |
---|
522 | /* Version already found? */ |
---|
523 | if (dmi->dmitable.ver > 0) |
---|
524 | return DMI_TABLE_PRESENT; |
---|
525 | |
---|
526 | dmi->dmitable.ver = (buf[0x06] << 8) + buf[0x07]; |
---|
527 | |
---|
528 | /* |
---|
529 | * DMI version 0.0 means that the real version is taken from |
---|
530 | * the SMBIOS version, which we don't know at this point. |
---|
531 | */ |
---|
532 | if (buf[14] != 0) { |
---|
533 | dmi->dmitable.major_version = buf[14] >> 4; |
---|
534 | dmi->dmitable.minor_version = buf[14] & 0x0F; |
---|
535 | } else { |
---|
536 | dmi->dmitable.major_version = 0; |
---|
537 | dmi->dmitable.minor_version = 0; |
---|
538 | } |
---|
539 | return DMI_TABLE_PRESENT; |
---|
540 | } |
---|
541 | |
---|
542 | int dmi_iterate(s_dmi * dmi) |
---|
543 | { |
---|
544 | uint8_t *p, *q; |
---|
545 | int found = 0; |
---|
546 | |
---|
547 | /* Cleaning structures */ |
---|
548 | memset(dmi, 0, sizeof(s_dmi)); |
---|
549 | |
---|
550 | memset(&dmi->base_board, 0, sizeof(s_base_board)); |
---|
551 | memset(&dmi->battery, 0, sizeof(s_battery)); |
---|
552 | memset(&dmi->bios, 0, sizeof(s_bios)); |
---|
553 | memset(&dmi->chassis, 0, sizeof(s_chassis)); |
---|
554 | for (int i = 0; i < MAX_DMI_MEMORY_ITEMS; i++) |
---|
555 | memset(&dmi->memory[i], 0, sizeof(s_memory)); |
---|
556 | memset(&dmi->processor, 0, sizeof(s_processor)); |
---|
557 | memset(&dmi->system, 0, sizeof(s_system)); |
---|
558 | |
---|
559 | /* Until we found this elements in the dmitable, we consider them as not filled */ |
---|
560 | dmi->base_board.filled = false; |
---|
561 | dmi->battery.filled = false; |
---|
562 | dmi->bios.filled = false; |
---|
563 | dmi->chassis.filled = false; |
---|
564 | for (int i = 0; i < MAX_DMI_MEMORY_ITEMS; i++) |
---|
565 | dmi->memory[i].filled = false; |
---|
566 | dmi->processor.filled = false; |
---|
567 | dmi->system.filled = false; |
---|
568 | |
---|
569 | p = (uint8_t *) 0xF0000; /* The start address to look at the dmi table */ |
---|
570 | /* The anchor-string is 16-bytes aligned */ |
---|
571 | for (q = p; q < p + 0x10000; q += 16) { |
---|
572 | /* To validate the presence of SMBIOS: |
---|
573 | * + the overall checksum must be correct |
---|
574 | * + the intermediate anchor-string must be _DMI_ |
---|
575 | * + the intermediate checksum must be correct |
---|
576 | */ |
---|
577 | if (memcmp(q, "_SM_", 4) == 0 && |
---|
578 | checksum(q, q[0x05]) && |
---|
579 | memcmp(q + 0x10, "_DMI_", 5) == 0 && checksum(q + 0x10, 0x0F)) { |
---|
580 | /* Do not return, legacy_decode will need to be called |
---|
581 | * on the intermediate structure to get the table length |
---|
582 | * and address |
---|
583 | */ |
---|
584 | smbios_decode(dmi, q); |
---|
585 | } else if (memcmp(q, "_DMI_", 5) == 0 && checksum(q, 0x0F)) { |
---|
586 | found = 1; |
---|
587 | legacy_decode(dmi, q); |
---|
588 | } |
---|
589 | } |
---|
590 | |
---|
591 | if (found) |
---|
592 | return DMI_TABLE_PRESENT; |
---|
593 | |
---|
594 | dmi->dmitable.base = 0; |
---|
595 | dmi->dmitable.num = 0; |
---|
596 | dmi->dmitable.ver = 0; |
---|
597 | dmi->dmitable.len = 0; |
---|
598 | return -ENODMITABLE; |
---|
599 | } |
---|
600 | |
---|
601 | void dmi_decode(struct dmi_header *h, uint16_t ver, s_dmi * dmi) |
---|
602 | { |
---|
603 | uint8_t *data = h->data; |
---|
604 | |
---|
605 | /* |
---|
606 | * Note: DMI types 37, 38 and 39 are untested |
---|
607 | */ |
---|
608 | switch (h->type) { |
---|
609 | case 0: /* 3.3.1 BIOS Information */ |
---|
610 | if (h->length < 0x12) |
---|
611 | break; |
---|
612 | dmi->bios.filled = true; |
---|
613 | strlcpy(dmi->bios.vendor, dmi_string(h, data[0x04]), |
---|
614 | sizeof(dmi->bios.vendor)); |
---|
615 | strlcpy(dmi->bios.version, dmi_string(h, data[0x05]), |
---|
616 | sizeof(dmi->bios.version)); |
---|
617 | strlcpy(dmi->bios.release_date, dmi_string(h, data[0x08]), |
---|
618 | sizeof(dmi->bios.release_date)); |
---|
619 | dmi->bios.address = WORD(data + 0x06); |
---|
620 | dmi_bios_runtime_size((0x10000 - WORD(data + 0x06)) << 4, dmi); |
---|
621 | dmi->bios.rom_size = (data[0x09] + 1) << 6; |
---|
622 | strlcpy(dmi->bios.rom_size_unit, "kB", sizeof(dmi->bios.rom_size_unit)); |
---|
623 | dmi_bios_characteristics(QWORD(data + 0x0A), dmi); |
---|
624 | |
---|
625 | if (h->length < 0x13) |
---|
626 | break; |
---|
627 | dmi_bios_characteristics_x1(data[0x12], dmi); |
---|
628 | if (h->length < 0x14) |
---|
629 | break; |
---|
630 | dmi_bios_characteristics_x2(data[0x13], dmi); |
---|
631 | if (h->length < 0x18) |
---|
632 | break; |
---|
633 | if (data[0x14] != 0xFF && data[0x15] != 0xFF) |
---|
634 | snprintf(dmi->bios.bios_revision, sizeof(dmi->bios.bios_revision), |
---|
635 | "%u.%u", data[0x14], data[0x15]); |
---|
636 | if (data[0x16] != 0xFF && data[0x17] != 0xFF) |
---|
637 | snprintf(dmi->bios.firmware_revision, |
---|
638 | sizeof(dmi->bios.firmware_revision), "%u.%u", data[0x16], |
---|
639 | data[0x17]); |
---|
640 | break; |
---|
641 | case 1: /* 3.3.2 System Information */ |
---|
642 | if (h->length < 0x08) |
---|
643 | break; |
---|
644 | dmi->system.filled = true; |
---|
645 | strlcpy(dmi->system.manufacturer, dmi_string(h, data[0x04]), |
---|
646 | sizeof(dmi->system.manufacturer)); |
---|
647 | strlcpy(dmi->system.product_name, dmi_string(h, data[0x05]), |
---|
648 | sizeof(dmi->system.product_name)); |
---|
649 | strlcpy(dmi->system.version, dmi_string(h, data[0x06]), |
---|
650 | sizeof(dmi->system.version)); |
---|
651 | strlcpy(dmi->system.serial, dmi_string(h, data[0x07]), |
---|
652 | sizeof(dmi->system.serial)); |
---|
653 | if (h->length < 0x19) |
---|
654 | break; |
---|
655 | dmi_system_uuid(data + 0x08, dmi); |
---|
656 | dmi_system_wake_up_type(data[0x18], dmi); |
---|
657 | if (h->length < 0x1B) |
---|
658 | break; |
---|
659 | strlcpy(dmi->system.sku_number, dmi_string(h, data[0x19]), |
---|
660 | sizeof(dmi->system.sku_number)); |
---|
661 | strlcpy(dmi->system.family, dmi_string(h, data[0x1A]), |
---|
662 | sizeof(dmi->system.family)); |
---|
663 | break; |
---|
664 | |
---|
665 | case 2: /* 3.3.3 Base Board Information */ |
---|
666 | if (h->length < 0x08) |
---|
667 | break; |
---|
668 | dmi->base_board.filled = true; |
---|
669 | strlcpy(dmi->base_board.manufacturer, dmi_string(h, data[0x04]), |
---|
670 | sizeof(dmi->base_board.manufacturer)); |
---|
671 | strlcpy(dmi->base_board.product_name, dmi_string(h, data[0x05]), |
---|
672 | sizeof(dmi->base_board.product_name)); |
---|
673 | strlcpy(dmi->base_board.version, dmi_string(h, data[0x06]), |
---|
674 | sizeof(dmi->base_board.version)); |
---|
675 | strlcpy(dmi->base_board.serial, dmi_string(h, data[0x07]), |
---|
676 | sizeof(dmi->base_board.serial)); |
---|
677 | if (h->length < 0x0F) |
---|
678 | break; |
---|
679 | strlcpy(dmi->base_board.asset_tag, dmi_string(h, data[0x08]), |
---|
680 | sizeof(dmi->base_board.asset_tag)); |
---|
681 | dmi_base_board_features(data[0x09], dmi); |
---|
682 | strlcpy(dmi->base_board.location, dmi_string(h, data[0x0A]), |
---|
683 | sizeof(dmi->base_board.location)); |
---|
684 | dmi_base_board_type(data[0x0D], dmi); |
---|
685 | if (h->length < 0x0F + data[0x0E] * sizeof(uint16_t)) |
---|
686 | break; |
---|
687 | break; |
---|
688 | case 3: /* 3.3.4 Chassis Information */ |
---|
689 | if (h->length < 0x09) |
---|
690 | break; |
---|
691 | dmi->chassis.filled = true; |
---|
692 | strlcpy(dmi->chassis.manufacturer, dmi_string(h, data[0x04]), |
---|
693 | sizeof(dmi->chassis.manufacturer)); |
---|
694 | strlcpy(dmi->chassis.type, dmi_chassis_type(data[0x05] & 0x7F), |
---|
695 | sizeof(dmi->chassis.type)); |
---|
696 | strlcpy(dmi->chassis.lock, dmi_chassis_lock(data[0x05] >> 7), |
---|
697 | sizeof(dmi->chassis.lock)); |
---|
698 | strlcpy(dmi->chassis.version, dmi_string(h, data[0x06]), |
---|
699 | sizeof(dmi->chassis.version)); |
---|
700 | strlcpy(dmi->chassis.serial, dmi_string(h, data[0x07]), |
---|
701 | sizeof(dmi->chassis.serial)); |
---|
702 | strlcpy(dmi->chassis.asset_tag, dmi_string(h, data[0x08]), |
---|
703 | sizeof(dmi->chassis.asset_tag)); |
---|
704 | if (h->length < 0x0D) |
---|
705 | break; |
---|
706 | strlcpy(dmi->chassis.boot_up_state, dmi_chassis_state(data[0x09]), |
---|
707 | sizeof(dmi->chassis.boot_up_state)); |
---|
708 | strlcpy(dmi->chassis.power_supply_state, |
---|
709 | dmi_chassis_state(data[0x0A]), |
---|
710 | sizeof(dmi->chassis.power_supply_state)); |
---|
711 | strlcpy(dmi->chassis.thermal_state, |
---|
712 | dmi_chassis_state(data[0x0B]), |
---|
713 | sizeof(dmi->chassis.thermal_state)); |
---|
714 | strlcpy(dmi->chassis.security_status, |
---|
715 | dmi_chassis_security_status(data[0x0C]), |
---|
716 | sizeof(dmi->chassis.security_status)); |
---|
717 | if (h->length < 0x11) |
---|
718 | break; |
---|
719 | snprintf(dmi->chassis.oem_information, |
---|
720 | sizeof(dmi->chassis.oem_information), "0x%08X", |
---|
721 | DWORD(data + 0x0D)); |
---|
722 | if (h->length < 0x15) |
---|
723 | break; |
---|
724 | dmi->chassis.height = data[0x11]; |
---|
725 | dmi->chassis.nb_power_cords = data[0x12]; |
---|
726 | break; |
---|
727 | case 4: /* 3.3.5 Processor Information */ |
---|
728 | if (h->length < 0x1A) |
---|
729 | break; |
---|
730 | dmi->processor.filled = true; |
---|
731 | strlcpy(dmi->processor.socket_designation, |
---|
732 | dmi_string(h, data[0x04]), |
---|
733 | sizeof(dmi->processor.socket_designation)); |
---|
734 | strlcpy(dmi->processor.type, |
---|
735 | dmi_processor_type(data[0x05]), sizeof(dmi->processor.type)); |
---|
736 | strlcpy(dmi->processor.manufacturer, |
---|
737 | dmi_string(h, data[0x07]), sizeof(dmi->processor.manufacturer)); |
---|
738 | strlcpy(dmi->processor.family, |
---|
739 | dmi_processor_family(data[0x06], |
---|
740 | dmi->processor.manufacturer), |
---|
741 | sizeof(dmi->processor.family)); |
---|
742 | dmi_processor_id(data[0x06], data + 8, dmi_string(h, data[0x10]), dmi); |
---|
743 | strlcpy(dmi->processor.version, |
---|
744 | dmi_string(h, data[0x10]), sizeof(dmi->processor.version)); |
---|
745 | dmi_processor_voltage(data[0x11], dmi); |
---|
746 | dmi->processor.external_clock = WORD(data + 0x12); |
---|
747 | dmi->processor.max_speed = WORD(data + 0x14); |
---|
748 | dmi->processor.current_speed = WORD(data + 0x16); |
---|
749 | if (data[0x18] & (1 << 6)) |
---|
750 | strlcpy(dmi->processor.status, |
---|
751 | dmi_processor_status(data[0x18] & 0x07), |
---|
752 | sizeof(dmi->processor.status)); |
---|
753 | else |
---|
754 | sprintf(dmi->processor.status, "Unpopulated"); |
---|
755 | strlcpy(dmi->processor.upgrade, |
---|
756 | dmi_processor_upgrade(data[0x19]), |
---|
757 | sizeof(dmi->processor.upgrade)); |
---|
758 | if (h->length < 0x20) |
---|
759 | break; |
---|
760 | dmi_processor_cache(WORD(data + 0x1A), "L1", ver, |
---|
761 | dmi->processor.cache1); |
---|
762 | dmi_processor_cache(WORD(data + 0x1C), "L2", ver, |
---|
763 | dmi->processor.cache2); |
---|
764 | dmi_processor_cache(WORD(data + 0x1E), "L3", ver, |
---|
765 | dmi->processor.cache3); |
---|
766 | if (h->length < 0x23) |
---|
767 | break; |
---|
768 | strlcpy(dmi->processor.serial, dmi_string(h, data[0x20]), |
---|
769 | sizeof(dmi->processor.serial)); |
---|
770 | strlcpy(dmi->processor.asset_tag, dmi_string(h, data[0x21]), |
---|
771 | sizeof(dmi->processor.asset_tag)); |
---|
772 | strlcpy(dmi->processor.part_number, dmi_string(h, data[0x22]), |
---|
773 | sizeof(dmi->processor.part_number)); |
---|
774 | dmi->processor.core_count = 0; |
---|
775 | dmi->processor.core_enabled = 0; |
---|
776 | dmi->processor.thread_count = 0; |
---|
777 | if (h->length < 0x28) |
---|
778 | break; |
---|
779 | dmi->processor.core_count = data[0x23]; |
---|
780 | dmi->processor.core_enabled = data[0x24]; |
---|
781 | dmi->processor.thread_count = data[0x25]; |
---|
782 | break; |
---|
783 | case 6: /* 3.3.7 Memory Module Information */ |
---|
784 | if (h->length < 0x0C) |
---|
785 | break; |
---|
786 | dmi->memory_module_count++; |
---|
787 | s_memory_module *module = |
---|
788 | &dmi->memory_module[dmi->memory_module_count - 1]; |
---|
789 | dmi->memory_module[dmi->memory_module_count - 1].filled = true; |
---|
790 | strlcpy(module->socket_designation, dmi_string(h, data[0x04]), |
---|
791 | sizeof(module->socket_designation)); |
---|
792 | dmi_memory_module_connections(data[0x05], module->bank_connections, sizeof(module->bank_connections)); |
---|
793 | dmi_memory_module_speed(data[0x06], module->speed); |
---|
794 | dmi_memory_module_types(WORD(data + 0x07), " ", module->type, sizeof(module->type)); |
---|
795 | dmi_memory_module_size(data[0x09], module->installed_size, sizeof(module->installed_size)); |
---|
796 | dmi_memory_module_size(data[0x0A], module->enabled_size, sizeof(module->enabled_size)); |
---|
797 | dmi_memory_module_error(data[0x0B], "\t\t", module->error_status); |
---|
798 | break; |
---|
799 | case 7: /* 3.3.8 Cache Information */ |
---|
800 | if (h->length < 0x0F) |
---|
801 | break; |
---|
802 | dmi->cache_count++; |
---|
803 | if (dmi->cache_count > MAX_DMI_CACHE_ITEMS) |
---|
804 | break; |
---|
805 | strlcpy(dmi->cache[dmi->cache_count - 1].socket_designation, |
---|
806 | dmi_string(h, data[0x04]), |
---|
807 | sizeof(dmi->cache[dmi->cache_count - 1].socket_designation)); |
---|
808 | snprintf(dmi->cache[dmi->cache_count - 1].configuration, |
---|
809 | sizeof(dmi->cache[dmi->cache_count - 1].configuration), |
---|
810 | "%s, %s, %u", |
---|
811 | WORD(data + 0x05) & 0x0080 ? "Enabled" : "Disabled", |
---|
812 | WORD(data + |
---|
813 | 0x05) & 0x0008 ? "Socketed" : "Not Socketed", |
---|
814 | (WORD(data + 0x05) & 0x0007) + 1); |
---|
815 | strlcpy(dmi->cache[dmi->cache_count - 1].mode, |
---|
816 | dmi_cache_mode((WORD(data + 0x05) >> 8) & 0x0003), |
---|
817 | sizeof(dmi->cache[dmi->cache_count - 1].mode)); |
---|
818 | strlcpy(dmi->cache[dmi->cache_count - 1].location, |
---|
819 | dmi_cache_location((WORD(data + 0x05) >> 5) & 0x0003), |
---|
820 | sizeof(dmi->cache[dmi->cache_count - 1].location)); |
---|
821 | dmi->cache[dmi->cache_count - 1].installed_size = |
---|
822 | dmi_cache_size(WORD(data + 0x09)); |
---|
823 | dmi->cache[dmi->cache_count - 1].max_size = |
---|
824 | dmi_cache_size(WORD(data + 0x07)); |
---|
825 | dmi_cache_types(WORD(data + 0x0B), " ", |
---|
826 | dmi->cache[dmi->cache_count - 1].supported_sram_types); |
---|
827 | dmi_cache_types(WORD(data + 0x0D), " ", |
---|
828 | dmi->cache[dmi->cache_count - 1].installed_sram_types); |
---|
829 | if (h->length < 0x13) |
---|
830 | break; |
---|
831 | dmi->cache[dmi->cache_count - 1].speed = data[0x0F]; /* ns */ |
---|
832 | strlcpy(dmi->cache[dmi->cache_count - 1].error_correction_type, |
---|
833 | dmi_cache_ec_type(data[0x10]), |
---|
834 | sizeof(dmi->cache[dmi->cache_count - 1].error_correction_type)); |
---|
835 | strlcpy(dmi->cache[dmi->cache_count - 1].system_type, |
---|
836 | dmi_cache_type(data[0x11]), |
---|
837 | sizeof(dmi->cache[dmi->cache_count - 1].system_type)); |
---|
838 | strlcpy(dmi->cache[dmi->cache_count - 1].associativity, |
---|
839 | dmi_cache_associativity(data[0x12]), |
---|
840 | sizeof(dmi->cache[dmi->cache_count - 1].associativity)); |
---|
841 | break; |
---|
842 | case 10: /* 3.3.11 On Board Devices Information */ |
---|
843 | dmi_on_board_devices(h, dmi); |
---|
844 | break; |
---|
845 | case 11: /* 3.3.12 OEM Strings */ |
---|
846 | if (h->length < 0x05) |
---|
847 | break; |
---|
848 | dmi_oem_strings(h, "\t", dmi); |
---|
849 | break; |
---|
850 | case 12: /* 3.3.13 System Configuration Options */ |
---|
851 | if (h->length < 0x05) |
---|
852 | break; |
---|
853 | dmi_system_configuration_options(h, "\t", dmi); |
---|
854 | break; |
---|
855 | case 17: /* 3.3.18 Memory Device */ |
---|
856 | if (h->length < 0x15) |
---|
857 | break; |
---|
858 | dmi->memory_count++; |
---|
859 | if (dmi->memory_count > MAX_DMI_MEMORY_ITEMS) |
---|
860 | break; |
---|
861 | s_memory *mem = &dmi->memory[dmi->memory_count - 1]; |
---|
862 | dmi->memory[dmi->memory_count - 1].filled = true; |
---|
863 | dmi_memory_array_error_handle(WORD(data + 0x06), mem->error); |
---|
864 | dmi_memory_device_width(WORD(data + 0x08), mem->total_width); |
---|
865 | dmi_memory_device_width(WORD(data + 0x0A), mem->data_width); |
---|
866 | dmi_memory_device_size(WORD(data + 0x0C), mem->size); |
---|
867 | strlcpy(mem->form_factor, |
---|
868 | dmi_memory_device_form_factor(data[0x0E]), |
---|
869 | sizeof(mem->form_factor)); |
---|
870 | dmi_memory_device_set(data[0x0F], mem->device_set); |
---|
871 | strlcpy(mem->device_locator, dmi_string(h, data[0x10]), |
---|
872 | sizeof(mem->device_locator)); |
---|
873 | strlcpy(mem->bank_locator, dmi_string(h, data[0x11]), |
---|
874 | sizeof(mem->bank_locator)); |
---|
875 | strlcpy(mem->type, dmi_memory_device_type(data[0x12]), |
---|
876 | sizeof(mem->type)); |
---|
877 | dmi_memory_device_type_detail(WORD(data + 0x13), mem->type_detail, sizeof(mem->type_detail)); |
---|
878 | if (h->length < 0x17) |
---|
879 | break; |
---|
880 | dmi_memory_device_speed(WORD(data + 0x15), mem->speed); |
---|
881 | if (h->length < 0x1B) |
---|
882 | break; |
---|
883 | strlcpy(mem->manufacturer, dmi_string(h, data[0x17]), |
---|
884 | sizeof(mem->manufacturer)); |
---|
885 | strlcpy(mem->serial, dmi_string(h, data[0x18]), sizeof(mem->serial)); |
---|
886 | strlcpy(mem->asset_tag, dmi_string(h, data[0x19]), |
---|
887 | sizeof(mem->asset_tag)); |
---|
888 | strlcpy(mem->part_number, dmi_string(h, data[0x1A]), |
---|
889 | sizeof(mem->part_number)); |
---|
890 | break; |
---|
891 | case 22: /* 3.3.23 Portable Battery */ |
---|
892 | if (h->length < 0x10) |
---|
893 | break; |
---|
894 | dmi->battery.filled = true; |
---|
895 | strlcpy(dmi->battery.location, dmi_string(h, data[0x04]), |
---|
896 | sizeof(dmi->battery.location)); |
---|
897 | strlcpy(dmi->battery.manufacturer, dmi_string(h, data[0x05]), |
---|
898 | sizeof(dmi->battery.manufacturer)); |
---|
899 | if (data[0x06] || h->length < 0x1A) |
---|
900 | strlcpy(dmi->battery.manufacture_date, |
---|
901 | dmi_string(h, data[0x06]), |
---|
902 | sizeof(dmi->battery.manufacture_date)); |
---|
903 | if (data[0x07] || h->length < 0x1A) |
---|
904 | strlcpy(dmi->battery.serial, dmi_string(h, data[0x07]), |
---|
905 | sizeof(dmi->battery.serial)); |
---|
906 | strlcpy(dmi->battery.name, dmi_string(h, data[0x08]), |
---|
907 | sizeof(dmi->battery.name)); |
---|
908 | if (data[0x09] != 0x02 || h->length < 0x1A) |
---|
909 | strlcpy(dmi->battery.chemistry, |
---|
910 | dmi_battery_chemistry(data[0x09]), |
---|
911 | sizeof(dmi->battery.chemistry)); |
---|
912 | if (h->length < 0x1A) |
---|
913 | dmi_battery_capacity(WORD(data + 0x0A), 1, |
---|
914 | dmi->battery.design_capacity); |
---|
915 | else |
---|
916 | dmi_battery_capacity(WORD(data + 0x0A), data[0x15], |
---|
917 | dmi->battery.design_capacity); |
---|
918 | dmi_battery_voltage(WORD(data + 0x0C), dmi->battery.design_voltage); |
---|
919 | strlcpy(dmi->battery.sbds, dmi_string(h, data[0x0E]), |
---|
920 | sizeof(dmi->battery.sbds)); |
---|
921 | dmi_battery_maximum_error(data[0x0F], dmi->battery.maximum_error); |
---|
922 | if (h->length < 0x1A) |
---|
923 | break; |
---|
924 | if (data[0x07] == 0) |
---|
925 | sprintf(dmi->battery.sbds_serial, "%04X", WORD(data + 0x10)); |
---|
926 | if (data[0x06] == 0) |
---|
927 | sprintf(dmi->battery.sbds_manufacture_date, "%u-%02u-%02u", |
---|
928 | 1980 + (WORD(data + 0x12) >> 9), |
---|
929 | (WORD(data + 0x12) >> 5) & 0x0F, WORD(data + 0x12) & 0x1F); |
---|
930 | if (data[0x09] == 0x02) |
---|
931 | strlcpy(dmi->battery.sbds_chemistry, dmi_string(h, data[0x14]), |
---|
932 | sizeof(dmi->battery.sbds_chemistry)); |
---|
933 | // sprintf(dmi->battery.oem_info,"0x%08X",DWORD(h, data+0x16)); |
---|
934 | break; |
---|
935 | case 23: /* 3.3.24 System Reset */ |
---|
936 | if (h->length < 0x0D) |
---|
937 | break; |
---|
938 | dmi->system.system_reset.filled = true; |
---|
939 | dmi->system.system_reset.status = data[0x04] & (1 << 0); |
---|
940 | dmi->system.system_reset.watchdog = data[0x04] & (1 << 5); |
---|
941 | if (!(data[0x04] & (1 << 5))) |
---|
942 | break; |
---|
943 | strlcpy(dmi->system.system_reset.boot_option, |
---|
944 | dmi_system_reset_boot_option((data[0x04] >> 1) & 0x3), |
---|
945 | sizeof dmi->system.system_reset.boot_option); |
---|
946 | strlcpy(dmi->system.system_reset.boot_option_on_limit, |
---|
947 | dmi_system_reset_boot_option((data[0x04] >> 3) & 0x3), |
---|
948 | sizeof dmi->system.system_reset.boot_option_on_limit); |
---|
949 | dmi_system_reset_count(WORD(data + 0x05), |
---|
950 | dmi->system.system_reset.reset_count); |
---|
951 | dmi_system_reset_count(WORD(data + 0x07), |
---|
952 | dmi->system.system_reset.reset_limit); |
---|
953 | dmi_system_reset_timer(WORD(data + 0x09), |
---|
954 | dmi->system.system_reset.timer_interval); |
---|
955 | dmi_system_reset_timer(WORD(data + 0x0B), |
---|
956 | dmi->system.system_reset.timeout); |
---|
957 | break; |
---|
958 | case 24: /* 3.3.25 Hardware Security */ |
---|
959 | if (h->length < 0x05) |
---|
960 | break; |
---|
961 | dmi->hardware_security.filled = true; |
---|
962 | strlcpy(dmi->hardware_security.power_on_passwd_status, |
---|
963 | dmi_hardware_security_status(data[0x04] >> 6), |
---|
964 | sizeof dmi->hardware_security.power_on_passwd_status); |
---|
965 | strlcpy(dmi->hardware_security.keyboard_passwd_status, |
---|
966 | dmi_hardware_security_status((data[0x04] >> 4) & 0x3), |
---|
967 | sizeof dmi->hardware_security.keyboard_passwd_status); |
---|
968 | strlcpy(dmi->hardware_security.administrator_passwd_status, |
---|
969 | dmi_hardware_security_status((data[0x04] >> 2) & 0x3), |
---|
970 | sizeof dmi->hardware_security.administrator_passwd_status); |
---|
971 | strlcpy(dmi->hardware_security.front_panel_reset_status, |
---|
972 | dmi_hardware_security_status(data[0x04] & 0x3), |
---|
973 | sizeof dmi->hardware_security.front_panel_reset_status); |
---|
974 | break; |
---|
975 | case 32: /* 3.3.33 System Boot Information */ |
---|
976 | if (h->length < 0x0B) |
---|
977 | break; |
---|
978 | dmi_system_boot_status(data[0x0A], dmi->system.system_boot_status); |
---|
979 | case 38: /* 3.3.39 IPMI Device Information */ |
---|
980 | if (h->length < 0x10) |
---|
981 | break; |
---|
982 | dmi->ipmi.filled = true; |
---|
983 | snprintf(dmi->ipmi.interface_type, |
---|
984 | sizeof(dmi->ipmi.interface_type), "%s", |
---|
985 | dmi_ipmi_interface_type(data[0x04])); |
---|
986 | dmi->ipmi.major_specification_version = data[0x05] >> 4; |
---|
987 | dmi->ipmi.minor_specification_version = data[0x05] & 0x0F; |
---|
988 | dmi->ipmi.I2C_slave_address = data[0x06] >> 1; |
---|
989 | if (data[0x07] != 0xFF) |
---|
990 | dmi->ipmi.nv_address = data[0x07]; |
---|
991 | else |
---|
992 | dmi->ipmi.nv_address = 0; /* Not Present */ |
---|
993 | dmi_ipmi_base_address(data[0x04], data + 0x08, &dmi->ipmi); |
---|
994 | if (h->length < 0x12) |
---|
995 | break; |
---|
996 | if (data[0x11] != 0x00) { |
---|
997 | dmi->ipmi.irq = data[0x11]; |
---|
998 | } |
---|
999 | break; |
---|
1000 | } |
---|
1001 | } |
---|
1002 | |
---|
1003 | void parse_dmitable(s_dmi * dmi) |
---|
1004 | { |
---|
1005 | int i = 0; |
---|
1006 | uint8_t *data = NULL; |
---|
1007 | uint8_t buf[dmi->dmitable.len]; |
---|
1008 | memcpy(buf, (int *)dmi->dmitable.base, sizeof(uint8_t) * dmi->dmitable.len); |
---|
1009 | data = buf; |
---|
1010 | dmi->memory_count = 0; |
---|
1011 | while (i < dmi->dmitable.num && data + 4 <= buf + dmi->dmitable.len) { /* 4 is the length of an SMBIOS structure header */ |
---|
1012 | uint8_t *next; |
---|
1013 | struct dmi_header h; |
---|
1014 | to_dmi_header(&h, data); |
---|
1015 | /* |
---|
1016 | * If a short entry is found (less than 4 bytes), not only it |
---|
1017 | * is invalid, but we cannot reliably locate the next entry. |
---|
1018 | * Better stop at this point, and let the user know his/her |
---|
1019 | * table is broken. |
---|
1020 | */ |
---|
1021 | if (h.length < 4) { |
---|
1022 | printf |
---|
1023 | ("Invalid entry length (%u). DMI table is broken! Stop.\n\n", |
---|
1024 | (unsigned int)h.length); |
---|
1025 | break; |
---|
1026 | } |
---|
1027 | |
---|
1028 | /* loo for the next handle */ |
---|
1029 | next = data + h.length; |
---|
1030 | while (next - buf + 1 < dmi->dmitable.len |
---|
1031 | && (next[0] != 0 || next[1] != 0)) |
---|
1032 | next++; |
---|
1033 | next += 2; |
---|
1034 | if (next - buf <= dmi->dmitable.len) { |
---|
1035 | dmi_decode(&h, dmi->dmitable.ver, dmi); |
---|
1036 | } |
---|
1037 | data = next; |
---|
1038 | i++; |
---|
1039 | } |
---|
1040 | } |
---|