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 } 1041