/* Simple program for dumping DMI/SMBIOS data * Based on code from python-dmidecode/dmidecode.c * * Copyright 2009 David Sommerseth * Copyright 2002-2008 Jean Delvare * Copyright 2000-2002 Alan Cox * * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * For the avoidance of doubt the "preferred form" of this code is one which * is in an open unpatent encumbered format. Where cryptographic key signing * forms part of the process of creating an executable the information * including keys needed to generate an equivalently functional executable * are deemed to be part of the source code. */ #include #include #include #include "types.h" #include "util.h" #include "dmidump.h" #include "efi.h" /* * Build a crafted entry point with table address hard-coded to 32, * as this is where we will put it in the output file. We adjust the * DMI checksum appropriately. The SMBIOS checksum needs no adjustment. */ static void overwrite_dmi_address(u8 * buf) { buf[0x05] += buf[0x08] + buf[0x09] + buf[0x0A] + buf[0x0B] - 32; buf[0x08] = 32; buf[0x09] = 0; buf[0x0A] = 0; buf[0x0B] = 0; } /* Same thing for SMBIOS3 entry points */ static void overwrite_smbios3_address(u8 *buf) { buf[0x05] += buf[0x10] + buf[0x11] + buf[0x12] + buf[0x13] + buf[0x14] + buf[0x15] + buf[0x16] + buf[0x17] - 32; buf[0x10] = 32; buf[0x11] = 0; buf[0x12] = 0; buf[0x13] = 0; buf[0x14] = 0; buf[0x15] = 0; buf[0x16] = 0; buf[0x17] = 0; } void dmi_table_dump(const u8 *buf, u32 len, const char *dumpfile) { write_dump(32, len, buf, dumpfile, 0); } void dmi_table(off_t base, u32 len, u16 num, u32 ver, const char *devmem, u32 flags, const char *dumpfile) { u8 *buf; size_t size = len; buf = read_file(NULL, flags & FLAG_NO_FILE_OFFSET ? 0 : base, &size, devmem); len = size; if (buf == NULL) { printf("read failed\n"); } dmi_table_dump(buf, len, dumpfile); free(buf); } static int smbios3_decode(u8 *buf, const char *devmem, u32 flags, const char *dumpfile) { u32 ver; u64 offset; offset = QWORD(buf + 0x10); ver = (buf[0x07] << 16) + (buf[0x08] << 8) + buf[0x09]; if (!checksum(buf, buf[0x06])) return 0; dmi_table(((off_t)offset.h << 32) | offset.l,DWORD(buf + 0x0C), 0, ver, devmem, flags | FLAG_STOP_AT_EOT, dumpfile); u8 crafted[32]; memcpy(crafted, buf, 32); overwrite_smbios3_address(crafted); //overwrite_dmi_address(crafted); //printf("Writing %d bytes to %s.",crafted[0x06], dumpfile); write_dump(0, crafted[0x06], crafted, dumpfile, 1); return 1; } static int smbios_decode(u8 *buf, const char *devmem, u32 flags, const char *dumpfile) { u16 ver; if (!checksum(buf, buf[0x05]) || memcmp(buf + 0x10, "_DMI_", 5) != 0 || !checksum(buf + 0x10, 0x0F)) return 0; ver = (buf[0x06] << 8) + buf[0x07]; switch (ver) { case 0x021F: case 0x0221: ver = 0x0203; break; case 0x0233: ver = 0x0206; break; } dmi_table(DWORD(buf + 0x18), WORD(buf + 0x16), WORD(buf + 0x1C), ver << 8, devmem, flags, dumpfile); u8 crafted[32]; memcpy(crafted, buf, 32); overwrite_dmi_address(crafted + 0x10); write_dump(0, crafted[0x05], crafted, dumpfile, 1); return 1; } static int legacy_decode(u8 *buf, const char *devmem, u32 flags, const char *dumpfile) { u8 crafted[16]; //dmi_table(); dmi_table(DWORD(buf + 0x08), WORD(buf + 0x06), WORD(buf + 0x0C), ((buf[0x0E] & 0xF0) << 12) + ((buf[0x0E] & 0x0F) << 8), devmem, flags, dumpfile); memcpy(crafted, buf, 16); overwrite_smbios3_address(crafted); write_dump(0, 0x0F, crafted, dumpfile, 1); return 1; } int dump(const char *memdev, const char *dumpfile) { /* On success, return found, otherwise return 0 */ int ret = 0; int found = 0; size_t fp; int efi; u8 *buf; size_t size; /* * First try reading from sysfs tables. The entry point file could * contain one of several types of entry points, so read enough for * the largest one, then determine what type it contains. */ size = 0x20; if ( (buf = read_file(NULL, 0, &size, SYS_ENTRY_FILE)) != NULL){ if (size >= 24 && memcmp(buf, "_SM3_", 5) == 0){ if (smbios3_decode(buf, SYS_TABLE_FILE, FLAG_NO_FILE_OFFSET, dumpfile)) found++; } else if (size >= 31 && memcmp(buf, "_SM_", 4) == 0) { if (smbios_decode(buf, SYS_TABLE_FILE, FLAG_NO_FILE_OFFSET, dumpfile)) found++; } else if (size >= 15 && memcmp(buf, "_DMI_", 5) == 0){ if (legacy_decode(buf, SYS_TABLE_FILE, FLAG_NO_FILE_OFFSET, dumpfile)) found++; } if (found){ ret = 1; goto exit_free; } } /* First try EFI (ia64, Intel-based Mac) */ efi = address_from_efi(NULL, &fp); switch(efi) { case EFI_NOT_FOUND: goto memory_scan; case EFI_NO_SMBIOS: ret = 1; goto exit_free; } if ((buf = mem_chunk(NULL, fp, 0x20, memdev )) == NULL){ ret = 1; goto exit_free; } if (memcmp(buf, "_SM3_", 5) == 0){ if(smbios3_decode(buf, memdev, 0, dumpfile)) found++; } else if (memcmp(buf, "_SM_", 4) == 0){ if(smbios_decode(buf, memdev, 0, dumpfile)) found++; } goto done; memory_scan: #if defined __i386__ || defined __x86_64__ /* Fallback to memory scan (x86, x86_64) */ if((buf = mem_chunk(NULL, 0xF0000, 0x10000, memdev)) == NULL) { ret = 1; goto exit_free; } /* Look for a 64-bit entry point first */ for(fp = 0; fp <= 0xFFF0; fp += 16){ if(memcmp(buf + fp, "_SM3_", 5) == 0 && fp <= 0xFFE0){ if(smbios3_decode(buf + fp, memdev, 0, dumpfile)){ found++; goto done; } } } /* If none found, look for a 32-bit entry point */ for(fp = 0; fp <= 0xFFF0; fp += 16) { if(memcmp(buf + fp, "_SM_", 4) == 0 && fp <= 0xFFE0) { if(smbios_decode(buf + fp, memdev, 0, dumpfile)){ found++; goto done; } } else if (memcmp(buf+fp, "_DMI_", 5) == 0){ if(legacy_decode(buf+fp, memdev, 0, dumpfile)){ found++; goto done; } } } #endif done: if(!found){ printf("No SMBIOS nor DMI entry point found, sorry.\n"); } free(buf); exit_free: if (!found) free(buf); return ret; } #ifdef _DMIDUMP_MAIN_ int main(int argc, char **argv) { if( argc != 3 ) { fprintf(stderr, "Usage: %s \n", argv[0]); return 1; } dump(argv[1], argv[2]); return 0; } #endif