From aef6454e2c916a705539bbc551f0ff6aa3f31987 Mon Sep 17 00:00:00 2001 From: Huzz Date: Sat, 3 Sep 2022 20:03:27 +0800 Subject: [PATCH 01/27] Fix reading info permission deny bugs. Details: 1. Change default /dev/mem to sysfs tables, if /dev/mem is unavailable, use sysfs tables instead. 2. Modify init method from dmidecodemodule. 3. Add read_file function instead memchunk. 4. Add SM3 reading function and get version function. 5. Test physical machine and KVM machine Resolves: https://github.com/nima/python-dmidecode/pull/39 Signed-off-by: Huzz --- src/dmidecode.c | 117 ++++++++++---- src/dmidecode.h | 13 +- src/dmidecodemodule.c | 367 ++++++++++++++++++++++++++++++------------ src/dmidecodemodule.h | 6 +- src/dmidump.c | 272 +++++++++++++++++++------------ src/dmidump.h | 7 + src/util.c | 166 +++++++++++++++++-- src/util.h | 1 + 8 files changed, 703 insertions(+), 246 deletions(-) diff --git a/src/dmidecode.c b/src/dmidecode.c index d30a5d3..19958d3 100644 --- a/src/dmidecode.c +++ b/src/dmidecode.c @@ -5197,7 +5197,7 @@ dmi_codes_major *find_dmiMajor(const struct dmi_header *h) return NULL; } -static void dmi_table(Log_t *logp, int type, u32 base, u16 len, u16 num, u16 ver, const char *devmem, xmlNode *xmlnode) +static void dmi_table(Log_t *logp, int type, u32 base, u16 len, u16 num, u16 ver, const char *devmem, u32 flags, xmlNode *xmlnode) { static u8 version_added = 0; u8 *buf; @@ -5221,35 +5221,40 @@ static void dmi_table(Log_t *logp, int type, u32 base, u16 len, u16 num, u16 ver info_n = NULL; } - if((buf = mem_chunk(logp, base, len, devmem)) == NULL) { - log_append(logp, LOGFL_NODUPS, LOG_WARNING, "Table is unreachable, sorry." -#ifndef USE_MMAP - "Try compiling dmidecode with -DUSE_MMAP." -#endif - ); - return; - } + if(flags & FLAG_NO_FILE_OFFSET){ + /* + * When reading from sysfs or from a dump file, the file may be + * shorter than announced. For SMBIOS v3 this is expcted, as we + * only know the maximum table size, not the actual table size. + * For older implementations (and for SMBIOS v3 too), this + * would be the result of the kernel truncating the table on + * parse error. + */ + size_t size = len; + buf = read_file(logp, flags & FLAG_NO_FILE_OFFSET ? 0 : base, &size, devmem); + if (num && size != (size_t)len){ + log_append(logp, LOGFL_NODUPS, LOG_WARNING, "Wrong DMI structures length: %i bytes announced, only %lu bytes available.\n", len, (unsigned long)size ); + } + len = size; + } else { + buf = mem_chunk(logp, base, len, devmem); + } + + if (ver > SUPPORTED_SMBIOS_VER){ + log_append(logp, LOGFL_NODUPS, LOG_WARNING, "# SMBIOS implementations newer than version %u.%u are not\n", "# fully supported by this version of dmidecode.\n", SUPPORTED_SMBIOS_VER >> 8, SUPPORTED_SMBIOS_VER & 0xFF); + } - if (ver > SUPPORTED_SMBIOS_VER) { - log_append(logp, LOGFL_NODUPS, LOG_WARNING, - "# SMBIOS implementations newer than version %u.%u are not\n" - "# fully supported by this version of dmidecode.\n", - SUPPORTED_SMBIOS_VER >> 8, SUPPORTED_SMBIOS_VER & 0xFF); - } - // FIXME: This is hackerish ... rather try to avoid looping dmi_table() calls too much if( version_added == 0 ) { dmixml_AddAttribute(xmlnode, "smbios_version", "%u.%u", ver >> 8, ver & 0xFF); version_added = 1; } - data = buf; - while(i < num && data + 4 <= buf + len) { /* 4 is the length of an SMBIOS structure header */ - + data = buf; + while(i < num && data + 4 <= buf + len) { /* 4 is the length of an SMBIOS structure header */ u8 *next; struct dmi_header h; to_dmi_header(&h, data); - /* ** If a short entry is found (less than 4 bytes), not only it ** is invalid, but we cannot reliably locate the next entry. @@ -5258,8 +5263,8 @@ static void dmi_table(Log_t *logp, int type, u32 base, u16 len, u16 num, u16 ver */ if(h.length < 4) { log_append(logp, LOGFL_NORMAL, LOG_WARNING, - "Invalid entry length (%i) for type %i. DMI table is broken! Stop.", - (unsigned int)h.length, type); + "Invalid entry length (%i) for type %i. DMI table is broken! Stop.", + (unsigned int)h.length, type); break; } @@ -5278,7 +5283,6 @@ static void dmi_table(Log_t *logp, int type, u32 base, u16 len, u16 num, u16 ver next++; } next += 2; - xmlNode *handle_n = NULL; if( h.type == type ) { if(next - buf <= len) { @@ -5309,6 +5313,7 @@ static void dmi_table(Log_t *logp, int type, u32 base, u16 len, u16 num, u16 ver dmixml_AddAttribute(handle_n, "length", "%i", (next - buf)); dmixml_AddAttribute(handle_n, "expected_length", "%i", len); + log_append(logp, LOGFL_NODUPS, LOG_WARNING, "DMI/SMBIOS type 0x%02X is exceeding the expected buffer " "size by %i bytes. Will not decode this entry.", @@ -5344,6 +5349,60 @@ static void dmi_table(Log_t *logp, int type, u32 base, u16 len, u16 num, u16 ver free(buf); } +int _smbios3_decode_check(u8 *buf){ + int check = (!checksum(buf, buf[0x06])) ? 0 : 1; + return check; +} + +xmlNode *smbios3_decode_get_version(u8 * buf, const char *devmem) +{ + int check = _smbios3_decode_check(buf); + + xmlNode *data_n = xmlNewNode(NULL, (xmlChar *) "DMIversion"); + assert( data_n != NULL ); + + dmixml_AddAttribute(data_n, "type", "SMBIOS"); + + if(check == 1) { + u16 ver = (buf[0x07] << 16) + (buf[0x08] << 8) + buf[0x09]; + + dmixml_AddTextContent(data_n, "SMBIOS %i.%i.%i present", buf[0x07], buf[0x08], buf[0x09]); + dmixml_AddAttribute(data_n, "version", "%i.%i.%i", buf[0x07], buf[0x08],buf[0x09]); + } else if(check == 0) { + dmixml_AddTextContent(data_n, "No SMBIOS nor DMI entry point found"); + dmixml_AddAttribute(data_n, "unknown", "1"); + } + return data_n; +} + +int smbios3_decode(Log_t *logp, int type, u8 *buf, const char *devmem, u32 flags, xmlNode *xmlnode) +{ + u32 ver; + u64 offset; + + /* Don't let checksum run beyond the buffer */ + if (buf[0x06] > 0x20) + { + return 0; + } + + int check = _smbios3_decode_check(buf); + if (check == 1) + { + ver = (buf[0x07] << 16) + (buf[0x08] << 8) + buf[0x09]; + offset = QWORD(buf + 0x10); + + if (!(flags & FLAG_NO_FILE_OFFSET) && offset.h && sizeof(off_t) < 8) + { + return 0; + } + + dmi_table(logp, type, ((off_t)offset.h << 32) | offset.l, DWORD(buf+0x0C), 0, ver, devmem, flags | FLAG_STOP_AT_EOT, xmlnode); + } + + return check; +} + int _smbios_decode_check(u8 * buf) { int check = (!checksum(buf, buf[0x05]) || memcmp(buf + 0x10, "_DMI_", 5) != 0 || @@ -5370,7 +5429,8 @@ xmlNode *smbios_decode_get_version(u8 * buf, const char *devmem) _M = 0; switch (ver) { case 0x021F: - _m = 31; + case 0x0221: + _m = ver & 0xFF; _M = 3; ver = 0x0203; break; @@ -5396,7 +5456,7 @@ xmlNode *smbios_decode_get_version(u8 * buf, const char *devmem) return data_n; } -int smbios_decode(Log_t *logp, int type, u8 *buf, const char *devmem, xmlNode *xmlnode) +int smbios_decode(Log_t *logp, int type, u8 *buf, const char *devmem, u32 flags, xmlNode *xmlnode) { int check = _smbios_decode_check(buf); @@ -5405,6 +5465,7 @@ int smbios_decode(Log_t *logp, int type, u8 *buf, const char *devmem, xmlNode *x switch (ver) { case 0x021F: + case 0x0221: ver = 0x0203; break; case 0x0233: @@ -5413,7 +5474,7 @@ int smbios_decode(Log_t *logp, int type, u8 *buf, const char *devmem, xmlNode *x } // printf(">>%d @ %d, %d<<\n", DWORD(buf+0x18), WORD(buf+0x16), WORD(buf+0x1C)); dmi_table(logp, type, DWORD(buf + 0x18), WORD(buf + 0x16), WORD(buf + 0x1C), ver, devmem, - xmlnode); + flags, xmlnode); } return check; } @@ -5451,13 +5512,13 @@ xmlNode *legacy_decode_get_version(u8 * buf, const char *devmem) return data_n; } -int legacy_decode(Log_t *logp, int type, u8 *buf, const char *devmem, xmlNode *xmlnode) +int legacy_decode(Log_t *logp, int type, u8 *buf, const char *devmem, u32 flags, xmlNode *xmlnode) { int check = _legacy_decode_check(buf); if(check == 1) dmi_table(logp, type, DWORD(buf + 0x08), WORD(buf + 0x06), WORD(buf + 0x0C), - ((buf[0x0E] & 0xF0) << 4) + (buf[0x0E] & 0x0F), devmem, xmlnode); + ((buf[0x0E] & 0xF0) << 4) + (buf[0x0E] & 0x0F), devmem, flags, xmlnode); return check; } diff --git a/src/dmidecode.h b/src/dmidecode.h index 926bd5d..22d70e1 100644 --- a/src/dmidecode.h +++ b/src/dmidecode.h @@ -23,6 +23,13 @@ #include "dmihelper.h" #include "dmierror.h" +#define FLAG_NO_FILE_OFFSET (1 << 0) +#define FLAG_STOP_AT_EOT (1 << 1) + +#define SYS_FIRMWARE_DIR "/sys/firmware/dmi/tables" +#define SYS_ENTRY_FILE SYS_FIRMWARE_DIR "/smbios_entry_point" +#define SYS_TABLE_FILE SYS_FIRMWARE_DIR "/DMI" + struct dmi_header { u8 type; u8 length; @@ -34,10 +41,12 @@ void dmi_dump(xmlNode *node, struct dmi_header * h); xmlNode *dmi_decode(xmlNode *parent_n, dmi_codes_major *dmiMajor, struct dmi_header * h, u16 ver); void to_dmi_header(struct dmi_header *h, u8 * data); +xmlNode *smbios3_decode_get_version(u8 * buf, const char *devmem); xmlNode *smbios_decode_get_version(u8 * buf, const char *devmem); xmlNode *legacy_decode_get_version(u8 * buf, const char *devmem); -int smbios_decode(Log_t *logp, int type, u8 *buf, const char *devmem, xmlNode *xmlnode); -int legacy_decode(Log_t *logp, int type, u8 *buf, const char *devmem, xmlNode *xmlnode); +int smbios3_decode(Log_t *logp, int type, u8 *buf, const char *devmem, u32 flags, xmlNode *xmlnode); +int smbios_decode(Log_t *logp, int type, u8 *buf, const char *devmem, u32 flags, xmlNode *xmlnode); +int legacy_decode(Log_t *logp, int type, u8 *buf, const char *devmem, u32 flags, xmlNode *xmlnode); const char *dmi_string(const struct dmi_header *dm, u8 s); void dmi_system_uuid(xmlNode *node, const u8 * p, u16 ver); diff --git a/src/dmidecodemodule.c b/src/dmidecodemodule.c index 44ef7aa..d3ac7ff 100644 --- a/src/dmidecodemodule.c +++ b/src/dmidecodemodule.c @@ -66,7 +66,9 @@ char *PyUnicode_AsUTF8(PyObject *unicode) { static void init(options *opt) { - opt->devmem = DEFAULT_MEM_DEV; + int efi; + size_t fp; + opt->dumpfile = NULL; opt->flags = 0; opt->type = -1; @@ -75,6 +77,13 @@ static void init(options *opt) opt->python_xml_map = strdup(PYTHON_XML_MAP); opt->logdata = log_init(); + efi = address_from_efi(opt->logdata, &fp); + if(efi == EFI_NOT_FOUND){ + opt->devmem = DEFAULT_MEM_DEV; + } else { + opt->devmem = SYS_TABLE_FILE; + } + /* sanity check */ if(sizeof(u8) != 1 || sizeof(u16) != 2 || sizeof(u32) != 4 || '\0' != 0) { log_append(opt->logdata, LOGFL_NORMAL, LOG_WARNING, @@ -116,70 +125,149 @@ xmlNode *dmidecode_get_version(options *opt) int efi; u8 *buf = NULL; xmlNode *ver_n = NULL; + size_t size; - /* Set default option values */ + /* + * First, if devmem is available, set default as DEFAULT_MEM_DEV + * Set default option values + */ if( opt->devmem == NULL ) { - opt->devmem = DEFAULT_MEM_DEV; + efi = address_from_efi(opt->logdata, &fp); + if(efi == EFI_NOT_FOUND){ + opt->devmem = DEFAULT_MEM_DEV; + } else { + opt->devmem = SYS_TABLE_FILE; + } } /* Read from dump if so instructed */ if(opt->dumpfile != NULL) { //. printf("Reading SMBIOS/DMI data from file %s.\n", dumpfile); if((buf = mem_chunk(opt->logdata, 0, 0x20, opt->dumpfile)) != NULL) { - if(memcmp(buf, "_SM_", 4) == 0) { - ver_n = smbios_decode_get_version(buf, opt->dumpfile); - if( dmixml_GetAttrValue(ver_n, "unknown") == NULL ) { - found++; - } - } else if(memcmp(buf, "_DMI_", 5) == 0) { - ver_n = legacy_decode_get_version(buf, opt->dumpfile); - if( dmixml_GetAttrValue(ver_n, "unknown") == NULL ) { - found++; - } - } - } - } else { /* Read from /dev/mem */ - /* First try EFI (ia64, Intel-based Mac) */ - efi = address_from_efi(opt->logdata, &fp); - if(efi == EFI_NOT_FOUND) { - /* Fallback to memory scan (x86, x86_64) */ - if((buf = mem_chunk(opt->logdata, 0xF0000, 0x10000, opt->devmem)) != NULL) { - for(fp = 0; fp <= 0xFFF0; fp += 16) { - if(memcmp(buf + fp, "_SM_", 4) == 0 && fp <= 0xFFE0) { - ver_n = smbios_decode_get_version(buf + fp, opt->devmem); - if( dmixml_GetAttrValue(ver_n, "unknown") == NULL ) { - found++; - } - fp += 16; - } else if(memcmp(buf + fp, "_DMI_", 5) == 0) { - ver_n = legacy_decode_get_version (buf + fp, opt->devmem); - if( dmixml_GetAttrValue(ver_n, "unknown") == NULL ) { - found++; - } - } - } - } - } else if(efi == EFI_NO_SMBIOS) { - ver_n = NULL; - } else { - // Process as EFI - if((buf = mem_chunk(opt->logdata, fp, 0x20, opt->devmem)) != NULL) { - ver_n = smbios_decode_get_version(buf, opt->devmem); - if( dmixml_GetAttrValue(ver_n, "unknown") == NULL ) { - found++; - } - //. TODO: dmixml_AddAttribute(dmixml_n, "efi_address", efiAddress); - } + ver_n = NULL; + goto exit_free; + } + if(memcmp(buf, "_SM3_", 5) == 0){ + ver_n = smbios3_decode_get_version(buf, opt->dumpfile); + if ( dmixml_GetAttrValue(ver_n, "unknown") == NULL ) + found++; + } else if(memcmp(buf, "_SM_", 4) == 0) { + ver_n = smbios_decode_get_version(buf, opt->dumpfile); + if( dmixml_GetAttrValue(ver_n, "unknown") == NULL ) + found++; + } else if(memcmp(buf, "_DMI_", 5) == 0) { + ver_n = legacy_decode_get_version(buf, opt->dumpfile); + if( dmixml_GetAttrValue(ver_n, "unknown") == NULL ) + found++; } } - if( buf != NULL ) { - free(buf); - } - if( !found ) { + + /* + * 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(opt->logdata, 0, &size, SYS_ENTRY_FILE)) != NULL ){ + if(size >= 24 && memcmp(buf, "_SM3_", 5) == 0){ + ver_n = smbios3_decode_get_version(buf, opt->devmem); + if (dmixml_GetAttrValue(ver_n, "unknown") == NULL) + found++; + } else if (size >= 31 && memcmp(buf, "_SM_", 4) == 0 ){ + ver_n = smbios_decode_get_version(buf, opt->devmem); + if (dmixml_GetAttrValue(ver_n, "unknown") == NULL) + found++; + } else if (size >= 15 && memcmp(buf, "_DMI_", 5) == 0){ + ver_n = legacy_decode_get_version (buf, opt->devmem); + if (dmixml_GetAttrValue(ver_n, "unknown") == NULL) + found++; + } + + if(found) + goto done; + } else { + ver_n = NULL; + goto exit_free; + } + + /* Read from /dev/mem */ + /* Next try EFI (ia64, Intel-based Mac) */ + efi = address_from_efi(opt->logdata, &fp); + switch(efi){ + case EFI_NOT_FOUND: + goto memory_scan; + case EFI_NO_SMBIOS: + ver_n = NULL; + goto exit_free; + } + + if(buf = mem_chunk(opt->logdata, fp, 0x20, opt->devmem) == NULL){ + ver_n = NULL; + goto exit_free; + } + + if(memcmp(buf, "_SM3_", 5) == 0){ + ver_n = smbios3_decode_get_version(buf, opt->devmem); + if(dmixml_GetAttrValue(ver_n, "unknown") == NULL) + found++; + } else if (memcmp(buf, "_SM_", 4) == 0 ) { + ver_n = smbios_decode_get_version(buf, opt->devmem); + if(dmixml_GetAttrValue(ver_n, "unknown") == NULL) + found++; + } + + goto done; + +memory_scan: +#if defined __i386__ || defined __x86_64__ + /* Fallback to memory scan (x86, x86_64) */ + if((buf = mem_chunk(opt->logdata, 0xF0000, 0x10000, opt->devmem)) == NULL) { + ver_n = NULL; + goto exit_free; + } + + /* Look for a 64-bit entry point first */ + for (fp = 0; fp <= 0xFFE0; fp+= 16){ + if(memcmp(buf+fp, "_SM3_", 5) == 0){ + ver_n = smbios3_decode_get_version(buf+fp, opt->devmem); + if( dmixml_GetAttrValue(ver_n, "unknown") == NULL ) { + 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) { + ver_n = smbios_decode_get_version(buf + fp, opt->devmem); + if ( dmixml_GetAttrValue(ver_n, "unknown") == NULL ) { + found++; + goto done; + } + fp += 16; + } else if (memcmp(buf + fp, "_DMI_", 5) == 0) { + ver_n = legacy_decode_get_version (buf + fp, opt->devmem); + if( dmixml_GetAttrValue(ver_n, "unknown") == NULL ) { + found++; + goto done; + } + } + } +#endif + +done: + if(!found){ log_append(opt->logdata, LOGFL_NODUPS, LOG_WARNING, - "No SMBIOS nor DMI entry point found, sorry."); - } - return ver_n; + "No SMBIOS nor DMI entry point found, sorry."); + } + +exit_free: + if (buf != NULL) + free(buf); + + return ver_n; + } int dmidecode_get_xml(options *opt, xmlNode* dmixml_n) @@ -195,6 +283,7 @@ int dmidecode_get_xml(options *opt, xmlNode* dmixml_n) size_t fp; int efi; u8 *buf = NULL; + size_t size; const char *f = opt->dumpfile ? opt->dumpfile : opt->devmem; if(access(f, R_OK) < 0) { @@ -205,53 +294,119 @@ int dmidecode_get_xml(options *opt, xmlNode* dmixml_n) /* Read from dump if so instructed */ if(opt->dumpfile != NULL) { - // printf("Reading SMBIOS/DMI data from file %s.\n", dumpfile); - if((buf = mem_chunk(opt->logdata, 0, 0x20, opt->dumpfile)) != NULL) { - if(memcmp(buf, "_SM_", 4) == 0) { - if(smbios_decode(opt->logdata, opt->type, buf, opt->dumpfile, dmixml_n)) - found++; - } else if(memcmp(buf, "_DMI_", 5) == 0) { - if(legacy_decode(opt->logdata, opt->type, buf, opt->dumpfile, dmixml_n)) - found++; + if((buf = mem_chunk(opt->logdata, 0, 0x20, opt->dumpfile)) == NULL) { + ret = 1; + goto exit_free; + } + if(memcmp(buf, "_SM3_", 5) == 0){ + if(smbios3_decode(opt->logdata, opt->type, buf,opt->dumpfile, 0, dmixml_n)) + found++; + } else if (memcmp(buf, "_SM_", 4) == 0){ + if(smbios_decode(opt->logdata, opt->type, buf, opt->dumpfile, 0, dmixml_n)) + found++; + } else if (memcmp(buf, "_DMI_", 5) == 0){ + if(legacy_decode(opt->logdata, opt->type, buf, opt->dumpfile, 0, dmixml_n)) + found++; + } + goto done; + } + + /* + * 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(opt->logdata, 0, &size, SYS_ENTRY_FILE)) != NULL){ + if ( size >= 24 && memcmp(buf, "_SM3_", 5) == 0) { + if (smbios3_decode(opt->logdata, opt->type, buf, SYS_TABLE_FILE, FLAG_NO_FILE_OFFSET, dmixml_n)) + found++; + } else if (size >= 31 && memcmp(buf, "_SM_", 4) == 0){ + if (smbios_decode(opt->logdata, opt->type, buf, SYS_TABLE_FILE, FLAG_NO_FILE_OFFSET, dmixml_n)) + found++; + } else if (size >= 15 && memcmp(buf, "_DMI_", 5) == 0){ + if (legacy_decode(opt->logdata, opt->type, buf, SYS_TABLE_FILE, FLAG_NO_FILE_OFFSET, dmixml_n)) + found++; + } + if (found) + goto done; + } else { + ret = 1; + goto done; + } + + /* Next try EFI (ia64, Intel-based Mac) */ + efi = address_from_efi(opt->logdata, &fp); + switch(efi){ + case EFI_NOT_FOUND: + goto memory_scan; + case EFI_NO_SMBIOS: + ret = 1; + goto exit_free; + } + + if(buf = mem_chunk(opt->logdata, fp, 0x20, opt->devmem) == NULL ){ + ret = 1; + goto exit_free; + } + + if (memcmp(buf, "_SM3_", 5) == 0){ + if (smbios3_decode(opt->logdata, opt->type, buf + fp, opt->devmem, 0, dmixml_n)) + found++; + } else if (memcmp(buf, "_SM_", 4) == 0){ + if(smbios_decode(opt->logdata, opt->type, buf + fp, opt->devmem, 0, dmixml_n)) + found++; + } + + goto done; + +memory_scan: +#if defined __i386__ || defined __x86_64__ + if((buf = mem_chunk(opt->logdata, 0xF0000, 0x10000, opt->devmem)) == NULL) + { + ret = 1; + goto exit_free; + } + + /* Look for a 64-bit entry point first */ + for (fp = 0; fp <= 0xFFE0; fp += 16){ + if (memcmp(buf + fp, "_SM3_", 5) == 0) + { + if(smbios3_decode(opt->logdata, opt->type, + buf + fp, opt->devmem, 0, dmixml_n)){ + found++; + goto done; } - } else { - ret = 1; } - } else { /* Read from /dev/mem */ - /* First try EFI (ia64, Intel-based Mac) */ - efi = address_from_efi(opt->logdata, &fp); - if(efi == EFI_NOT_FOUND) { - /* Fallback to memory scan (x86, x86_64) */ - if((buf = mem_chunk(opt->logdata, 0xF0000, 0x10000, opt->devmem)) != NULL) { - for(fp = 0; fp <= 0xFFF0; fp += 16) { - if(memcmp(buf + fp, "_SM_", 4) == 0 && fp <= 0xFFE0) { - if(smbios_decode(opt->logdata, opt->type, - buf + fp, opt->devmem, dmixml_n)) { - found++; - fp += 16; - } - } else if(memcmp(buf + fp, "_DMI_", 5) == 0) { - if(legacy_decode(opt->logdata, opt->type, - buf + fp, opt->devmem, dmixml_n)) - found++; - } - } - } else - ret = 1; - } else if(efi == EFI_NO_SMBIOS) { - ret = 1; - } else { - if((buf = mem_chunk(opt->logdata, fp, 0x20, opt->devmem)) == NULL) - ret = 1; - else if(smbios_decode(opt->logdata, opt->type, buf, opt->devmem, dmixml_n)) + } + + /* 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(opt->logdata, opt->type, + buf + fp, opt->devmem, 0, dmixml_n)) { + found++; + goto done; + } + } else if(memcmp(buf + fp, "_DMI_", 5) == 0) { + if(legacy_decode(opt->logdata, opt->type, + buf + fp, opt->devmem, 0, dmixml_n)) found++; - // TODO: dmixml_AddAttribute(dmixml_n, "efi_address", "0x%08x", efiAddress); + goto done; + } } +#endif + +done: + if( !found ) { + log_append(opt->logdata, LOGFL_NODUPS, LOG_WARNING, + "No SMBIOS nor DMI entry point found, sorry."); } - if(ret == 0) { + +exit_free: + if(buf != NULL) free(buf); - } - //muntrace(); + return ret; } @@ -342,14 +497,21 @@ xmlNode *__dmidecode_xml_getsection(options *opt, const char *section) { static PyObject *dmidecode_get_group(options *opt, const char *section) { + int efi; + size_t fp; PyObject *pydata = NULL; xmlNode *dmixml_n = NULL; ptzMAP *mapping = NULL; /* Set default option values */ if( opt->devmem == NULL ) { - opt->devmem = DEFAULT_MEM_DEV; - } + efi = address_from_efi(opt->logdata, &fp); + if(efi == EFI_NOT_FOUND){ + opt->devmem = DEFAULT_MEM_DEV; + } else { + opt->devmem = SYS_TABLE_FILE; + } + } opt->flags = 0; // Decode the dmidata into an XML node @@ -380,11 +542,18 @@ static PyObject *dmidecode_get_group(options *opt, const char *section) xmlNode *__dmidecode_xml_gettypeid(options *opt, int typeid) { + int efi; + size_t fp; xmlNode *dmixml_n = NULL; /* Set default option values */ if( opt->devmem == NULL ) { - opt->devmem = DEFAULT_MEM_DEV; + efi = address_from_efi(opt->logdata, &fp); + if(efi == EFI_NOT_FOUND){ + opt->devmem = DEFAULT_MEM_DEV; + } else { + opt->devmem = SYS_TABLE_FILE; + } } opt->flags = 0; @@ -598,7 +767,7 @@ static PyObject *dmidecode_dump(PyObject * self, PyObject * null) stat(f, &_buf); if( (access(f, F_OK) != 0) || ((access(f, W_OK) == 0) && S_ISREG(_buf.st_mode)) ) { - if( dump(DEFAULT_MEM_DEV, f) ) { + if( dump(SYS_TABLE_FILE, f) ) { Py_RETURN_TRUE; } } diff --git a/src/dmidecodemodule.h b/src/dmidecodemodule.h index 3600ba9..044317e 100644 --- a/src/dmidecodemodule.h +++ b/src/dmidecodemodule.h @@ -68,8 +68,10 @@ xmlNode *dmidecode_get_version(options *); extern void dmi_dump(xmlNode *node, struct dmi_header *h); extern int address_from_efi(Log_t *logp, size_t * address); extern void to_dmi_header(struct dmi_header *h, u8 * data); -extern int smbios_decode(Log_t *logp, int type, u8 *buf, const char *devmem, xmlNode *node); -extern int legacy_decode(Log_t *logp, int type, u8 *buf, const char *devmem, xmlNode *node); +extern int smbios3_decode(Log_t *logp, int type, u8 *buf, const char *devmem, u32 flags, xmlNode *node); +extern int smbios_decode(Log_t *logp, int type, u8 *buf, const char *devmem, u32 flags, xmlNode *node); +extern int legacy_decode(Log_t *logp, int type, u8 *buf, const char *devmem, u32 flags, xmlNode *node); +extern xmlNode *smbios3_decode_get_version(u8 * buf, const char *devmem); extern xmlNode *smbios_decode_get_version(u8 * buf, const char *devmem); extern xmlNode *legacy_decode_get_version(u8 * buf, const char *devmem); extern void *mem_chunk(Log_t *logp, size_t base, size_t len, const char *devmem); diff --git a/src/dmidump.c b/src/dmidump.c index fc67481..0d052fc 100644 --- a/src/dmidump.c +++ b/src/dmidump.c @@ -51,144 +51,214 @@ static void overwrite_dmi_address(u8 * buf) 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; +} -int write_dump(size_t base, size_t len, const void *data, const char *dumpfile, int add) +void dmi_table_dump(const u8 *buf, u32 len, const char *dumpfile) { - FILE *f; + write_dump(32, len, buf, dumpfile, 0); +} - f = fopen(dumpfile, add ? "r+b" : "wb"); - if(!f) { - fprintf(stderr, "%s: ", dumpfile); - perror("fopen"); - return -1; - } +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; - if(fseek(f, base, SEEK_SET) != 0) { - fprintf(stderr, "%s: ", dumpfile); - perror("fseek"); - goto err_close; - } + buf = read_file(NULL, flags & FLAG_NO_FILE_OFFSET ? 0 : base, + &size, devmem); + len = size; - if(fwrite(data, len, 1, f) != 1) { - fprintf(stderr, "%s: ", dumpfile); - perror("fwrite"); - goto err_close; + if (buf == NULL) + { + printf("read failed\n"); } + dmi_table_dump(buf, len, dumpfile); + free(buf); +} - if(fclose(f)) { - fprintf(stderr, "%s: ", dumpfile); - perror("fclose"); - return -1; - } +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]; - return 0; + dmi_table(((off_t)offset.h << 32) | offset.l,DWORD(buf + 0x0C), 0, ver, devmem, flags | FLAG_STOP_AT_EOT, dumpfile); - err_close: - fclose(f); - return -1; -} + if (!checksum(buf, buf[0x05])) + return 0; + 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; +} -int dumpling(u8 * buf, const char *dumpfile, u8 mode) +static int smbios_decode(u8 *buf, const char *devmem, u32 flags, const char *dumpfile) { - u32 base; - u16 len; - - if(mode == NON_LEGACY) { - if(!checksum(buf, buf[0x05]) || !memcmp(buf + 0x10, "_DMI_", 5) == 0 || - !checksum(buf + 0x10, 0x0F)) - return 0; - base = DWORD(buf + 0x18); - len = WORD(buf + 0x16); - } else { - if(!checksum(buf, 0x0F)) - return 0; - base = DWORD(buf + 0x08); - len = WORD(buf + 0x06); - } + u16 ver; + if (!checksum(buf, buf[0x05]) + || memcmp(buf + 0x10, "_DMI_", 5) != 0 + || !checksum(buf + 0x10, 0x0F)) + return 0; - u8 *buff; + ver = (buf[0x06] << 8) + buf[0x07]; + switch (ver) + { + case 0x021F: + case 0x0221: + ver = 0x0203; + break; + case 0x0233: + ver = 0x0206; + break; + } - if((buff = mem_chunk(NULL, base, len, DEFAULT_MEM_DEV)) != NULL) { - //. Part 1. -#ifdef NDEBUG - printf("# Writing %d bytes to %s.\n", len, dumpfile); -#endif - write_dump(32, len, buff, dumpfile, 0); - free(buff); - //. Part 2. - if(mode != LEGACY) { - u8 crafted[32]; + dmi_table(DWORD(buf + 0x18), WORD(buf + 0x16), WORD(buf + 0x1C), + ver << 8, devmem, flags, dumpfile); - memcpy(crafted, buf, 32); - overwrite_dmi_address(crafted + 0x10); -#ifdef NDEBUG - printf("# Writing %d bytes to %s.\n", crafted[0x05], dumpfile); -#endif - write_dump(0, crafted[0x05], crafted, dumpfile, 1); - } else { - u8 crafted[16]; - - memcpy(crafted, buf, 16); - overwrite_dmi_address(crafted); -#ifdef NDEBUG - printf("# Writing %d bytes to %s.\n", 0x0F, dumpfile); -#endif - write_dump(0, 0x0F, crafted, dumpfile, 1); - } - } else { - fprintf(stderr, "Failed to read table, sorry.\n"); - } + u8 crafted[32]; + memcpy(crafted, buf, 32); + overwrite_dmi_address(crafted + 0x10); + write_dump(0, crafted[0x05], crafted, dumpfile, 1); - //. TODO: Cleanup 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); +} int dump(const char *memdev, const char *dumpfile) { - /* On success, return found, otherwise return -1 */ + /* 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); - if(efi == EFI_NOT_FOUND) { - /* Fallback to memory scan (x86, x86_64) */ - if((buf = mem_chunk(NULL, 0xF0000, 0x10000, memdev)) != NULL) { - for(fp = 0; fp <= 0xFFF0; fp += 16) { - if(memcmp(buf + fp, "_SM_", 4) == 0 && fp <= 0xFFE0) { - if(dumpling(buf + fp, dumpfile, NON_LEGACY)) - found++; - fp += 16; - } else if(memcmp(buf + fp, "_DMI_", 5) == 0) { - if(dumpling(buf + fp, dumpfile, LEGACY)) - found++; - } - } - } else - ret = -1; - } else if(efi == EFI_NO_SMBIOS) { - ret = -1; - } else { - if((buf = mem_chunk(NULL, fp, 0x20, memdev)) == NULL) - ret = -1; - else if(dumpling(buf, dumpfile, NON_LEGACY)) + 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; - if(ret == 0) { - free(buf); - if(!found) { - ret = -1; +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 == 0 ? found : ret; + return ret; } diff --git a/src/dmidump.h b/src/dmidump.h index 3c12248..a025829 100644 --- a/src/dmidump.h +++ b/src/dmidump.h @@ -32,6 +32,13 @@ #define NON_LEGACY 0 #define LEGACY 1 +#define FLAG_NO_FILE_OFFSET (1 << 0) +#define FLAG_STOP_AT_EOT (1 << 1) + +#define SYS_FIRMWARE_DIR "/sys/firmware/dmi/tables" +#define SYS_ENTRY_FILE SYS_FIRMWARE_DIR "/smbios_entry_point" +#define SYS_TABLE_FILE SYS_FIRMWARE_DIR "/DMI" + int dump(const char *memdev, const char *dumpfile); #endif diff --git a/src/util.c b/src/util.c index da97767..4f233ff 100644 --- a/src/util.c +++ b/src/util.c @@ -50,7 +50,6 @@ #include "util.h" #include "dmilog.h" -#ifndef USE_MMAP static int myread(Log_t *logp, int fd, u8 * buf, size_t count, const char *prefix) { ssize_t r = 1; @@ -76,7 +75,6 @@ static int myread(Log_t *logp, int fd, u8 * buf, size_t count, const char *prefi return 0; } -#endif int checksum(const u8 * buf, size_t len) { @@ -88,6 +86,73 @@ int checksum(const u8 * buf, size_t len) return (sum == 0); } +/* + * Reads all of file from given offset, up to max_len bytes. + * A buffer of at most max_len bytes is allocated by this function, and + * needs to be freed by the caller. + * This provides a similar usage model to mem_chunk() + * + * Returns a pointer to the allocated buffer, or NULL on error, and + * sets max_len to the length actually read. + */ +void *read_file(Log_t *logp, off_t base, size_t *max_len, const char *filename) +{ + struct stat statbuf; + int fd; + u8 *p; + /* + * Don't print error message on missing file, as we will try to read + * files that may or may not be present. + */ + if ((fd = open(filename, O_RDONLY)) == -1) + { + if (errno != ENOENT) + perror(filename); + return NULL; + } + + /* + * Check file size, don't allocate more than can be read. + */ + if (fstat(fd, &statbuf) == 0) + { + if (base >= statbuf.st_size) + { + fprintf(stderr, "%s: Can't read data beyond EOF\n", + filename); + p = NULL; + goto out; + } + if (*max_len > (size_t)statbuf.st_size - base) + *max_len = statbuf.st_size - base; + } + + if ((p = malloc(*max_len)) == NULL) + { + perror("malloc"); + goto out; + } + + if (lseek(fd, base, SEEK_SET) == -1) + { + fprintf(stderr, "%s: ", filename); + perror("lseek"); + goto err_free; + } + if (myread(logp, fd, p, *max_len, filename) == 0) + goto out; + +err_free: + free(p); + p = NULL; + +out: + if (close(fd) == -1) + perror(filename); + + return p; +} + /* Static global variables which should only * be used by the sigill_handler() */ @@ -105,6 +170,18 @@ void sigill_handler(int ignore_this) { } } +static void safe_memcpy(void *dest, const void *src, size_t n) +{ +#ifdef USE_SLOW_MEMCPY + size_t i; + + for (i = 0; i < n; i++) + *((u8 *)dest + i) = *((const u8 *)src + i); +#else + memcpy(dest, src, n); +#endif +} + /* * Copy a physical memory chunk into a memory buffer. * This function allocates memory. @@ -115,7 +192,8 @@ void *mem_chunk(Log_t *logp, size_t base, size_t len, const char *devmem) int fd = -1; #ifdef USE_MMAP - size_t mmoffset; + struct stat statbuf; + size_t mmoffset; void *mmp; #endif sigill_logobj = logp; @@ -134,6 +212,23 @@ void *mem_chunk(Log_t *logp, size_t base, size_t len, const char *devmem) goto exit; } #ifdef USE_MMAP + if (sigill_error || fstat(fd, &statbuf) == -1 ) + { + log_append(logp, LOGFL_NORMAL, LOG_WARNING,"fstat: %s", strerror(errno)); + goto err_free; + } + + /* + * mmap() will fail with SIGBUS if trying to map beyond the end of + * the file. + */ + if (sigill_error || S_ISREG(statbuf.st_mode) && base + (off_t)len > statbuf.st_size ) + { + log_append(logp, LOGFL_NORMAL, LOG_WARNING, + "mmap: Can't map beyond end of file %s: %s", + devmem, strerror(errno)); + goto err_free; + } #ifdef _SC_PAGESIZE mmoffset = base % sysconf(_SC_PAGESIZE); #else @@ -147,9 +242,7 @@ void *mem_chunk(Log_t *logp, size_t base, size_t len, const char *devmem) mmp = mmap(0, mmoffset + len, PROT_READ, MAP_SHARED, fd, base - mmoffset); if(sigill_error || (mmp == MAP_FAILED)) { log_append(logp, LOGFL_NORMAL, LOG_WARNING, "%s (mmap): %s", devmem, strerror(errno)); - free(p); - p = NULL; - goto exit; + goto try_read; } memcpy(p, (u8 *) mmp + mmoffset, len); @@ -167,28 +260,34 @@ void *mem_chunk(Log_t *logp, size_t base, size_t len, const char *devmem) p = NULL; goto exit; } -#else /* USE_MMAP */ - if(sigill_error || (lseek(fd, base, SEEK_SET) == -1)) { + goto exit; + +try_read: +#endif /* USE_MMAP */ + if (lseek(fd, base, SEEK_SET) == -1 ) + { log_append(logp, LOGFL_NORMAL, LOG_WARNING, "%s (lseek): %s", devmem, strerror(errno)); - free(p); - p = NULL; - goto exit; + goto err_free; } - if(sigill_error || (myread(logp, fd, p, len, devmem) == -1)) { + if(sigill_error || (myread(logp, fd, p, len, devmem) == 0)) { free(p); p = NULL; goto exit; } -#endif /* USE_MMAP */ - exit: +err_free: + free(p); + p = NULL; + +exit: if (fd >= 0) { if(close(fd) == -1) perror(devmem); } signal(SIGILL, SIG_DFL); sigill_logobj = NULL; + return p; } @@ -207,3 +306,42 @@ u64 u64_range(u64 start, u64 end) return res; } + +int write_dump(size_t base, size_t len, const void *data, const char *dumpfile, int add) +{ + FILE *f; + f = fopen(dumpfile, add ? "r+b" : "wb"); + if (!f) + { + fprintf(stderr, "%s: ", dumpfile); + perror("fopen"); + return -1; + } + + if (fseek(f, base, SEEK_SET) != 0) + { + fprintf(stderr, "%s: ", dumpfile); + perror("fseek"); + goto err_close; + } + + if (fwrite(data, len, 1, f) != 1) + { + fprintf(stderr, "%s: ", dumpfile); + perror("fwrite"); + goto err_close; + } + + if (fclose(f)) + { + fprintf(stderr, "%s: ", dumpfile); + perror("fclose"); + return -1; + } + + return 0; + +err_close: + fclose(f); + return -1; +} diff --git a/src/util.h b/src/util.h index aa0487a..3c803c0 100644 --- a/src/util.h +++ b/src/util.h @@ -27,6 +27,7 @@ #define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0])) int checksum(const u8 * buf, size_t len); +void *read_file( Log_t *logp, off_t base, size_t *len, const char *filename); void *mem_chunk(Log_t *logp, size_t base, size_t len, const char *devmem); int write_dump(size_t base, size_t len, const void *data, const char *dumpfile, int add); u64 u64_range(u64 start, u64 end); From a37fc124b558a9fda5e81faca12a35ab076aa006 Mon Sep 17 00:00:00 2001 From: Zhongze Hu Date: Mon, 5 Sep 2022 02:14:39 +0800 Subject: [PATCH 02/27] Fix bugs: 1. Fix smbios3_decode decoding sysfs table dump error. 2. Fix check smbios version error warning message. --- src/dmidecode.c | 12 +++++------- src/dmidump.c | 6 +++--- src/efi.c | 5 ++++- src/util.c | 5 +++-- 4 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/dmidecode.c b/src/dmidecode.c index 19958d3..cd9e420 100644 --- a/src/dmidecode.c +++ b/src/dmidecode.c @@ -92,7 +92,7 @@ #include "dmihelper.h" -#define SUPPORTED_SMBIOS_VER 0x0207 +#define SUPPORTED_SMBIOS_VER 0x030300 /******************************************************************************* ** Type-independant Stuff @@ -5197,7 +5197,7 @@ dmi_codes_major *find_dmiMajor(const struct dmi_header *h) return NULL; } -static void dmi_table(Log_t *logp, int type, u32 base, u16 len, u16 num, u16 ver, const char *devmem, u32 flags, xmlNode *xmlnode) +static void dmi_table(Log_t *logp, int type, u32 base, u32 len, u16 num, u32 ver, const char *devmem, u32 flags, xmlNode *xmlnode) { static u8 version_added = 0; u8 *buf; @@ -5241,7 +5241,7 @@ static void dmi_table(Log_t *logp, int type, u32 base, u16 len, u16 num, u16 ver } if (ver > SUPPORTED_SMBIOS_VER){ - log_append(logp, LOGFL_NODUPS, LOG_WARNING, "# SMBIOS implementations newer than version %u.%u are not\n", "# fully supported by this version of dmidecode.\n", SUPPORTED_SMBIOS_VER >> 8, SUPPORTED_SMBIOS_VER & 0xFF); + log_append(logp, LOGFL_NODUPS, LOG_WARNING, "# SMBIOS implementations newer than version %u.%u.%u are not\n fully supported by this version of dmidecode.\n", SUPPORTED_SMBIOS_VER >> 16, (SUPPORTED_SMBIOS_VER >> 8) & 0xFF, SUPPORTED_SMBIOS_VER & 0xFF); } if( version_added == 0 ) { @@ -5250,7 +5250,7 @@ static void dmi_table(Log_t *logp, int type, u32 base, u16 len, u16 num, u16 ver } data = buf; - while(i < num && data + 4 <= buf + len) { /* 4 is the length of an SMBIOS structure header */ + while((i < num||!num) && data + 4 <= buf + len) { /* 4 is the length of an SMBIOS structure header */ u8 *next; struct dmi_header h; @@ -5364,8 +5364,7 @@ xmlNode *smbios3_decode_get_version(u8 * buf, const char *devmem) dmixml_AddAttribute(data_n, "type", "SMBIOS"); if(check == 1) { - u16 ver = (buf[0x07] << 16) + (buf[0x08] << 8) + buf[0x09]; - + u32 ver = (buf[0x07] << 16) + (buf[0x08] << 8) + buf[0x09]; dmixml_AddTextContent(data_n, "SMBIOS %i.%i.%i present", buf[0x07], buf[0x08], buf[0x09]); dmixml_AddAttribute(data_n, "version", "%i.%i.%i", buf[0x07], buf[0x08],buf[0x09]); } else if(check == 0) { @@ -5396,7 +5395,6 @@ int smbios3_decode(Log_t *logp, int type, u8 *buf, const char *devmem, u32 flags { return 0; } - dmi_table(logp, type, ((off_t)offset.h << 32) | offset.l, DWORD(buf+0x0C), 0, ver, devmem, flags | FLAG_STOP_AT_EOT, xmlnode); } diff --git a/src/dmidump.c b/src/dmidump.c index 0d052fc..da0d676 100644 --- a/src/dmidump.c +++ b/src/dmidump.c @@ -96,11 +96,11 @@ static int smbios3_decode(u8 *buf, const char *devmem, u32 flags, const char *du offset = QWORD(buf + 0x10); ver = (buf[0x07] << 16) + (buf[0x08] << 8) + buf[0x09]; - dmi_table(((off_t)offset.h << 32) | offset.l,DWORD(buf + 0x0C), 0, ver, devmem, flags | FLAG_STOP_AT_EOT, dumpfile); - - if (!checksum(buf, buf[0x05])) + 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); diff --git a/src/efi.c b/src/efi.c index ae8d0db..362e2f9 100644 --- a/src/efi.c +++ b/src/efi.c @@ -49,6 +49,7 @@ int address_from_efi(Log_t *logp, size_t * address) FILE *efi_systab; const char *filename = NULL; char linebuf[64]; + const char *eptype; int ret; *address = 0; /* Prevent compiler warning */ @@ -67,8 +68,10 @@ int address_from_efi(Log_t *logp, size_t * address) char *addrp = strchr(linebuf, '='); *(addrp++) = '\0'; - if(strcmp(linebuf, "SMBIOS") == 0) { + if(strcmp(linebuf, "SMBIOS3") == 0 + || strcmp(linebuf, "SMBIOS") == 0) { *address = strtoul(addrp, NULL, 0); + eptype = linebuf; ret = 0; break; } diff --git a/src/util.c b/src/util.c index 4f233ff..465376e 100644 --- a/src/util.c +++ b/src/util.c @@ -239,13 +239,14 @@ void *mem_chunk(Log_t *logp, size_t base, size_t len, const char *devmem) * but to workaround problems many people encountered when trying * to read from /dev/mem using regular read() calls. */ - mmp = mmap(0, mmoffset + len, PROT_READ, MAP_SHARED, fd, base - mmoffset); + mmp = mmap(NULL, mmoffset + len, PROT_READ, MAP_SHARED, fd, base - mmoffset); if(sigill_error || (mmp == MAP_FAILED)) { log_append(logp, LOGFL_NORMAL, LOG_WARNING, "%s (mmap): %s", devmem, strerror(errno)); goto try_read; } - memcpy(p, (u8 *) mmp + mmoffset, len); + safe_memcpy(p, (u8 *) mmp + mmoffset, len); + if (sigill_error) { log_append(logp, LOGFL_NODUPS, LOG_WARNING, "Failed to do memcpy() due to SIGILL signal"); From c97d1ca021ddc160d70525d0840b1731f50ac4ca Mon Sep 17 00:00:00 2001 From: Zhongze Hu Date: Sat, 3 Sep 2022 20:03:27 +0800 Subject: [PATCH 03/27] Fix the failure of opening "/dev/mem": Permission denied The "/dev/mem" may be disabled(e.g kernel enables lockdown), which makes python-dmidecode has no permission to access the "/dev/mem". As a result, python-dmidecode will report an error as below: ** COLLECTED WARNINGS ** Failed to open memory buffer (/dev/mem): Permission denied No SMBIOS nor DMI entry point found, sorry. ** END OF WARNINGS ** Let's try to read the sysfs tables if the "/dev/mem" is unavailable. Resolves: https://github.com/nima/python-dmidecode/issues/15 Signed-off-by: Zhongze Hu --- src/dmidecode.c | 117 ++++++++++---- src/dmidecode.h | 13 +- src/dmidecodemodule.c | 367 ++++++++++++++++++++++++++++++------------ src/dmidecodemodule.h | 6 +- src/dmidump.c | 272 +++++++++++++++++++------------ src/dmidump.h | 7 + src/util.c | 166 +++++++++++++++++-- src/util.h | 1 + 8 files changed, 703 insertions(+), 246 deletions(-) diff --git a/src/dmidecode.c b/src/dmidecode.c index d30a5d3..19958d3 100644 --- a/src/dmidecode.c +++ b/src/dmidecode.c @@ -5197,7 +5197,7 @@ dmi_codes_major *find_dmiMajor(const struct dmi_header *h) return NULL; } -static void dmi_table(Log_t *logp, int type, u32 base, u16 len, u16 num, u16 ver, const char *devmem, xmlNode *xmlnode) +static void dmi_table(Log_t *logp, int type, u32 base, u16 len, u16 num, u16 ver, const char *devmem, u32 flags, xmlNode *xmlnode) { static u8 version_added = 0; u8 *buf; @@ -5221,35 +5221,40 @@ static void dmi_table(Log_t *logp, int type, u32 base, u16 len, u16 num, u16 ver info_n = NULL; } - if((buf = mem_chunk(logp, base, len, devmem)) == NULL) { - log_append(logp, LOGFL_NODUPS, LOG_WARNING, "Table is unreachable, sorry." -#ifndef USE_MMAP - "Try compiling dmidecode with -DUSE_MMAP." -#endif - ); - return; - } + if(flags & FLAG_NO_FILE_OFFSET){ + /* + * When reading from sysfs or from a dump file, the file may be + * shorter than announced. For SMBIOS v3 this is expcted, as we + * only know the maximum table size, not the actual table size. + * For older implementations (and for SMBIOS v3 too), this + * would be the result of the kernel truncating the table on + * parse error. + */ + size_t size = len; + buf = read_file(logp, flags & FLAG_NO_FILE_OFFSET ? 0 : base, &size, devmem); + if (num && size != (size_t)len){ + log_append(logp, LOGFL_NODUPS, LOG_WARNING, "Wrong DMI structures length: %i bytes announced, only %lu bytes available.\n", len, (unsigned long)size ); + } + len = size; + } else { + buf = mem_chunk(logp, base, len, devmem); + } + + if (ver > SUPPORTED_SMBIOS_VER){ + log_append(logp, LOGFL_NODUPS, LOG_WARNING, "# SMBIOS implementations newer than version %u.%u are not\n", "# fully supported by this version of dmidecode.\n", SUPPORTED_SMBIOS_VER >> 8, SUPPORTED_SMBIOS_VER & 0xFF); + } - if (ver > SUPPORTED_SMBIOS_VER) { - log_append(logp, LOGFL_NODUPS, LOG_WARNING, - "# SMBIOS implementations newer than version %u.%u are not\n" - "# fully supported by this version of dmidecode.\n", - SUPPORTED_SMBIOS_VER >> 8, SUPPORTED_SMBIOS_VER & 0xFF); - } - // FIXME: This is hackerish ... rather try to avoid looping dmi_table() calls too much if( version_added == 0 ) { dmixml_AddAttribute(xmlnode, "smbios_version", "%u.%u", ver >> 8, ver & 0xFF); version_added = 1; } - data = buf; - while(i < num && data + 4 <= buf + len) { /* 4 is the length of an SMBIOS structure header */ - + data = buf; + while(i < num && data + 4 <= buf + len) { /* 4 is the length of an SMBIOS structure header */ u8 *next; struct dmi_header h; to_dmi_header(&h, data); - /* ** If a short entry is found (less than 4 bytes), not only it ** is invalid, but we cannot reliably locate the next entry. @@ -5258,8 +5263,8 @@ static void dmi_table(Log_t *logp, int type, u32 base, u16 len, u16 num, u16 ver */ if(h.length < 4) { log_append(logp, LOGFL_NORMAL, LOG_WARNING, - "Invalid entry length (%i) for type %i. DMI table is broken! Stop.", - (unsigned int)h.length, type); + "Invalid entry length (%i) for type %i. DMI table is broken! Stop.", + (unsigned int)h.length, type); break; } @@ -5278,7 +5283,6 @@ static void dmi_table(Log_t *logp, int type, u32 base, u16 len, u16 num, u16 ver next++; } next += 2; - xmlNode *handle_n = NULL; if( h.type == type ) { if(next - buf <= len) { @@ -5309,6 +5313,7 @@ static void dmi_table(Log_t *logp, int type, u32 base, u16 len, u16 num, u16 ver dmixml_AddAttribute(handle_n, "length", "%i", (next - buf)); dmixml_AddAttribute(handle_n, "expected_length", "%i", len); + log_append(logp, LOGFL_NODUPS, LOG_WARNING, "DMI/SMBIOS type 0x%02X is exceeding the expected buffer " "size by %i bytes. Will not decode this entry.", @@ -5344,6 +5349,60 @@ static void dmi_table(Log_t *logp, int type, u32 base, u16 len, u16 num, u16 ver free(buf); } +int _smbios3_decode_check(u8 *buf){ + int check = (!checksum(buf, buf[0x06])) ? 0 : 1; + return check; +} + +xmlNode *smbios3_decode_get_version(u8 * buf, const char *devmem) +{ + int check = _smbios3_decode_check(buf); + + xmlNode *data_n = xmlNewNode(NULL, (xmlChar *) "DMIversion"); + assert( data_n != NULL ); + + dmixml_AddAttribute(data_n, "type", "SMBIOS"); + + if(check == 1) { + u16 ver = (buf[0x07] << 16) + (buf[0x08] << 8) + buf[0x09]; + + dmixml_AddTextContent(data_n, "SMBIOS %i.%i.%i present", buf[0x07], buf[0x08], buf[0x09]); + dmixml_AddAttribute(data_n, "version", "%i.%i.%i", buf[0x07], buf[0x08],buf[0x09]); + } else if(check == 0) { + dmixml_AddTextContent(data_n, "No SMBIOS nor DMI entry point found"); + dmixml_AddAttribute(data_n, "unknown", "1"); + } + return data_n; +} + +int smbios3_decode(Log_t *logp, int type, u8 *buf, const char *devmem, u32 flags, xmlNode *xmlnode) +{ + u32 ver; + u64 offset; + + /* Don't let checksum run beyond the buffer */ + if (buf[0x06] > 0x20) + { + return 0; + } + + int check = _smbios3_decode_check(buf); + if (check == 1) + { + ver = (buf[0x07] << 16) + (buf[0x08] << 8) + buf[0x09]; + offset = QWORD(buf + 0x10); + + if (!(flags & FLAG_NO_FILE_OFFSET) && offset.h && sizeof(off_t) < 8) + { + return 0; + } + + dmi_table(logp, type, ((off_t)offset.h << 32) | offset.l, DWORD(buf+0x0C), 0, ver, devmem, flags | FLAG_STOP_AT_EOT, xmlnode); + } + + return check; +} + int _smbios_decode_check(u8 * buf) { int check = (!checksum(buf, buf[0x05]) || memcmp(buf + 0x10, "_DMI_", 5) != 0 || @@ -5370,7 +5429,8 @@ xmlNode *smbios_decode_get_version(u8 * buf, const char *devmem) _M = 0; switch (ver) { case 0x021F: - _m = 31; + case 0x0221: + _m = ver & 0xFF; _M = 3; ver = 0x0203; break; @@ -5396,7 +5456,7 @@ xmlNode *smbios_decode_get_version(u8 * buf, const char *devmem) return data_n; } -int smbios_decode(Log_t *logp, int type, u8 *buf, const char *devmem, xmlNode *xmlnode) +int smbios_decode(Log_t *logp, int type, u8 *buf, const char *devmem, u32 flags, xmlNode *xmlnode) { int check = _smbios_decode_check(buf); @@ -5405,6 +5465,7 @@ int smbios_decode(Log_t *logp, int type, u8 *buf, const char *devmem, xmlNode *x switch (ver) { case 0x021F: + case 0x0221: ver = 0x0203; break; case 0x0233: @@ -5413,7 +5474,7 @@ int smbios_decode(Log_t *logp, int type, u8 *buf, const char *devmem, xmlNode *x } // printf(">>%d @ %d, %d<<\n", DWORD(buf+0x18), WORD(buf+0x16), WORD(buf+0x1C)); dmi_table(logp, type, DWORD(buf + 0x18), WORD(buf + 0x16), WORD(buf + 0x1C), ver, devmem, - xmlnode); + flags, xmlnode); } return check; } @@ -5451,13 +5512,13 @@ xmlNode *legacy_decode_get_version(u8 * buf, const char *devmem) return data_n; } -int legacy_decode(Log_t *logp, int type, u8 *buf, const char *devmem, xmlNode *xmlnode) +int legacy_decode(Log_t *logp, int type, u8 *buf, const char *devmem, u32 flags, xmlNode *xmlnode) { int check = _legacy_decode_check(buf); if(check == 1) dmi_table(logp, type, DWORD(buf + 0x08), WORD(buf + 0x06), WORD(buf + 0x0C), - ((buf[0x0E] & 0xF0) << 4) + (buf[0x0E] & 0x0F), devmem, xmlnode); + ((buf[0x0E] & 0xF0) << 4) + (buf[0x0E] & 0x0F), devmem, flags, xmlnode); return check; } diff --git a/src/dmidecode.h b/src/dmidecode.h index 926bd5d..22d70e1 100644 --- a/src/dmidecode.h +++ b/src/dmidecode.h @@ -23,6 +23,13 @@ #include "dmihelper.h" #include "dmierror.h" +#define FLAG_NO_FILE_OFFSET (1 << 0) +#define FLAG_STOP_AT_EOT (1 << 1) + +#define SYS_FIRMWARE_DIR "/sys/firmware/dmi/tables" +#define SYS_ENTRY_FILE SYS_FIRMWARE_DIR "/smbios_entry_point" +#define SYS_TABLE_FILE SYS_FIRMWARE_DIR "/DMI" + struct dmi_header { u8 type; u8 length; @@ -34,10 +41,12 @@ void dmi_dump(xmlNode *node, struct dmi_header * h); xmlNode *dmi_decode(xmlNode *parent_n, dmi_codes_major *dmiMajor, struct dmi_header * h, u16 ver); void to_dmi_header(struct dmi_header *h, u8 * data); +xmlNode *smbios3_decode_get_version(u8 * buf, const char *devmem); xmlNode *smbios_decode_get_version(u8 * buf, const char *devmem); xmlNode *legacy_decode_get_version(u8 * buf, const char *devmem); -int smbios_decode(Log_t *logp, int type, u8 *buf, const char *devmem, xmlNode *xmlnode); -int legacy_decode(Log_t *logp, int type, u8 *buf, const char *devmem, xmlNode *xmlnode); +int smbios3_decode(Log_t *logp, int type, u8 *buf, const char *devmem, u32 flags, xmlNode *xmlnode); +int smbios_decode(Log_t *logp, int type, u8 *buf, const char *devmem, u32 flags, xmlNode *xmlnode); +int legacy_decode(Log_t *logp, int type, u8 *buf, const char *devmem, u32 flags, xmlNode *xmlnode); const char *dmi_string(const struct dmi_header *dm, u8 s); void dmi_system_uuid(xmlNode *node, const u8 * p, u16 ver); diff --git a/src/dmidecodemodule.c b/src/dmidecodemodule.c index 44ef7aa..d3ac7ff 100644 --- a/src/dmidecodemodule.c +++ b/src/dmidecodemodule.c @@ -66,7 +66,9 @@ char *PyUnicode_AsUTF8(PyObject *unicode) { static void init(options *opt) { - opt->devmem = DEFAULT_MEM_DEV; + int efi; + size_t fp; + opt->dumpfile = NULL; opt->flags = 0; opt->type = -1; @@ -75,6 +77,13 @@ static void init(options *opt) opt->python_xml_map = strdup(PYTHON_XML_MAP); opt->logdata = log_init(); + efi = address_from_efi(opt->logdata, &fp); + if(efi == EFI_NOT_FOUND){ + opt->devmem = DEFAULT_MEM_DEV; + } else { + opt->devmem = SYS_TABLE_FILE; + } + /* sanity check */ if(sizeof(u8) != 1 || sizeof(u16) != 2 || sizeof(u32) != 4 || '\0' != 0) { log_append(opt->logdata, LOGFL_NORMAL, LOG_WARNING, @@ -116,70 +125,149 @@ xmlNode *dmidecode_get_version(options *opt) int efi; u8 *buf = NULL; xmlNode *ver_n = NULL; + size_t size; - /* Set default option values */ + /* + * First, if devmem is available, set default as DEFAULT_MEM_DEV + * Set default option values + */ if( opt->devmem == NULL ) { - opt->devmem = DEFAULT_MEM_DEV; + efi = address_from_efi(opt->logdata, &fp); + if(efi == EFI_NOT_FOUND){ + opt->devmem = DEFAULT_MEM_DEV; + } else { + opt->devmem = SYS_TABLE_FILE; + } } /* Read from dump if so instructed */ if(opt->dumpfile != NULL) { //. printf("Reading SMBIOS/DMI data from file %s.\n", dumpfile); if((buf = mem_chunk(opt->logdata, 0, 0x20, opt->dumpfile)) != NULL) { - if(memcmp(buf, "_SM_", 4) == 0) { - ver_n = smbios_decode_get_version(buf, opt->dumpfile); - if( dmixml_GetAttrValue(ver_n, "unknown") == NULL ) { - found++; - } - } else if(memcmp(buf, "_DMI_", 5) == 0) { - ver_n = legacy_decode_get_version(buf, opt->dumpfile); - if( dmixml_GetAttrValue(ver_n, "unknown") == NULL ) { - found++; - } - } - } - } else { /* Read from /dev/mem */ - /* First try EFI (ia64, Intel-based Mac) */ - efi = address_from_efi(opt->logdata, &fp); - if(efi == EFI_NOT_FOUND) { - /* Fallback to memory scan (x86, x86_64) */ - if((buf = mem_chunk(opt->logdata, 0xF0000, 0x10000, opt->devmem)) != NULL) { - for(fp = 0; fp <= 0xFFF0; fp += 16) { - if(memcmp(buf + fp, "_SM_", 4) == 0 && fp <= 0xFFE0) { - ver_n = smbios_decode_get_version(buf + fp, opt->devmem); - if( dmixml_GetAttrValue(ver_n, "unknown") == NULL ) { - found++; - } - fp += 16; - } else if(memcmp(buf + fp, "_DMI_", 5) == 0) { - ver_n = legacy_decode_get_version (buf + fp, opt->devmem); - if( dmixml_GetAttrValue(ver_n, "unknown") == NULL ) { - found++; - } - } - } - } - } else if(efi == EFI_NO_SMBIOS) { - ver_n = NULL; - } else { - // Process as EFI - if((buf = mem_chunk(opt->logdata, fp, 0x20, opt->devmem)) != NULL) { - ver_n = smbios_decode_get_version(buf, opt->devmem); - if( dmixml_GetAttrValue(ver_n, "unknown") == NULL ) { - found++; - } - //. TODO: dmixml_AddAttribute(dmixml_n, "efi_address", efiAddress); - } + ver_n = NULL; + goto exit_free; + } + if(memcmp(buf, "_SM3_", 5) == 0){ + ver_n = smbios3_decode_get_version(buf, opt->dumpfile); + if ( dmixml_GetAttrValue(ver_n, "unknown") == NULL ) + found++; + } else if(memcmp(buf, "_SM_", 4) == 0) { + ver_n = smbios_decode_get_version(buf, opt->dumpfile); + if( dmixml_GetAttrValue(ver_n, "unknown") == NULL ) + found++; + } else if(memcmp(buf, "_DMI_", 5) == 0) { + ver_n = legacy_decode_get_version(buf, opt->dumpfile); + if( dmixml_GetAttrValue(ver_n, "unknown") == NULL ) + found++; } } - if( buf != NULL ) { - free(buf); - } - if( !found ) { + + /* + * 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(opt->logdata, 0, &size, SYS_ENTRY_FILE)) != NULL ){ + if(size >= 24 && memcmp(buf, "_SM3_", 5) == 0){ + ver_n = smbios3_decode_get_version(buf, opt->devmem); + if (dmixml_GetAttrValue(ver_n, "unknown") == NULL) + found++; + } else if (size >= 31 && memcmp(buf, "_SM_", 4) == 0 ){ + ver_n = smbios_decode_get_version(buf, opt->devmem); + if (dmixml_GetAttrValue(ver_n, "unknown") == NULL) + found++; + } else if (size >= 15 && memcmp(buf, "_DMI_", 5) == 0){ + ver_n = legacy_decode_get_version (buf, opt->devmem); + if (dmixml_GetAttrValue(ver_n, "unknown") == NULL) + found++; + } + + if(found) + goto done; + } else { + ver_n = NULL; + goto exit_free; + } + + /* Read from /dev/mem */ + /* Next try EFI (ia64, Intel-based Mac) */ + efi = address_from_efi(opt->logdata, &fp); + switch(efi){ + case EFI_NOT_FOUND: + goto memory_scan; + case EFI_NO_SMBIOS: + ver_n = NULL; + goto exit_free; + } + + if(buf = mem_chunk(opt->logdata, fp, 0x20, opt->devmem) == NULL){ + ver_n = NULL; + goto exit_free; + } + + if(memcmp(buf, "_SM3_", 5) == 0){ + ver_n = smbios3_decode_get_version(buf, opt->devmem); + if(dmixml_GetAttrValue(ver_n, "unknown") == NULL) + found++; + } else if (memcmp(buf, "_SM_", 4) == 0 ) { + ver_n = smbios_decode_get_version(buf, opt->devmem); + if(dmixml_GetAttrValue(ver_n, "unknown") == NULL) + found++; + } + + goto done; + +memory_scan: +#if defined __i386__ || defined __x86_64__ + /* Fallback to memory scan (x86, x86_64) */ + if((buf = mem_chunk(opt->logdata, 0xF0000, 0x10000, opt->devmem)) == NULL) { + ver_n = NULL; + goto exit_free; + } + + /* Look for a 64-bit entry point first */ + for (fp = 0; fp <= 0xFFE0; fp+= 16){ + if(memcmp(buf+fp, "_SM3_", 5) == 0){ + ver_n = smbios3_decode_get_version(buf+fp, opt->devmem); + if( dmixml_GetAttrValue(ver_n, "unknown") == NULL ) { + 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) { + ver_n = smbios_decode_get_version(buf + fp, opt->devmem); + if ( dmixml_GetAttrValue(ver_n, "unknown") == NULL ) { + found++; + goto done; + } + fp += 16; + } else if (memcmp(buf + fp, "_DMI_", 5) == 0) { + ver_n = legacy_decode_get_version (buf + fp, opt->devmem); + if( dmixml_GetAttrValue(ver_n, "unknown") == NULL ) { + found++; + goto done; + } + } + } +#endif + +done: + if(!found){ log_append(opt->logdata, LOGFL_NODUPS, LOG_WARNING, - "No SMBIOS nor DMI entry point found, sorry."); - } - return ver_n; + "No SMBIOS nor DMI entry point found, sorry."); + } + +exit_free: + if (buf != NULL) + free(buf); + + return ver_n; + } int dmidecode_get_xml(options *opt, xmlNode* dmixml_n) @@ -195,6 +283,7 @@ int dmidecode_get_xml(options *opt, xmlNode* dmixml_n) size_t fp; int efi; u8 *buf = NULL; + size_t size; const char *f = opt->dumpfile ? opt->dumpfile : opt->devmem; if(access(f, R_OK) < 0) { @@ -205,53 +294,119 @@ int dmidecode_get_xml(options *opt, xmlNode* dmixml_n) /* Read from dump if so instructed */ if(opt->dumpfile != NULL) { - // printf("Reading SMBIOS/DMI data from file %s.\n", dumpfile); - if((buf = mem_chunk(opt->logdata, 0, 0x20, opt->dumpfile)) != NULL) { - if(memcmp(buf, "_SM_", 4) == 0) { - if(smbios_decode(opt->logdata, opt->type, buf, opt->dumpfile, dmixml_n)) - found++; - } else if(memcmp(buf, "_DMI_", 5) == 0) { - if(legacy_decode(opt->logdata, opt->type, buf, opt->dumpfile, dmixml_n)) - found++; + if((buf = mem_chunk(opt->logdata, 0, 0x20, opt->dumpfile)) == NULL) { + ret = 1; + goto exit_free; + } + if(memcmp(buf, "_SM3_", 5) == 0){ + if(smbios3_decode(opt->logdata, opt->type, buf,opt->dumpfile, 0, dmixml_n)) + found++; + } else if (memcmp(buf, "_SM_", 4) == 0){ + if(smbios_decode(opt->logdata, opt->type, buf, opt->dumpfile, 0, dmixml_n)) + found++; + } else if (memcmp(buf, "_DMI_", 5) == 0){ + if(legacy_decode(opt->logdata, opt->type, buf, opt->dumpfile, 0, dmixml_n)) + found++; + } + goto done; + } + + /* + * 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(opt->logdata, 0, &size, SYS_ENTRY_FILE)) != NULL){ + if ( size >= 24 && memcmp(buf, "_SM3_", 5) == 0) { + if (smbios3_decode(opt->logdata, opt->type, buf, SYS_TABLE_FILE, FLAG_NO_FILE_OFFSET, dmixml_n)) + found++; + } else if (size >= 31 && memcmp(buf, "_SM_", 4) == 0){ + if (smbios_decode(opt->logdata, opt->type, buf, SYS_TABLE_FILE, FLAG_NO_FILE_OFFSET, dmixml_n)) + found++; + } else if (size >= 15 && memcmp(buf, "_DMI_", 5) == 0){ + if (legacy_decode(opt->logdata, opt->type, buf, SYS_TABLE_FILE, FLAG_NO_FILE_OFFSET, dmixml_n)) + found++; + } + if (found) + goto done; + } else { + ret = 1; + goto done; + } + + /* Next try EFI (ia64, Intel-based Mac) */ + efi = address_from_efi(opt->logdata, &fp); + switch(efi){ + case EFI_NOT_FOUND: + goto memory_scan; + case EFI_NO_SMBIOS: + ret = 1; + goto exit_free; + } + + if(buf = mem_chunk(opt->logdata, fp, 0x20, opt->devmem) == NULL ){ + ret = 1; + goto exit_free; + } + + if (memcmp(buf, "_SM3_", 5) == 0){ + if (smbios3_decode(opt->logdata, opt->type, buf + fp, opt->devmem, 0, dmixml_n)) + found++; + } else if (memcmp(buf, "_SM_", 4) == 0){ + if(smbios_decode(opt->logdata, opt->type, buf + fp, opt->devmem, 0, dmixml_n)) + found++; + } + + goto done; + +memory_scan: +#if defined __i386__ || defined __x86_64__ + if((buf = mem_chunk(opt->logdata, 0xF0000, 0x10000, opt->devmem)) == NULL) + { + ret = 1; + goto exit_free; + } + + /* Look for a 64-bit entry point first */ + for (fp = 0; fp <= 0xFFE0; fp += 16){ + if (memcmp(buf + fp, "_SM3_", 5) == 0) + { + if(smbios3_decode(opt->logdata, opt->type, + buf + fp, opt->devmem, 0, dmixml_n)){ + found++; + goto done; } - } else { - ret = 1; } - } else { /* Read from /dev/mem */ - /* First try EFI (ia64, Intel-based Mac) */ - efi = address_from_efi(opt->logdata, &fp); - if(efi == EFI_NOT_FOUND) { - /* Fallback to memory scan (x86, x86_64) */ - if((buf = mem_chunk(opt->logdata, 0xF0000, 0x10000, opt->devmem)) != NULL) { - for(fp = 0; fp <= 0xFFF0; fp += 16) { - if(memcmp(buf + fp, "_SM_", 4) == 0 && fp <= 0xFFE0) { - if(smbios_decode(opt->logdata, opt->type, - buf + fp, opt->devmem, dmixml_n)) { - found++; - fp += 16; - } - } else if(memcmp(buf + fp, "_DMI_", 5) == 0) { - if(legacy_decode(opt->logdata, opt->type, - buf + fp, opt->devmem, dmixml_n)) - found++; - } - } - } else - ret = 1; - } else if(efi == EFI_NO_SMBIOS) { - ret = 1; - } else { - if((buf = mem_chunk(opt->logdata, fp, 0x20, opt->devmem)) == NULL) - ret = 1; - else if(smbios_decode(opt->logdata, opt->type, buf, opt->devmem, dmixml_n)) + } + + /* 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(opt->logdata, opt->type, + buf + fp, opt->devmem, 0, dmixml_n)) { + found++; + goto done; + } + } else if(memcmp(buf + fp, "_DMI_", 5) == 0) { + if(legacy_decode(opt->logdata, opt->type, + buf + fp, opt->devmem, 0, dmixml_n)) found++; - // TODO: dmixml_AddAttribute(dmixml_n, "efi_address", "0x%08x", efiAddress); + goto done; + } } +#endif + +done: + if( !found ) { + log_append(opt->logdata, LOGFL_NODUPS, LOG_WARNING, + "No SMBIOS nor DMI entry point found, sorry."); } - if(ret == 0) { + +exit_free: + if(buf != NULL) free(buf); - } - //muntrace(); + return ret; } @@ -342,14 +497,21 @@ xmlNode *__dmidecode_xml_getsection(options *opt, const char *section) { static PyObject *dmidecode_get_group(options *opt, const char *section) { + int efi; + size_t fp; PyObject *pydata = NULL; xmlNode *dmixml_n = NULL; ptzMAP *mapping = NULL; /* Set default option values */ if( opt->devmem == NULL ) { - opt->devmem = DEFAULT_MEM_DEV; - } + efi = address_from_efi(opt->logdata, &fp); + if(efi == EFI_NOT_FOUND){ + opt->devmem = DEFAULT_MEM_DEV; + } else { + opt->devmem = SYS_TABLE_FILE; + } + } opt->flags = 0; // Decode the dmidata into an XML node @@ -380,11 +542,18 @@ static PyObject *dmidecode_get_group(options *opt, const char *section) xmlNode *__dmidecode_xml_gettypeid(options *opt, int typeid) { + int efi; + size_t fp; xmlNode *dmixml_n = NULL; /* Set default option values */ if( opt->devmem == NULL ) { - opt->devmem = DEFAULT_MEM_DEV; + efi = address_from_efi(opt->logdata, &fp); + if(efi == EFI_NOT_FOUND){ + opt->devmem = DEFAULT_MEM_DEV; + } else { + opt->devmem = SYS_TABLE_FILE; + } } opt->flags = 0; @@ -598,7 +767,7 @@ static PyObject *dmidecode_dump(PyObject * self, PyObject * null) stat(f, &_buf); if( (access(f, F_OK) != 0) || ((access(f, W_OK) == 0) && S_ISREG(_buf.st_mode)) ) { - if( dump(DEFAULT_MEM_DEV, f) ) { + if( dump(SYS_TABLE_FILE, f) ) { Py_RETURN_TRUE; } } diff --git a/src/dmidecodemodule.h b/src/dmidecodemodule.h index 3600ba9..044317e 100644 --- a/src/dmidecodemodule.h +++ b/src/dmidecodemodule.h @@ -68,8 +68,10 @@ xmlNode *dmidecode_get_version(options *); extern void dmi_dump(xmlNode *node, struct dmi_header *h); extern int address_from_efi(Log_t *logp, size_t * address); extern void to_dmi_header(struct dmi_header *h, u8 * data); -extern int smbios_decode(Log_t *logp, int type, u8 *buf, const char *devmem, xmlNode *node); -extern int legacy_decode(Log_t *logp, int type, u8 *buf, const char *devmem, xmlNode *node); +extern int smbios3_decode(Log_t *logp, int type, u8 *buf, const char *devmem, u32 flags, xmlNode *node); +extern int smbios_decode(Log_t *logp, int type, u8 *buf, const char *devmem, u32 flags, xmlNode *node); +extern int legacy_decode(Log_t *logp, int type, u8 *buf, const char *devmem, u32 flags, xmlNode *node); +extern xmlNode *smbios3_decode_get_version(u8 * buf, const char *devmem); extern xmlNode *smbios_decode_get_version(u8 * buf, const char *devmem); extern xmlNode *legacy_decode_get_version(u8 * buf, const char *devmem); extern void *mem_chunk(Log_t *logp, size_t base, size_t len, const char *devmem); diff --git a/src/dmidump.c b/src/dmidump.c index fc67481..0d052fc 100644 --- a/src/dmidump.c +++ b/src/dmidump.c @@ -51,144 +51,214 @@ static void overwrite_dmi_address(u8 * buf) 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; +} -int write_dump(size_t base, size_t len, const void *data, const char *dumpfile, int add) +void dmi_table_dump(const u8 *buf, u32 len, const char *dumpfile) { - FILE *f; + write_dump(32, len, buf, dumpfile, 0); +} - f = fopen(dumpfile, add ? "r+b" : "wb"); - if(!f) { - fprintf(stderr, "%s: ", dumpfile); - perror("fopen"); - return -1; - } +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; - if(fseek(f, base, SEEK_SET) != 0) { - fprintf(stderr, "%s: ", dumpfile); - perror("fseek"); - goto err_close; - } + buf = read_file(NULL, flags & FLAG_NO_FILE_OFFSET ? 0 : base, + &size, devmem); + len = size; - if(fwrite(data, len, 1, f) != 1) { - fprintf(stderr, "%s: ", dumpfile); - perror("fwrite"); - goto err_close; + if (buf == NULL) + { + printf("read failed\n"); } + dmi_table_dump(buf, len, dumpfile); + free(buf); +} - if(fclose(f)) { - fprintf(stderr, "%s: ", dumpfile); - perror("fclose"); - return -1; - } +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]; - return 0; + dmi_table(((off_t)offset.h << 32) | offset.l,DWORD(buf + 0x0C), 0, ver, devmem, flags | FLAG_STOP_AT_EOT, dumpfile); - err_close: - fclose(f); - return -1; -} + if (!checksum(buf, buf[0x05])) + return 0; + 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; +} -int dumpling(u8 * buf, const char *dumpfile, u8 mode) +static int smbios_decode(u8 *buf, const char *devmem, u32 flags, const char *dumpfile) { - u32 base; - u16 len; - - if(mode == NON_LEGACY) { - if(!checksum(buf, buf[0x05]) || !memcmp(buf + 0x10, "_DMI_", 5) == 0 || - !checksum(buf + 0x10, 0x0F)) - return 0; - base = DWORD(buf + 0x18); - len = WORD(buf + 0x16); - } else { - if(!checksum(buf, 0x0F)) - return 0; - base = DWORD(buf + 0x08); - len = WORD(buf + 0x06); - } + u16 ver; + if (!checksum(buf, buf[0x05]) + || memcmp(buf + 0x10, "_DMI_", 5) != 0 + || !checksum(buf + 0x10, 0x0F)) + return 0; - u8 *buff; + ver = (buf[0x06] << 8) + buf[0x07]; + switch (ver) + { + case 0x021F: + case 0x0221: + ver = 0x0203; + break; + case 0x0233: + ver = 0x0206; + break; + } - if((buff = mem_chunk(NULL, base, len, DEFAULT_MEM_DEV)) != NULL) { - //. Part 1. -#ifdef NDEBUG - printf("# Writing %d bytes to %s.\n", len, dumpfile); -#endif - write_dump(32, len, buff, dumpfile, 0); - free(buff); - //. Part 2. - if(mode != LEGACY) { - u8 crafted[32]; + dmi_table(DWORD(buf + 0x18), WORD(buf + 0x16), WORD(buf + 0x1C), + ver << 8, devmem, flags, dumpfile); - memcpy(crafted, buf, 32); - overwrite_dmi_address(crafted + 0x10); -#ifdef NDEBUG - printf("# Writing %d bytes to %s.\n", crafted[0x05], dumpfile); -#endif - write_dump(0, crafted[0x05], crafted, dumpfile, 1); - } else { - u8 crafted[16]; - - memcpy(crafted, buf, 16); - overwrite_dmi_address(crafted); -#ifdef NDEBUG - printf("# Writing %d bytes to %s.\n", 0x0F, dumpfile); -#endif - write_dump(0, 0x0F, crafted, dumpfile, 1); - } - } else { - fprintf(stderr, "Failed to read table, sorry.\n"); - } + u8 crafted[32]; + memcpy(crafted, buf, 32); + overwrite_dmi_address(crafted + 0x10); + write_dump(0, crafted[0x05], crafted, dumpfile, 1); - //. TODO: Cleanup 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); +} int dump(const char *memdev, const char *dumpfile) { - /* On success, return found, otherwise return -1 */ + /* 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); - if(efi == EFI_NOT_FOUND) { - /* Fallback to memory scan (x86, x86_64) */ - if((buf = mem_chunk(NULL, 0xF0000, 0x10000, memdev)) != NULL) { - for(fp = 0; fp <= 0xFFF0; fp += 16) { - if(memcmp(buf + fp, "_SM_", 4) == 0 && fp <= 0xFFE0) { - if(dumpling(buf + fp, dumpfile, NON_LEGACY)) - found++; - fp += 16; - } else if(memcmp(buf + fp, "_DMI_", 5) == 0) { - if(dumpling(buf + fp, dumpfile, LEGACY)) - found++; - } - } - } else - ret = -1; - } else if(efi == EFI_NO_SMBIOS) { - ret = -1; - } else { - if((buf = mem_chunk(NULL, fp, 0x20, memdev)) == NULL) - ret = -1; - else if(dumpling(buf, dumpfile, NON_LEGACY)) + 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; - if(ret == 0) { - free(buf); - if(!found) { - ret = -1; +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 == 0 ? found : ret; + return ret; } diff --git a/src/dmidump.h b/src/dmidump.h index 3c12248..a025829 100644 --- a/src/dmidump.h +++ b/src/dmidump.h @@ -32,6 +32,13 @@ #define NON_LEGACY 0 #define LEGACY 1 +#define FLAG_NO_FILE_OFFSET (1 << 0) +#define FLAG_STOP_AT_EOT (1 << 1) + +#define SYS_FIRMWARE_DIR "/sys/firmware/dmi/tables" +#define SYS_ENTRY_FILE SYS_FIRMWARE_DIR "/smbios_entry_point" +#define SYS_TABLE_FILE SYS_FIRMWARE_DIR "/DMI" + int dump(const char *memdev, const char *dumpfile); #endif diff --git a/src/util.c b/src/util.c index da97767..4f233ff 100644 --- a/src/util.c +++ b/src/util.c @@ -50,7 +50,6 @@ #include "util.h" #include "dmilog.h" -#ifndef USE_MMAP static int myread(Log_t *logp, int fd, u8 * buf, size_t count, const char *prefix) { ssize_t r = 1; @@ -76,7 +75,6 @@ static int myread(Log_t *logp, int fd, u8 * buf, size_t count, const char *prefi return 0; } -#endif int checksum(const u8 * buf, size_t len) { @@ -88,6 +86,73 @@ int checksum(const u8 * buf, size_t len) return (sum == 0); } +/* + * Reads all of file from given offset, up to max_len bytes. + * A buffer of at most max_len bytes is allocated by this function, and + * needs to be freed by the caller. + * This provides a similar usage model to mem_chunk() + * + * Returns a pointer to the allocated buffer, or NULL on error, and + * sets max_len to the length actually read. + */ +void *read_file(Log_t *logp, off_t base, size_t *max_len, const char *filename) +{ + struct stat statbuf; + int fd; + u8 *p; + /* + * Don't print error message on missing file, as we will try to read + * files that may or may not be present. + */ + if ((fd = open(filename, O_RDONLY)) == -1) + { + if (errno != ENOENT) + perror(filename); + return NULL; + } + + /* + * Check file size, don't allocate more than can be read. + */ + if (fstat(fd, &statbuf) == 0) + { + if (base >= statbuf.st_size) + { + fprintf(stderr, "%s: Can't read data beyond EOF\n", + filename); + p = NULL; + goto out; + } + if (*max_len > (size_t)statbuf.st_size - base) + *max_len = statbuf.st_size - base; + } + + if ((p = malloc(*max_len)) == NULL) + { + perror("malloc"); + goto out; + } + + if (lseek(fd, base, SEEK_SET) == -1) + { + fprintf(stderr, "%s: ", filename); + perror("lseek"); + goto err_free; + } + if (myread(logp, fd, p, *max_len, filename) == 0) + goto out; + +err_free: + free(p); + p = NULL; + +out: + if (close(fd) == -1) + perror(filename); + + return p; +} + /* Static global variables which should only * be used by the sigill_handler() */ @@ -105,6 +170,18 @@ void sigill_handler(int ignore_this) { } } +static void safe_memcpy(void *dest, const void *src, size_t n) +{ +#ifdef USE_SLOW_MEMCPY + size_t i; + + for (i = 0; i < n; i++) + *((u8 *)dest + i) = *((const u8 *)src + i); +#else + memcpy(dest, src, n); +#endif +} + /* * Copy a physical memory chunk into a memory buffer. * This function allocates memory. @@ -115,7 +192,8 @@ void *mem_chunk(Log_t *logp, size_t base, size_t len, const char *devmem) int fd = -1; #ifdef USE_MMAP - size_t mmoffset; + struct stat statbuf; + size_t mmoffset; void *mmp; #endif sigill_logobj = logp; @@ -134,6 +212,23 @@ void *mem_chunk(Log_t *logp, size_t base, size_t len, const char *devmem) goto exit; } #ifdef USE_MMAP + if (sigill_error || fstat(fd, &statbuf) == -1 ) + { + log_append(logp, LOGFL_NORMAL, LOG_WARNING,"fstat: %s", strerror(errno)); + goto err_free; + } + + /* + * mmap() will fail with SIGBUS if trying to map beyond the end of + * the file. + */ + if (sigill_error || S_ISREG(statbuf.st_mode) && base + (off_t)len > statbuf.st_size ) + { + log_append(logp, LOGFL_NORMAL, LOG_WARNING, + "mmap: Can't map beyond end of file %s: %s", + devmem, strerror(errno)); + goto err_free; + } #ifdef _SC_PAGESIZE mmoffset = base % sysconf(_SC_PAGESIZE); #else @@ -147,9 +242,7 @@ void *mem_chunk(Log_t *logp, size_t base, size_t len, const char *devmem) mmp = mmap(0, mmoffset + len, PROT_READ, MAP_SHARED, fd, base - mmoffset); if(sigill_error || (mmp == MAP_FAILED)) { log_append(logp, LOGFL_NORMAL, LOG_WARNING, "%s (mmap): %s", devmem, strerror(errno)); - free(p); - p = NULL; - goto exit; + goto try_read; } memcpy(p, (u8 *) mmp + mmoffset, len); @@ -167,28 +260,34 @@ void *mem_chunk(Log_t *logp, size_t base, size_t len, const char *devmem) p = NULL; goto exit; } -#else /* USE_MMAP */ - if(sigill_error || (lseek(fd, base, SEEK_SET) == -1)) { + goto exit; + +try_read: +#endif /* USE_MMAP */ + if (lseek(fd, base, SEEK_SET) == -1 ) + { log_append(logp, LOGFL_NORMAL, LOG_WARNING, "%s (lseek): %s", devmem, strerror(errno)); - free(p); - p = NULL; - goto exit; + goto err_free; } - if(sigill_error || (myread(logp, fd, p, len, devmem) == -1)) { + if(sigill_error || (myread(logp, fd, p, len, devmem) == 0)) { free(p); p = NULL; goto exit; } -#endif /* USE_MMAP */ - exit: +err_free: + free(p); + p = NULL; + +exit: if (fd >= 0) { if(close(fd) == -1) perror(devmem); } signal(SIGILL, SIG_DFL); sigill_logobj = NULL; + return p; } @@ -207,3 +306,42 @@ u64 u64_range(u64 start, u64 end) return res; } + +int write_dump(size_t base, size_t len, const void *data, const char *dumpfile, int add) +{ + FILE *f; + f = fopen(dumpfile, add ? "r+b" : "wb"); + if (!f) + { + fprintf(stderr, "%s: ", dumpfile); + perror("fopen"); + return -1; + } + + if (fseek(f, base, SEEK_SET) != 0) + { + fprintf(stderr, "%s: ", dumpfile); + perror("fseek"); + goto err_close; + } + + if (fwrite(data, len, 1, f) != 1) + { + fprintf(stderr, "%s: ", dumpfile); + perror("fwrite"); + goto err_close; + } + + if (fclose(f)) + { + fprintf(stderr, "%s: ", dumpfile); + perror("fclose"); + return -1; + } + + return 0; + +err_close: + fclose(f); + return -1; +} diff --git a/src/util.h b/src/util.h index aa0487a..3c803c0 100644 --- a/src/util.h +++ b/src/util.h @@ -27,6 +27,7 @@ #define ARRAY_SIZE(x) (sizeof(x)/sizeof((x)[0])) int checksum(const u8 * buf, size_t len); +void *read_file( Log_t *logp, off_t base, size_t *len, const char *filename); void *mem_chunk(Log_t *logp, size_t base, size_t len, const char *devmem); int write_dump(size_t base, size_t len, const void *data, const char *dumpfile, int add); u64 u64_range(u64 start, u64 end); From fbaab9283729b0de4862bdd774d2cf866bd4ea5f Mon Sep 17 00:00:00 2001 From: Zhongze Hu Date: Mon, 5 Sep 2022 02:14:39 +0800 Subject: [PATCH 04/27] Fix for printing an empty dictionary Currently, python-dmidecode will print an empty dictionary as below: # python3 Python 3.9.13 (main, Jul 25 2022, 00:00:00) [GCC 11.3.1 20220421 (Red Hat 11.3.1-2)] on linux Type "help", "copyright", "credits" or "license" for more information. >>> import dmidecode >>> dmidecode.bios() {} >>> This patch will solve the above issue. Signed-off-by: Zhongze Hu --- src/dmidecode.c | 12 +++++------- src/dmidump.c | 6 +++--- src/efi.c | 5 ++++- src/util.c | 5 +++-- 4 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/dmidecode.c b/src/dmidecode.c index 19958d3..cd9e420 100644 --- a/src/dmidecode.c +++ b/src/dmidecode.c @@ -92,7 +92,7 @@ #include "dmihelper.h" -#define SUPPORTED_SMBIOS_VER 0x0207 +#define SUPPORTED_SMBIOS_VER 0x030300 /******************************************************************************* ** Type-independant Stuff @@ -5197,7 +5197,7 @@ dmi_codes_major *find_dmiMajor(const struct dmi_header *h) return NULL; } -static void dmi_table(Log_t *logp, int type, u32 base, u16 len, u16 num, u16 ver, const char *devmem, u32 flags, xmlNode *xmlnode) +static void dmi_table(Log_t *logp, int type, u32 base, u32 len, u16 num, u32 ver, const char *devmem, u32 flags, xmlNode *xmlnode) { static u8 version_added = 0; u8 *buf; @@ -5241,7 +5241,7 @@ static void dmi_table(Log_t *logp, int type, u32 base, u16 len, u16 num, u16 ver } if (ver > SUPPORTED_SMBIOS_VER){ - log_append(logp, LOGFL_NODUPS, LOG_WARNING, "# SMBIOS implementations newer than version %u.%u are not\n", "# fully supported by this version of dmidecode.\n", SUPPORTED_SMBIOS_VER >> 8, SUPPORTED_SMBIOS_VER & 0xFF); + log_append(logp, LOGFL_NODUPS, LOG_WARNING, "# SMBIOS implementations newer than version %u.%u.%u are not\n fully supported by this version of dmidecode.\n", SUPPORTED_SMBIOS_VER >> 16, (SUPPORTED_SMBIOS_VER >> 8) & 0xFF, SUPPORTED_SMBIOS_VER & 0xFF); } if( version_added == 0 ) { @@ -5250,7 +5250,7 @@ static void dmi_table(Log_t *logp, int type, u32 base, u16 len, u16 num, u16 ver } data = buf; - while(i < num && data + 4 <= buf + len) { /* 4 is the length of an SMBIOS structure header */ + while((i < num||!num) && data + 4 <= buf + len) { /* 4 is the length of an SMBIOS structure header */ u8 *next; struct dmi_header h; @@ -5364,8 +5364,7 @@ xmlNode *smbios3_decode_get_version(u8 * buf, const char *devmem) dmixml_AddAttribute(data_n, "type", "SMBIOS"); if(check == 1) { - u16 ver = (buf[0x07] << 16) + (buf[0x08] << 8) + buf[0x09]; - + u32 ver = (buf[0x07] << 16) + (buf[0x08] << 8) + buf[0x09]; dmixml_AddTextContent(data_n, "SMBIOS %i.%i.%i present", buf[0x07], buf[0x08], buf[0x09]); dmixml_AddAttribute(data_n, "version", "%i.%i.%i", buf[0x07], buf[0x08],buf[0x09]); } else if(check == 0) { @@ -5396,7 +5395,6 @@ int smbios3_decode(Log_t *logp, int type, u8 *buf, const char *devmem, u32 flags { return 0; } - dmi_table(logp, type, ((off_t)offset.h << 32) | offset.l, DWORD(buf+0x0C), 0, ver, devmem, flags | FLAG_STOP_AT_EOT, xmlnode); } diff --git a/src/dmidump.c b/src/dmidump.c index 0d052fc..da0d676 100644 --- a/src/dmidump.c +++ b/src/dmidump.c @@ -96,11 +96,11 @@ static int smbios3_decode(u8 *buf, const char *devmem, u32 flags, const char *du offset = QWORD(buf + 0x10); ver = (buf[0x07] << 16) + (buf[0x08] << 8) + buf[0x09]; - dmi_table(((off_t)offset.h << 32) | offset.l,DWORD(buf + 0x0C), 0, ver, devmem, flags | FLAG_STOP_AT_EOT, dumpfile); - - if (!checksum(buf, buf[0x05])) + 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); diff --git a/src/efi.c b/src/efi.c index ae8d0db..362e2f9 100644 --- a/src/efi.c +++ b/src/efi.c @@ -49,6 +49,7 @@ int address_from_efi(Log_t *logp, size_t * address) FILE *efi_systab; const char *filename = NULL; char linebuf[64]; + const char *eptype; int ret; *address = 0; /* Prevent compiler warning */ @@ -67,8 +68,10 @@ int address_from_efi(Log_t *logp, size_t * address) char *addrp = strchr(linebuf, '='); *(addrp++) = '\0'; - if(strcmp(linebuf, "SMBIOS") == 0) { + if(strcmp(linebuf, "SMBIOS3") == 0 + || strcmp(linebuf, "SMBIOS") == 0) { *address = strtoul(addrp, NULL, 0); + eptype = linebuf; ret = 0; break; } diff --git a/src/util.c b/src/util.c index 4f233ff..465376e 100644 --- a/src/util.c +++ b/src/util.c @@ -239,13 +239,14 @@ void *mem_chunk(Log_t *logp, size_t base, size_t len, const char *devmem) * but to workaround problems many people encountered when trying * to read from /dev/mem using regular read() calls. */ - mmp = mmap(0, mmoffset + len, PROT_READ, MAP_SHARED, fd, base - mmoffset); + mmp = mmap(NULL, mmoffset + len, PROT_READ, MAP_SHARED, fd, base - mmoffset); if(sigill_error || (mmp == MAP_FAILED)) { log_append(logp, LOGFL_NORMAL, LOG_WARNING, "%s (mmap): %s", devmem, strerror(errno)); goto try_read; } - memcpy(p, (u8 *) mmp + mmoffset, len); + safe_memcpy(p, (u8 *) mmp + mmoffset, len); + if (sigill_error) { log_append(logp, LOGFL_NODUPS, LOG_WARNING, "Failed to do memcpy() due to SIGILL signal"); From 2ff3641933ca9fb732f6bcd3d3dd09946f88f7d7 Mon Sep 17 00:00:00 2001 From: Zhongze Hu Date: Wed, 7 Sep 2022 19:33:38 +0800 Subject: [PATCH 05/27] Update python-dmidecode to smbios 3.3.0 1. Update case 1 to case 42 to smbios 3.3.0; 2. Add case 43 for TPM device and Redfish; 3. Add case 43 in pymap file; 4. Using OUT_OF_SPEC Macro for outofspec string; 5. Modify smbios version to 0x030300 6. Test this commit by private/dumpfiles --- src/dmidecode.c | 1342 +++++++++++++++++++++++++++++++++++++++-------- src/dmidecode.h | 3 +- src/pymap.xml | 3 + 3 files changed, 1130 insertions(+), 218 deletions(-) diff --git a/src/dmidecode.c b/src/dmidecode.c index cd9e420..0eeb1ac 100644 --- a/src/dmidecode.c +++ b/src/dmidecode.c @@ -79,6 +79,7 @@ #include #include #include +#include #include "version.h" #include "config.h" @@ -93,11 +94,24 @@ #include "dmihelper.h" #define SUPPORTED_SMBIOS_VER 0x030300 +#define OUT_OF_SPEC "outofspec" /******************************************************************************* ** Type-independant Stuff */ +/* Returns 1 if the buffer contains only printable ASCII characters */ +int is_printable(const u8 *data, int len) +{ + int i; + + for (i = 0; i < len; i++) + if (data[i] < 32 || data[i] >= 127) + return 0; + + return 1; +} + const char *dmi_string(const struct dmi_header *dm, u8 s) { char *bp = (char *)dm->data; @@ -177,11 +191,12 @@ xmlNode *dmi_smbios_structure_type(xmlNode *node, u8 code) {"Additional Information", "AdditionalInfo", NULL, NULL}, {"Onboard Device", "OnboardDevice", NULL, NULL}, /* 41 */ {"Management Controller Host Interface", "MgmntCtrltHostIntf", NULL, NULL}, /* 42 */ + {"TPM Device", "TPMDevice", NULL, NULL}, /* 43 */ /* *INDENT-ON* */ }; xmlNode *type_n = NULL; - if(code <= 42) { + if(code <= 43) { type_n = xmlNewChild(node, NULL, (xmlChar *)types[code].tagname, NULL); assert( type_n != NULL ); @@ -191,6 +206,10 @@ xmlNode *dmi_smbios_structure_type(xmlNode *node, u8 code) if( (types[code].attrname != NULL) && (types[code].attrvalue != NULL) ) { dmixml_AddAttribute(type_n, types[code].attrname, "%s", types[code].attrvalue); } + } else if (code >= 128) { + type_n = xmlNewChild(node, NULL, (xmlChar *)"OEMspecific", NULL); + assert( type_n != NULL ); + dmixml_AddAttribute(type_n, "flags", "0x%04x", code); } else { type_n = xmlNewChild(node, NULL, (xmlChar *) "UnknownSMBiosType", NULL); dmixml_AddAttribute(type_n, "flags", "0x%04x", code); @@ -307,8 +326,6 @@ static void dmi_add_memory_size(xmlNode *node, u64 code, int shift) } - - /******************************************************************************* ** 7.1 BIOS Information (Type 0) */ @@ -328,6 +345,30 @@ void dmi_bios_runtime_size(xmlNode *node, u32 code) } } +void dmi_bios_rom_size(xmlNode *node, u8 code1, u16 code2) +{ + static const char *unit[4] = { + "MB", "GB" + }; + + xmlNode *brz_n = xmlNewChild(node, NULL, (xmlChar *)"ROMSize", NULL); + dmixml_AddAttribute(brz_n, "flags", "0x%04x", code1); + + if (code1 != 0xFF) + { + u64 s = { .l = (code1 + 1) << 6}; + dmi_add_memory_size(brz_n, s, 1); + }else{ + if ( (code2 >> 14) <= 0x02 ){ + dmixml_AddAttribute(brz_n, "unit", unit[code2 >> 14]); + dmixml_AddTextContent(brz_n, "%i", code2 & 0x3FFF); + }else{ + dmixml_AddAttribute(brz_n, OUT_OF_SPEC, "1"); + } + + } +} + /* 7.1.1 */ void dmi_bios_characteristics(xmlNode *node, u64 code) { @@ -500,7 +541,7 @@ void dmi_system_wake_up_type(xmlNode *node, u8 code) if(code <= 0x08) { dmixml_AddTextContent(swut_n, type[code]); } else { - dmixml_AddAttribute(swut_n, "outofspec", "1"); + dmixml_AddAttribute(swut_n, OUT_OF_SPEC, "1"); } } @@ -620,7 +661,14 @@ void dmi_chassis_type(xmlNode *node, u8 code) "CompactPCI", "AdvancedTCA", /* 0x1B */ "Blade", - "Blade Enclosing" /* 0x1D */ + "Blade Enclosing", /* 0x1D */ + "Tablet", + "Convertible", + "Detachable", + "IoT Gateway", + "Embedded PC", + "Mini PC", + "Stick PC" /* 0x24 */ }; xmlNode *type_n = xmlNewChild(node, NULL, (xmlChar *)"ChassisType", NULL); assert( type_n != NULL ); @@ -629,7 +677,7 @@ void dmi_chassis_type(xmlNode *node, u8 code) code &= 0x7F; /* bits 6:0 are chassis type, 7th bit is the lock bit */ - if(code >= 0x01 && code <= 0x1B) { + if(code >= 0x01 && code <= 0x24) { dmixml_AddAttribute(type_n, "available", "1"); dmixml_AddTextContent(type_n, "%s", type[code - 0x01]); } else { @@ -691,7 +739,7 @@ void dmi_chassis_security_status(xmlNode *node, u8 code) if(code >= 0x01 && code <= 0x05) { dmixml_AddTextContent(secstat_n, "%s", status[code - 0x01]); } else { - dmixml_AddAttribute(secstat_n, "unavailable", "1"); + dmixml_AddAttribute(secstat_n, OUT_OF_SPEC, "1"); } } @@ -701,7 +749,7 @@ void dmi_chassis_height(xmlNode *node, u8 code) assert( hght_n != NULL ); if(code == 0x00) { - dmixml_AddAttribute(hght_n, "unspecified", "1"); + dmixml_AddAttribute(hght_n, OUT_OF_SPEC, "1"); } else { dmixml_AddAttribute(hght_n, "unit", "U"); dmixml_AddTextContent(hght_n, "%i", code); @@ -714,7 +762,7 @@ void dmi_chassis_power_cords(xmlNode *node, u8 code) assert( pwrc_n != NULL ); if(code == 0x00) { - dmixml_AddAttribute(pwrc_n, "unspecified", "1"); + dmixml_AddAttribute(pwrc_n, OUT_OF_SPEC, "1"); } else { dmixml_AddTextContent(pwrc_n, "%i", code); } @@ -771,7 +819,7 @@ void dmi_processor_type(xmlNode *node, u8 code) if(code >= 0x01 && code <= 0x06) { dmixml_AddTextContent(proct_n, type[code - 0x01]); } else { - dmixml_AddAttribute(proct_n, "outofspec", "1"); + dmixml_AddAttribute(proct_n, OUT_OF_SPEC, "1"); } } @@ -829,6 +877,10 @@ void dmi_processor_family(xmlNode *node, const struct dmi_header *h, u16 ver) { 0x29, "Core Duo Mobile" }, { 0x2A, "Core Solo Mobile" }, { 0x2B, "Atom" }, + { 0x2C, "Core M" }, + { 0x2D, "Core m3" }, + { 0x2E, "Core m5" }, + { 0x2F, "Core m7" }, { 0x30, "Alpha" }, { 0x31, "Alpha 21064" }, @@ -880,6 +932,12 @@ void dmi_processor_family(xmlNode *node, const struct dmi_header *h, u16 ver) { 0x63, "68010" }, { 0x64, "68020" }, { 0x65, "68030" }, + { 0x66, "Athlon X4" }, + { 0x67, "Opteron X1000" }, + { 0x68, "Opteron X2000" }, + { 0x69, "Opteron A-Series" }, + { 0x6A, "Opteron X3000" }, + { 0x6B, "Zen" }, { 0x70, "Hobbit" }, @@ -992,6 +1050,8 @@ void dmi_processor_family(xmlNode *node, const struct dmi_header *h, u16 ver) { 0xFA, "i860" }, { 0xFB, "i960" }, + { 0x100, "ARMv7" }, + { 0x101, "ARMv8" }, { 0x104, "SH-3" }, { 0x105, "SH-4" }, @@ -1007,6 +1067,9 @@ void dmi_processor_family(xmlNode *node, const struct dmi_header *h, u16 ver) { 0x15E, "DSP" }, { 0x1F4, "Video Processor" }, + { 0x200, "RV32" }, + { 0x201, "RV64" }, + { 0x202, "RV128" } /* *INDENT-ON* */ }; @@ -1071,7 +1134,7 @@ void dmi_processor_family(xmlNode *node, const struct dmi_header *h, u16 ver) } if(low == high) { /* Not found */ - dmixml_AddAttribute(family_n, "outofspec", "1"); + dmixml_AddAttribute(family_n, OUT_OF_SPEC, "1"); return; } @@ -1081,7 +1144,7 @@ void dmi_processor_family(xmlNode *node, const struct dmi_header *h, u16 ver) low = i + 1; } - dmixml_AddAttribute(family_n, "outofspec", "1"); + dmixml_AddAttribute(family_n, OUT_OF_SPEC, "1"); } xmlNode *dmi_processor_id(xmlNode *node, const struct dmi_header *h) @@ -1134,7 +1197,7 @@ xmlNode *dmi_processor_id(xmlNode *node, const struct dmi_header *h) assert( data_n != NULL ); assert( h && h->data ); - type = h->data[0x06]; + type = (h->data[0x06] == 0xFE && h->length >=0x2A) ? WORD(h->data+0x28) : h->data[0x06]; p = h->data + 8; version = (char *) dmi_string(h, h->data[0x10]); @@ -1186,6 +1249,21 @@ xmlNode *dmi_processor_id(xmlNode *node, const struct dmi_header *h) dx & 0xF); return data_n; } + } else if ( (type >= 0x100 && type <= 0x101) /* ARM */ + || (type >= 0x118 && type <= 0x119)) /* ARM */ + { + u32 midr = DWORD(p); + /* + * The format of this field was not defined for ARM processors + * before version 3.1.0 of the SMBIOS specification, so we + * silently skip it if it reads all zeroes. + */ + if (midr == 0) + return data_n; + dmixml_AddTextChild(data_n, "Signature", + "Implementor 0x%02x, Variant 0x%x, Architecture %i, Part 0x%03x, Revision %i", + midr >> 24, (midr >> 20) & 0xF, (midr >> 16) & 0xF, (midr >> 4) & 0xFFF, midr & 0xF); + return data_n; } else if( (type >= 0x0B && type <= 0x15) /* Intel, Cyrix */ ||(type >= 0x28 && type <= 0x2B) /* Intel */ ||(type >= 0xA1 && type <= 0xB3) /* Intel */ @@ -1197,14 +1275,14 @@ xmlNode *dmi_processor_id(xmlNode *node, const struct dmi_header *h) ) { sig = 1; - - } else if((type >= 0x18 && type <= 0x1D) /* AMD */ - ||type == 0x1F /* AMD */ - ||(type >= 0x38 && type <= 0x3E) /* AMD */ - ||(type >= 0x46 && type <= 0x49) /* AMD */ - ||(type >= 0x83 && type <= 0x8F) /* AMD */ - ||(type >= 0xB6 && type <= 0xB7) /* AMD */ - ||(type >= 0xE6 && type <= 0xEF) /* AMD */ + } else if((type >= 0x18 && type <= 0x1D) /* AMD */ + ||type == 0x1F /* AMD */ + ||(type >= 0x38 && type <= 0x3F) /* AMD */ + ||(type >= 0x46 && type <= 0x4F) /* AMD */ + ||(type >= 0x66 && type <= 0x6B) /* AMD */ + ||(type >= 0x83 && type <= 0x8F) /* AMD */ + ||(type >= 0xB6 && type <= 0xB7) /* AMD */ + ||(type >= 0xE6 && type <= 0xEF) /* AMD */ ) { sig = 2; @@ -1236,14 +1314,21 @@ xmlNode *dmi_processor_id(xmlNode *node, const struct dmi_header *h) return data_n; } + /* + * Extra flags are now returned in the ECX register when one calls + * the CPUID instruction. Their meaning is explained in table 3-5, but + * DMI doesn't support this yet. + */ eax = DWORD(p); edx = DWORD(p + 4); switch (sig) { case 1: /* Intel */ dmixml_AddTextChild(data_n, "Signature", "Type %i, Family %i, Model %i, Stepping %i", - (eax >> 12) & 0x3, ((eax >> 20) & 0xFF) + ((eax >> 8) & 0x0F), - ((eax >> 12) & 0xF0) + ((eax >> 4) & 0x0F), eax & 0xF); + (eax >> 12) & 0x3, + ((eax >> 20) & 0xFF) + ((eax >> 8) & 0x0F), + ((eax >> 12) & 0xF0) + ((eax >> 4) & 0x0F), + eax & 0xF); break; case 2: /* AMD, publication #25481 revision 2.28 */ dmixml_AddTextChild(data_n, "Signature", @@ -1290,7 +1375,7 @@ void dmi_processor_voltage(xmlNode *node, u8 code) if(code & 0x80) { xmlNode *v_n = dmixml_AddTextChild(vltg_n, "Voltage", "%.1f", (float)(code & 0x7f) / 10); dmixml_AddAttribute(v_n, "unit", "V"); - } else if( code == 0x00 ) { + } else if( (code & 0x07 ) == 0x00 ) { dmixml_AddAttribute(vltg_n, "unknown_value", "1"); } else { for(i = 0; i <= 2; i++) { @@ -1333,7 +1418,7 @@ void dmi_processor_status(xmlNode *node, u8 code) } else if( code == 0x07 ) { dmixml_AddTextContent(prst_n, "%s", status[5]); } else { - dmixml_AddAttribute(prst_n, "outofspec", "1"); + dmixml_AddAttribute(prst_n, OUT_OF_SPEC, "1"); } } @@ -1384,18 +1469,33 @@ void dmi_processor_upgrade(xmlNode *node, u8 code) "Socket FM1", "Socket FM2", "Socket LGA2011-3", - "Socket LGA1356-3" /* 0x2C */ - + "Socket LGA1356-3", /* 0x2C */ + "Socket LGA1150", + "Socket BGA1168", + "Socket BGA1234", + "Socket BGA1364", + "Socket AM4", + "Socket LGA1151", + "Socket BGA1356", + "Socket BGA1440", + "Socket BGA1515", + "Socket LGA3647-1", + "Socket SP3", + "Socket SP3r2", + "Socket LGA2066", + "Socket BGA1392", + "Socket BGA1510", + "Socket BGA1528" /* 0x3C */ }; xmlNode *upgr_n = xmlNewChild(node, NULL, (xmlChar *) "Upgrade", NULL); assert( upgr_n != NULL ); dmixml_AddAttribute(upgr_n, "dmispec", "7.5.5"); dmixml_AddAttribute(upgr_n, "flags", "0x%04x", code); - if(code >= 0x01 && code <= 0x2A) { + if(code >= 0x01 && code <= 0x3C) { dmixml_AddTextContent(upgr_n, "%s", upgrade[code - 0x01]); } else { - dmixml_AddAttribute(upgr_n, "outofspec", "1"); + dmixml_AddAttribute(upgr_n, OUT_OF_SPEC, "1"); } } @@ -1474,7 +1574,7 @@ void dmi_memory_controller_ed_method(xmlNode *node, u8 code) if(code >= 0x01 && code <= 0x08) { dmixml_AddTextContent(ercm_n, method[code - 0x01]); } else { - dmixml_AddAttribute(ercm_n, "outofspec", "1"); + dmixml_AddAttribute(ercm_n, OUT_OF_SPEC, "1"); } } @@ -1527,7 +1627,7 @@ void dmi_memory_controller_interleave(xmlNode *node, const char *tagname, u8 cod if(code >= 0x01 && code <= 0x07) { dmixml_AddTextContent(mci_n, interleave[code - 0x01]); } else { - dmixml_AddAttribute(mci_n, "outofspec", "1"); + dmixml_AddAttribute(mci_n, OUT_OF_SPEC, "1"); } } @@ -1681,19 +1781,17 @@ void dmi_memory_module_error(xmlNode *node, u8 code) { xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) "ModuleErrorStatus", NULL); assert( data_n != NULL ); + static const char *status[] = { + "OK", /* 0x00 */ + "Uncorrectable Errors", + "Correctable Errors", + "Correctable and Uncorrectable Errors" /* 0x03 */ + }; dmixml_AddAttribute(data_n, "flags", "0x%04x", code); if( !(code & (1 << 2)) ) { - if((code & 0x03) == 0) { - dmixml_AddAttribute(data_n, "Error", "1"); - } - if(code & (1 << 0)) { - dmixml_AddTextContent(data_n, "Uncorrectable Errors"); - } - if(code & (1 << 1)) { - dmixml_AddTextContent(data_n, "Correctable Errors"); - } + dmixml_AddAttribute(data_n, "Error Status", "%s", status[code & 0x03]); } } @@ -1729,24 +1827,36 @@ void dmi_cache_location(xmlNode *node, u8 code) if(location[code] != NULL) { dmixml_AddTextContent(data_n, location[code]); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } -void dmi_cache_size(xmlNode *node, const char *tagname, u16 code) +void dmi_cache_size_2(xmlNode *node, const char *tagname, u32 code) { - xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) tagname, NULL); - assert( data_n != NULL ); - dmixml_AddAttribute(data_n, "dmispec", "7.8"); - dmixml_AddAttribute(data_n, "flags", "0x%04x", code); + xmlNode *caches_n = xmlNewChild(node, NULL, (xmlChar *)tagname, NULL); + assert(caches_n != NULL); + dmixml_AddAttribute(caches_n, "dmispec", "7.8"); + dmixml_AddAttribute(caches_n, "flags", "0x%04x", code); - if(code & 0x8000) { - dmixml_AddAttribute(data_n, "unit", "KB"); - dmixml_AddTextContent(data_n, "%i", (code & 0x7FFF) << 6); + u64 size; + if (code & 0x80000000){ + code &= 0x7FFFFFFFLU; + size.l = code << 6; + size.h = code >> 26; } else { - dmixml_AddAttribute(data_n, "unit", "KB"); - dmixml_AddTextContent(data_n, "%i", code); + dmixml_AddAttribute(caches_n, "unit", "KB"); + dmixml_AddTextContent(caches_n, "%i", code); + size.l = code; + size.h = 0; } + + /* Use a more convenient unit for large cache size */ + dmi_add_memory_size(caches_n, size, 1); +} + +void dmi_cache_size(xmlNode *node, const char *tagname, u16 code) +{ + dmi_cache_size_2(node, tagname, (((u32)code & 0x8000LU) << 16) | (code & 0x7FFFLU)); } /* 7.8.2 */ @@ -1798,7 +1908,7 @@ void dmi_cache_ec_type(xmlNode *node, u8 code) if(code >= 0x01 && code <= 0x06) { dmixml_AddTextContent(data_n, type[code - 0x01]); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } @@ -1820,7 +1930,7 @@ void dmi_cache_type(xmlNode *node, u8 code) if(code >= 0x01 && code <= 0x05) { dmixml_AddTextContent(data_n, type[code - 0x01]); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } @@ -1851,7 +1961,7 @@ void dmi_cache_associativity(xmlNode *node, u8 code) if(code >= 0x01 && code <= 0x0E) { dmixml_AddTextContent(data_n, type[code - 0x01]); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } @@ -1897,7 +2007,8 @@ void dmi_port_connector_type(xmlNode *node, const char *tpref, u8 code) "Mini Jack (headphones)", "BNC", "IEEE 1394", - "SAS/SATA Plug Receptacle" /* 0x22 */ + "SAS/SATA Plug Receptacle", /* 0x22 */ + "USB Type-C Receptacle" /* 0x23 */ }; static const char *type_0xA0[] = { "PC-98", /* 0xA0 */ @@ -1913,14 +2024,14 @@ void dmi_port_connector_type(xmlNode *node, const char *tpref, u8 code) dmixml_AddAttribute(data_n, "flags", "0x%04x", code); dmixml_AddAttribute(data_n, "type", "%s", tpref); - if(code <= 0x22) { + if(code <= 0x23) { dmixml_AddTextContent(data_n, type[code]); } else if(code >= 0xA0 && code <= 0xA4) { dmixml_AddTextContent(data_n, type_0xA0[code - 0xA0]); } else if(code == 0xFF) { dmixml_AddTextContent(data_n, "Other"); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } @@ -1980,7 +2091,7 @@ void dmi_port_type(xmlNode *node, u8 code) } else if(code == 0xFF) { dmixml_AddTextContent(data_n, "Other"); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } @@ -2010,8 +2121,29 @@ void dmi_slot_type(xmlNode *node, u8 code) "AGP 2x", "AGP 4x", "PCI-X", - "AGP 8x" /* 0x13 */ + "AGP 8x", /* 0x13 */ + "M.2 Socket 1-DP", + "M.2 Socket 1-SD", + "M.2 Socket 2", + "M.2 Socket 3", + "MXM Type I", + "MXM Type II", + "MXM Type III", + "MXM Type III-HE", + "MXM Type IV", + "MXM 3.0 Type A", + "MXM 3.0 Type B", + "PCI Express 2 SFF-8639", + "PCI Express 3 SFF-8639", + "PCI Express Mini 52-pin with bottom-side keep-outs", + "PCI Express Mini 52-pin without bottom-side keep-outs", + "PCI Express Mini 76-pin" /* 0x23 */ + }; + + static const char *type_0x30[] = { + "CXL FLexbus 1.0" /* 0x30 */ }; + static const char *type_0xA0[] = { "PC-98/C20", /* 0xA0 */ "PC-98/C24", @@ -2035,19 +2167,30 @@ void dmi_slot_type(xmlNode *node, u8 code) "PCI Express 3 x2", "PCI Express 3 x4", "PCI Express 3 x8", - "PCI Express 3 x16" /* 0xB6 */ + "PCI Express 3 x16", /* 0xB6 */ + NULL, /* 0xB7 */ + "PCI Express 4", + "PCI Express 4 x1", + "PCI Express 4 x2", + "PCI Express 4 x4", + "PCI Express 4 x8", + "PCI Express 4 x16" /* 0xBD */ }; xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) "SlotType", NULL); assert( data_n != NULL ); dmixml_AddAttribute(data_n, "dmispec", "7.10.1"); dmixml_AddAttribute(data_n, "flags", "0x%04x", code); - if(code >= 0x01 && code <= 0x13) { + if(code >= 0x01 && code <= 0x23) { dmixml_AddTextContent(data_n, "%s", type[code - 0x01]); - } else if(code >= 0xA0 && code <= 0xB6) { + } else if (code == 0x30){ + dmixml_AddTextContent(data_n, "%s", type_0x30[code - 0x30]); + } else if (code >= 0xA0 && code <= 0xB6) { dmixml_AddTextContent(data_n, "%s", type_0xA0[code - 0xA0]); + } else if (code >= 0xB8 && code <= 0xBD) { + dmixml_AddTextContent(data_n, "%s", type_0xA0[code - 0xB8]); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } @@ -2078,7 +2221,7 @@ void dmi_slot_bus_width(xmlNode *node, u8 code) if( (code >= 0x01) && (code <= 0x0E) ) { dmixml_AddTextContent(data_n, "%s", width[code - 0x01]); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } @@ -2089,7 +2232,8 @@ void dmi_slot_current_usage(xmlNode *node, u8 code) "Other", /* 0x01 */ "Unknown", "Available", - "In Use" /* 0x04 */ + "In Use", /* 0x04 */ + "Unavailable" /* 0x05 */ }; xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) "CurrentUsage", NULL); @@ -2098,10 +2242,10 @@ void dmi_slot_current_usage(xmlNode *node, u8 code) dmixml_AddAttribute(data_n, "flags", "0x%04x", code); - if(code >= 0x01 && code <= 0x04) { + if(code >= 0x01 && code <= 0x05) { dmixml_AddTextContent(data_n, usage[code - 0x01]); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } @@ -2112,7 +2256,9 @@ void dmi_slot_length(xmlNode *node, u8 code) "Other", /* 0x01 */ "Unknown", "Short", - "Long" /* 0x04 */ + "Long", /* 0x04 */ + "2.5\" drive form factor", + "3.5\" drive form factor" /* 0x06 */ }; xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) "SlotLength", NULL); @@ -2120,15 +2266,15 @@ void dmi_slot_length(xmlNode *node, u8 code) dmixml_AddAttribute(data_n, "dmispec", "7.10.4"); dmixml_AddAttribute(data_n, "flags", "0x%04x", code); - if(code >= 0x01 && code <= 0x04) { + if(code >= 0x01 && code <= 0x06) { dmixml_AddTextContent(data_n, length[code - 0x01]); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } /* 7.10.5 */ -void inline set_slottype(xmlNode *node, u8 type) { +void set_slottype(xmlNode *node, u8 type) { switch (type) { case 0x04: /* MCA */ dmixml_AddAttribute(node, "slottype", "MCA"); @@ -2149,6 +2295,11 @@ void inline set_slottype(xmlNode *node, u8 type) { case 0x12: /* PCI-X */ dmixml_AddAttribute(node, "slottype", "PCI-X"); break; + case 0x21: /* PCI Express Mini */ + case 0x22: /* PCI Express Mini */ + case 0x23: /* PCI Express Mini */ + dmixml_AddAttribute(node, "slottype", "PCI Express Mini"); + break; case 0xA5: /* PCI Express */ case 0xA6: /* PCI Express */ case 0xA7: /* PCI Express */ @@ -2157,6 +2308,7 @@ void inline set_slottype(xmlNode *node, u8 type) { case 0xAA: /* PCI Express */ dmixml_AddAttribute(node, "slottype", "PCI Express"); break; + case 0x1F: /* PCI Express 2*/ case 0xAB: /* PCI Express 2*/ case 0xAC: /* PCI Express 2*/ case 0xAD: /* PCI Express 2*/ @@ -2165,6 +2317,23 @@ void inline set_slottype(xmlNode *node, u8 type) { case 0xB0: /* PCI Express 2*/ dmixml_AddAttribute(node, "slottype", "PCI Express 2"); break; + case 0x20: /* PCI Express 3 */ + case 0xB1: /* PCI Express 3 */ + case 0xB2: /* PCI Express 3 */ + case 0xB3: /* PCI Express 3 */ + case 0xB4: /* PCI Express 3 */ + case 0xB5: /* PCI Express 3 */ + case 0xB6: /* PCI Express 3 */ + dmixml_AddAttribute(node, "slottype", "PCI Express 3"); + break; + case 0xB8: /* PCI Express 4 */ + case 0xB9: /* PCI Express 4 */ + case 0xBA: /* PCI Express 4 */ + case 0xBB: /* PCI Express 4 */ + case 0xBC: /* PCI Express 4 */ + case 0xBD: /* PCI Express 4 */ + dmixml_AddAttribute(node, "slottype", "PCI Express 4"); + break; case 0x07: /* PCMCIA */ dmixml_AddAttribute(node, "slottype", "PCMCIA"); break; @@ -2187,30 +2356,47 @@ void dmi_slot_id(xmlNode *node, u8 code1, u8 code2, u8 type) case 0x05: /* EISA */ dmixml_AddAttribute(slotid_n, "id", "%i", code1); break; - case 0x06: /* PCI */ - case 0x0E: /* PCI */ - case 0x0F: /* AGP */ - case 0x10: /* AGP */ - case 0x11: /* AGP */ - case 0x12: /* PCI-X */ - case 0x13: /* AGP */ - case 0xA5: /* PCI Express */ - case 0xA6: /* PCI Express */ - case 0xA7: /* PCI Express */ - case 0xA8: /* PCI Express */ - case 0xA9: /* PCI Express */ - case 0xAA: /* PCI Express */ - case 0xAB: /* PCI Express 2 */ - case 0xAC: /* PCI Express 2 */ - case 0xAD: /* PCI Express 2 */ - case 0xAE: /* PCI Express 2 */ - case 0xAF: /* PCI Express 2 */ - case 0xB0: /* PCI Express 2 */ + case 0x06: /* PCI */ + case 0x0E: /* PCI */ + case 0x0F: /* AGP */ + case 0x10: /* AGP */ + case 0x11: /* AGP */ + case 0x12: /* PCI-X */ + case 0x13: /* AGP */ + case 0x1F: /* PCI Express 2 */ + case 0x20: /* PCI Express 3 */ + case 0x21: /* PCI Express Mini */ + case 0x22: /* PCI Express Mini */ + case 0x23: /* PCI Express Mini */ + case 0xA5: /* PCI Express */ + case 0xA6: /* PCI Express */ + case 0xA7: /* PCI Express */ + case 0xA8: /* PCI Express */ + case 0xA9: /* PCI Express */ + case 0xAA: /* PCI Express */ + case 0xAB: /* PCI Express 2 */ + case 0xAC: /* PCI Express 2 */ + case 0xAD: /* PCI Express 2 */ + case 0xAE: /* PCI Express 2 */ + case 0xAF: /* PCI Express 2 */ + case 0xB0: /* PCI Express 2 */ + case 0xB1: /* PCI Express 3 */ + case 0xB2: /* PCI Express 3 */ + case 0xB3: /* PCI Express 3 */ + case 0xB4: /* PCI Express 3 */ + case 0xB5: /* PCI Express 3 */ + case 0xB6: /* PCI Express 3 */ + case 0xB8: /* PCI Express 4 */ + case 0xB9: /* PCI Express 4 */ + case 0xBA: /* PCI Express 4 */ + case 0xBB: /* PCI Express 4 */ + case 0xBC: /* PCI Express 4 */ + case 0xBD: /* PCI Express 4 */ dmixml_AddAttribute(slotid_n, "id", "%i", code1); break; case 0x07: /* PCMCIA */ dmixml_AddAttribute(slotid_n, "adapter", "%i", code1); - dmixml_AddAttribute(slotid_n, "id", "%i", code2); + dmixml_AddAttribute(slotid_n, "socket", "%i", code2); break; default: break; @@ -2235,8 +2421,10 @@ void dmi_slot_characteristics(xmlNode *node, u8 code1, u8 code2) static const char *characteristics2[] = { "PME signal is supported", /* 0 */ "Hot-plug devices are supported", - "SMBus signal is supported" /* 2 */ + "SMBus signal is supported", /* 2 */ + "PCIe slot bifurcation is supported" /* 3 */ }; + xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) "SlotCharacteristics", NULL); assert( data_n != NULL ); dmixml_AddAttribute(data_n, "dmispec", "7.10.6, 7.10.7"); @@ -2258,7 +2446,7 @@ void dmi_slot_characteristics(xmlNode *node, u8 code1, u8 code2) c_n = NULL; } } - for(i = 0; i <= 2; i++) { + for(i = 0; i <= 3; i++) { if(code2 & (1 << i)) { xmlNode *c_n = dmixml_AddTextChild(data_n, "Characteristic", "%s", characteristics2[i]); @@ -2281,6 +2469,23 @@ void dmi_slot_segment_bus_func(xmlNode *node, u16 code1, u8 code2, u8 code3) } } +void dmi_slot_peers(xmlNode *node, u8 n, const u8 *data, struct dmi_header *h) +{ + xmlNode *sp_n = xmlNewChild(node, NULL, (xmlChar *)"Peerdevices", NULL); + assert(sp_n != NULL); + + int i; + for (i = 1; i <= n; i++, data += 5){ + xmlNode *dev_n = dmixml_AddDMIstring(sp_n, "device", h, i); + + dmixml_AddAttribute(dev_n, "index", "%i", i); + dmixml_AddTextContent(dev_n, "%04x:%02x:%02x.%x (Width %u)", + WORD(data), data[2], data[3] >> 3, data[3] & 0x07, data[4]); + dev_n = NULL; + } +} + + /******************************************************************************* ** 7.11 On Board Devices Information (Type 10) */ @@ -2307,7 +2512,7 @@ void dmi_on_board_devices_type(xmlNode *node, u8 code) if(code >= 0x01 && code <= 0x0A) { dmixml_AddTextChild(node, "Type", "%s", type[code - 0x01]); } else { - dmixml_AddAttribute(node, "outofspec", "1"); + dmixml_AddAttribute(node, OUT_OF_SPEC, "1"); } } @@ -2402,6 +2607,14 @@ void dmi_bios_languages(xmlNode *node, struct dmi_header *h, u8 brevity_code) } } +static const char *dmi_bios_language_format(u8 code) +{ + if (code & 0x01) + return "Abbreviated"; + else + return "Long"; +} + /******************************************************************************* ** 7.15 Group Associations (Type 14) */ @@ -2446,7 +2659,7 @@ void dmi_event_log_method(xmlNode *node, u8 code) dmixml_AddTextContent(data_n, "OEM-specific"); dmixml_AddAttribute(data_n, "unknown", "1"); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } @@ -2513,7 +2726,7 @@ void dmi_event_log_header_type(xmlNode *node, u8 code) } else if(code >= 0x80) { dmixml_AddTextContent(data_n, "OEM-specific"); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } @@ -2559,7 +2772,7 @@ void dmi_event_log_descriptor_type(xmlNode *node, u8 code) } else if(code == 0xFF) { dmixml_AddTextContent(data_n, "End of log"); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } @@ -2586,7 +2799,7 @@ void dmi_event_log_descriptor_format(xmlNode *node, u8 code) } else if(code >= 0x80) { dmixml_AddTextContent(data_n, "OEM-specific"); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } @@ -2628,11 +2841,12 @@ void dmi_memory_array_location(xmlNode *node, u8 code) "NuBus" /* 0x0A, master.mif says 16 */ }; static const char *location_0xA0[] = { - "PC-98/C20 Add-on Card", /* 0xA0 */ - "PC-98/C24 Add-on Card", - "PC-98/E Add-on Card", - "PC-98/Local Bus Add-on Card", - "PC-98/Card Slot Add-on Card" /* 0xA4, from master.mif */ + "PC-98/C20 Add-on Card", /* 0xA0 */ + "PC-98/C24 Add-on Card", + "PC-98/E Add-on Card", + "PC-98/Local Bus Add-on Card", + "PC-98/Card Slot Add-on Card", + "CXL Flexbus 1.0" /* 0xA4, from master.mif */ }; xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) "Location", NULL); @@ -2642,10 +2856,10 @@ void dmi_memory_array_location(xmlNode *node, u8 code) if(code >= 0x01 && code <= 0x0A) { dmixml_AddTextContent(data_n, location[code - 0x01]); - } else if(code >= 0xA0 && code <= 0xA3) { + } else if(code >= 0xA0 && code <= 0xA4) { dmixml_AddTextContent(data_n, location_0xA0[code - 0xA0]); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } @@ -2669,7 +2883,7 @@ void dmi_memory_array_use(xmlNode *node, u8 code) if(code >= 0x01 && code <= 0x07) { dmixml_AddTextContent(data_n, use[code - 0x01]); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } @@ -2694,7 +2908,7 @@ void dmi_memory_array_ec_type(xmlNode *node, u8 code) if(code >= 0x01 && code <= 0x07) { dmixml_AddTextContent(data_n, type[code - 0x01]); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } @@ -2766,6 +2980,7 @@ void dmi_memory_device_size(xmlNode *node, u16 code) //. Keeping this as String rather than Int as it has KB and MB representations... dmixml_AddAttribute(data_n, "unit", "%s", (code & 0x8000 ? "KB" : "MB")); dmixml_AddTextContent(data_n, "%d", (code & 0x8000 ? code & 0x7FFF : code)); + //dmi_add_memory_size(data_n, code, 1); } } @@ -2793,35 +3008,51 @@ static void dmi_memory_device_extended_size(xmlNode *node, u32 code) } +void dmi_memory_voltage_value(xmlNode *node, const char *tag, u16 code) +{ + xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *)tag, NULL); + assert(data_n != NULL); + dmixml_AddAttribute(data_n, "flags", "0x%04x", code); + + if (code == 0) { + dmixml_AddAttribute(data_n, "unknown", "1"); + } else { + dmixml_AddAttribute(data_n, "unit", "V"); + dmixml_AddTextContent(data_n, "%.3f", (float)(i16)code / 1000); + } +} + + void dmi_memory_device_form_factor(xmlNode *node, u8 code) { /* 7.18.1 */ static const char *form_factor[] = { - "Other", /* 0x01 */ - "Unknown", - "SIMM", - "SIP", - "Chip", - "DIP", - "ZIP", - "Proprietary Card", - "DIMM", - "TSOP", - "Row Of Chips", - "RIMM", - "SODIMM", - "SRIMM", - "FB-DIMM" /* 0x0F */ + "Other", /* 0x01 */ + "Unknown", + "SIMM", + "SIP", + "Chip", + "DIP", + "ZIP", + "Proprietary Card", + "DIMM", + "TSOP", + "Row Of Chips", + "RIMM", + "SODIMM", + "SRIMM", + "FB-DIMM", /* 0x0F */ + "Die" /* 0x10 */ }; xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) "FormFactor", NULL); assert( data_n != NULL ); dmixml_AddAttribute(data_n, "dmispec", "7.18.1"); dmixml_AddAttribute(data_n, "flags", "0x%04x", code); - if(code >= 0x01 && code <= 0x0F) { + if(code >= 0x01 && code <= 0x10) { dmixml_AddTextContent(data_n, "%s", form_factor[code - 0x01]); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } @@ -2831,9 +3062,11 @@ void dmi_memory_device_set(xmlNode *node, u8 code) assert( data_n != NULL ); dmixml_AddAttribute(data_n, "flags", "0x%04x", code); - if(code == 0xFF) { - dmixml_AddAttribute(data_n, "outofspec", "1"); - } else if( code > 0 ) { + if (code == 0) { + // empty tag + } else if (code == 0xFF) { + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); + } else { dmixml_AddTextContent(data_n, "%ld", code); } } @@ -2842,41 +3075,51 @@ void dmi_memory_device_type(xmlNode *node, u8 code) { /* 7.18.2 */ static const char *type[] = { - "Other", /* 0x01 */ - "Unknown", - "DRAM", - "EDRAM", - "VRAM", - "SRAM", - "RAM", - "ROM", - "Flash", - "EEPROM", - "FEPROM", - "EPROM", - "CDRAM", - "3DRAM", - "SDRAM", - "SGRAM", - "RDRAM", - "DDR", - "DDR2", - "DDR2 FB-DIMM", /* 0x14 */ - "Reserved", - "Reserved", - "Reserved", - "DDR3", - "FBD2" /* 0x19 */ + "Other", /* 0x01 */ + "Unknown", + "DRAM", + "EDRAM", + "VRAM", + "SRAM", + "RAM", + "ROM", + "Flash", + "EEPROM", + "FEPROM", + "EPROM", + "CDRAM", + "3DRAM", + "SDRAM", + "SGRAM", + "RDRAM", + "DDR", + "DDR2", + "DDR2 FB-DIMM", /* 0x14 */ + "Reserved", + "Reserved", + "Reserved", + "DDR3", + "FBD2", /* 0x19 */ + "DDR4", + "LPDDR", + "LPDDR2", + "LPDDR3", + "LPDDR4", + "Logical non-volatile device", + "HBM", + "HBM2", /* 0x21 */ + "DDR5", + "LPDDR5" /* 0x23 */ }; xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) "Type", NULL); assert( data_n != NULL ); dmixml_AddAttribute(data_n, "dmispec", "7.18.2"); dmixml_AddAttribute(data_n, "flags", "0x%04x", code); - if(code >= 0x01 && code <= 0x19) { + if(code >= 0x01 && code <= 0x23) { dmixml_AddTextContent(data_n, "%s", type[code - 0x01]); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } @@ -2917,6 +3160,7 @@ void dmi_memory_device_type_detail(xmlNode *node, u16 code) } } + void dmi_memory_device_speed(xmlNode *node, const char *tag, u16 code) { xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) tag, NULL); @@ -2926,24 +3170,121 @@ void dmi_memory_device_speed(xmlNode *node, const char *tag, u16 code) if(code == 0) { dmixml_AddAttribute(data_n, "unknown", "1"); } else { - dmixml_AddAttribute(data_n, "unit", "MHz"); + dmixml_AddAttribute(data_n, "unit", "MT/s"); dmixml_AddTextContent(data_n, "%i", code); } } -void dmi_memory_voltage_value(xmlNode *node, const char *tag, u16 code) { - xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) tag, NULL); - assert( data_n != NULL ); + +void dmi_memory_technology(xmlNode *node, u8 code) +{ + /* 7.18.6 */ + static const char *const technology[] = { + "Other", /* 0x01 */ + "Unknown", + "DRAM", + "NVDIMM-N", + "NVDIMM-F", + "NVDIMM-P", + "Intel Optane DC persistent memory" /* 0x07 */ + }; + + xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *)"MemoryTechnology", NULL); + assert(data_n != NULL); + dmixml_AddAttribute(data_n, "dmispec", "7.18.6"); dmixml_AddAttribute(data_n, "flags", "0x%04x", code); - if (code == 0) { - dmixml_AddAttribute(data_n, "unknown", "1"); - } else { - dmixml_AddAttribute(data_n, "unit", "V"); - dmixml_AddTextContent(data_n, "%.3f", (float)(i16)code / 1000); + if (code >= 0x01 && code <= 0x07) + dmixml_AddTextContent(data_n, "%s", technology[code - 0x01]); + else + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); +} + +void dmi_memory_operating_mode_capability(xmlNode *node, u16 code) +{ + /* 7.18.7 */ + static const char *const mode[] = { + "Other", /* 1 */ + "Unknown", + "Volatile memory", + "Byte-accessible persistent memory", + "Block-accessible persistent memory" /* 5 */ + }; + xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *)"Memory Operating Mode Capability", NULL); + assert(data_n != NULL); + dmixml_AddAttribute(data_n, "dmispec", "7.18.7"); + dmixml_AddAttribute(data_n, "flags", "0x%04x", code); + + char list[99]; /* Update length if you touch the array above */ + if ((code & 0xFFFE) != 0) { + int i, off = 0; + list[0] = '\0'; + for (i = 1; i <= 5; i++) { + if (code & (1 << i)) + off += sprintf(list + off, off ? " %s" : "%s", mode[i - 1]); + } + dmixml_AddTextContent(data_n, "%s", list); } } +void dmi_memory_manufacturer_id(xmlNode *node, u16 code) +{ + /* 7.18.8 */ + /* 7.18.10 */ + /* LSB is 7-bit Odd Parity number of continuation codes */ + + xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *)"Memory Manufacturer Id", NULL); + assert(data_n != NULL); + dmixml_AddAttribute(data_n, "dmispec", "7.18.8/7.18.10"); + dmixml_AddAttribute(data_n, "flags", "0x%04x", code); + + if (code != 0) { + dmixml_AddAttribute(data_n, "%s", "Bank"); + dmixml_AddTextContent(data_n, "%u", (code & 0x7F) + 1); + dmixml_AddAttribute(data_n, "%s", "Hex"); + dmixml_AddTextContent(data_n, "%u", code >> 8); + } else { + dmixml_AddAttribute(data_n, "unknown", "1"); + } +} + + +void dmi_memory_product_id(xmlNode *node, u16 code) +{ + /* 7.18.9 */ + /* 7.18.11 */ + + xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *)"Memory Product Id", NULL); + assert(data_n != NULL); + dmixml_AddAttribute(data_n, "dmispec", "7.18.9/7.18.11"); + dmixml_AddAttribute(data_n, "flags", "0x%04x", code); + + if (code != 0){ + dmixml_AddTextContent(data_n, "%u", code); + } else { + dmixml_AddAttribute(data_n, "unknown", "1"); + } +} + + +void dmi_memory_size(xmlNode *node, u64 code) +{ + /* 7.18.12 */ + /* 7.18.13 */ + xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *)"Memory Size", NULL); + assert(data_n != NULL); + dmixml_AddAttribute(data_n, "dmispec", "7.18.12/7.18.13"); + dmixml_AddAttribute(data_n, "flags", "0x%04x", code); + + if (code.h == 0xFFFFFFFF && code.l == 0xFFFFFFFF) { + dmixml_AddAttribute(data_n, "unknown", "1"); + } else if (code.h == 0x0 && code.l == 0x0) { + // empty tag + } else { + dmi_add_memory_size(data_n, code, 0); + } +} + /******************************************************************************* * 7.19 32-bit Memory Error Information (Type 18) */ @@ -2975,7 +3316,7 @@ void dmi_memory_error_type(xmlNode *node, u8 code) if(code >= 0x01 && code <= 0x0E) { dmixml_AddTextContent(data_n, "%s", type[code - 0x01]); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } @@ -2996,7 +3337,7 @@ void dmi_memory_error_granularity(xmlNode *node, u8 code) if(code >= 0x01 && code <= 0x04) { dmixml_AddTextContent(data_n, "%s", granularity[code - 0x01]); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } @@ -3018,7 +3359,7 @@ void dmi_memory_error_operation(xmlNode *node, u8 code) if(code >= 0x01 && code <= 0x05) { dmixml_AddTextContent(data_n, "%s", operation[code - 0x01]); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } @@ -3094,7 +3435,7 @@ void dmi_mapped_address_row_position(xmlNode *node, u8 code) assert( data_n != NULL ); if(code == 0) { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } else if(code == 0xFF) { dmixml_AddAttribute(data_n, "unknown", "1"); } else { @@ -3152,7 +3493,7 @@ void dmi_pointing_device_type(xmlNode *node, u8 code) if(code >= 0x01 && code <= 0x09) { dmixml_AddTextContent(data_n, "%s", type[code - 0x01]); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } @@ -3184,7 +3525,7 @@ void dmi_pointing_device_interface(xmlNode *node, u8 code) } else if(code >= 0xA0 && code <= 0xA2) { dmixml_AddTextContent(data_n, interface_0xA0[code - 0xA0]); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } @@ -3213,7 +3554,7 @@ void dmi_battery_chemistry(xmlNode *node, u8 code) if(code >= 0x01 && code <= 0x08) { dmixml_AddTextContent(data_n, "%s", chemistry[code - 0x01]); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } @@ -3273,7 +3614,7 @@ void dmi_system_reset_boot_option(xmlNode *node, const char *tagname, u8 code) if( (code > 0) && (code < 4) ) { dmixml_AddTextContent(data_n, option[code - 0x1]); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } @@ -3378,7 +3719,7 @@ void dmi_voltage_probe_location(xmlNode *node, u8 code) if(code >= 0x01 && code <= 0x0B) { dmixml_AddTextContent(data_n, "%s", location[code - 0x01]); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } @@ -3401,7 +3742,7 @@ void dmi_probe_status(xmlNode *node, u8 code) if(code >= 0x01 && code <= 0x06) { dmixml_AddTextContent(data_n, "%s", status[code - 0x01]); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } @@ -3479,7 +3820,7 @@ void dmi_cooling_device_type(xmlNode *node, u8 code) } else if(code >= 0x10 && code <= 0x11) { dmixml_AddTextContent(data_n, "%s", type_0x10[code - 0x10]); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } @@ -3529,7 +3870,7 @@ void dmi_temperature_probe_location(xmlNode *node, u8 code) if(code >= 0x01 && code <= 0x0F) { dmixml_AddTextContent(data_n, "%s", location[code - 0x01]); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } @@ -3621,7 +3962,7 @@ void dmi_system_boot_status(xmlNode *node, u8 code) } else if(code >= 192) { dmixml_AddTextContent(data_n, "Product-specific"); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } @@ -3645,6 +3986,21 @@ void dmi_64bit_memory_error_address(xmlNode *node, const char *tagname, u64 code ** 7.35 Management Device (Type 34) */ +/* + * Several boards have a bug where some type 34 structures have their + * length incorrectly set to 0x10 instead of 0x0B. This causes the + * first 5 characters of the device name to be trimmed. It's easy to + * check and fix, so do it, but warn. + */ +void dmi_fixup_type_34(struct dmi_header *h) +{ + u8 *p = h->data; + + if (h->length == 0x10 && is_printable(p + 0x0B, 0x10 - 0x0B)) { + h->length = 0x0B; + } +} + void dmi_management_device_type(xmlNode *node, u8 code) { /* 7.35.1 */ @@ -3671,7 +4027,7 @@ void dmi_management_device_type(xmlNode *node, u8 code) if(code >= 0x01 && code <= 0x0D) { dmixml_AddTextContent(data_n, "%s", type[code - 0x01]); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } @@ -3693,7 +4049,7 @@ void dmi_management_device_address_type(xmlNode *node, u8 code) if(code >= 0x01 && code <= 0x05) { dmixml_AddTextContent(data_n, "%s", type[code - 0x01]); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } @@ -3718,7 +4074,7 @@ void dmi_memory_channel_type(xmlNode *node, u8 code) if(code >= 0x01 && code <= 0x04) { dmixml_AddTextContent(data_n, "%s", type[code - 0x01]); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } @@ -3757,7 +4113,7 @@ void dmi_ipmi_interface_type(xmlNode *node, u8 code) if(code <= 0x04) { dmixml_AddTextContent(data_n, "%s", type[code]); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } @@ -3793,7 +4149,7 @@ void dmi_ipmi_register_spacing(xmlNode *node, u8 code) if(code <= 0x02) { dmixml_AddTextContent(data_n, "%s", spacing[code]); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } @@ -3836,7 +4192,7 @@ void dmi_power_supply_type(xmlNode *node, u8 code) if(code >= 0x01 && code <= 0x08) { dmixml_AddTextContent(data_n, "%s", type[code - 0x01]); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } @@ -3859,7 +4215,7 @@ void dmi_power_supply_status(xmlNode *node, u8 code) if(code >= 0x01 && code <= 0x05) { dmixml_AddTextContent(data_n, "%s", status[code - 0x01]); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } @@ -3882,7 +4238,7 @@ void dmi_power_supply_range_switching(xmlNode *node, u8 code) if(code >= 0x01 && code <= 0x06) { dmixml_AddTextContent(data_n, "%s", switching[code - 0x01]); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } } @@ -3961,22 +4317,486 @@ xmlNode * dmi_management_controller_host_type(xmlNode *node, u8 code) "16750/16750A UART Register Compatible", "16850/16850A UART Register Compatible" /* 0x08 */ }; - xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) "ManagementControllerHost", NULL); + xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) "ManagementControllerHost", NULL); assert( data_n != NULL ); + dmixml_AddAttribute(data_n, "dmispec", "7.43"); dmixml_AddAttribute(data_n, "flags", "0x%04x", code); if (code >= 0x02 && code <= 0x08) { - dmixml_AddTextChild(data_n, "Type", "%s", type[code - 0x01]); + dmixml_AddTextChild(data_n, "Type", "%s", type[code - 0x02]); + } else if (code == 0x40) { + dmixml_AddTextChild(data_n, "Type", "Network"); } else if (code == 0xF0) { dmixml_AddTextChild(data_n, "Type", "OEM"); } else { - dmixml_AddAttribute(data_n, "outofspec", "1"); + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); } return data_n; } +//===================below should be checked========================== + +/* + * 7.43.2: Protocol Record Types + */ +void dmi_protocol_record_type(xmlNode *node, u8 code) +{ + const char *protocol[] = { + "Reserved", /* 0x0 */ + "Reserved", + "IPMI", + "MCTP", + "Redfish over IP" /* 0x4 */ + }; + + xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *)"ProtocolRecordType", NULL); + assert(data_n != NULL); + + dmixml_AddAttribute(data_n, "dmispec", "7.43.2"); + dmixml_AddAttribute(data_n, "flags", "0x%04x", code); + + if (code <= 0x4) { + dmixml_AddTextContent(data_n, "%s", protocol[code]); + } else if (code == 0xF0) { + dmixml_AddTextContent(data_n, "OEM"); + } else { + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); + } +} + +/* + * DSP0270: 8.6: Protocol IP Assignment types + */ +void dmi_protocol_assignment_type(xmlNode *node, u8 type) +{ + const char *assignment[] = { + "Unknown", /* 0x0 */ + "Static", + "DHCP", + "AutoConf", + "Host Selected" /* 0x4 */ + }; + + xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *)"ProtocolAssignmentType", NULL); + assert(data_n != NULL); + + if (type <= 0x4){ + dmixml_AddTextContent(data_n, "%s", assignment[type]); + } else { + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); + } +} + +/* + * DSP0270: 8.6: Protocol IP Address type + */ +void dmi_address_type(xmlNode *node, u8 type) +{ + const char *addressformat[] = { + "Unknown", /* 0x0 */ + "IPv4", + "IPv6" /* 0x2 */ + }; + + xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *)"AddressType", NULL); + assert(data_n != NULL); + + if (type <= 0x2) { + dmixml_AddTextContent(data_n, "Type", "%s", addressformat[type]); + } else { + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); + } +} + +/* + * DSP0270: 8.6 Protocol Address decode + */ +void dmi_address_decode(xmlNode *node, u8 *data, char *storage, u8 addrtype) +{ + xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *)"AdressDecode", NULL); + assert(data_n != NULL); + + if (addrtype == 0x1) {/* IPv4 */ + dmixml_AddAttribute(data_n, "Type", "ipv4"); + dmixml_AddTextContent(data_n, "%s", inet_ntop(AF_INET, data, storage, 64)); + } else if (addrtype == 0x2) {/* IPv6 */ + dmixml_AddAttribute(data_n, "Type", "ipv6"); + dmixml_AddTextContent(data_n, "%s", inet_ntop(AF_INET6, data, storage, 64)); + } else { + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); + } +} + +/* + * DSP0270: 8.5: Parse the protocol record format + */ +void dmi_parse_protocol_record(xmlNode *node, u8 *rec) +{ + xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *)"ParseProtocolRecord", NULL); + assert(data_n != NULL); + + u8 rid; + u8 rlen; + u8 *rdata; + char buf[64]; + u8 assign_val; + u8 addrtype; + u8 hlen; + const char *addrstr; + const char *hname; + char attr[38]; + + /* DSP0270: 8.5: Protocol Identifier */ + rid = rec[0x0]; + /* DSP0270: 8.5: Protocol Record Length */ + rlen = rec[0x1]; + /* DSP0270: 8.5: Protocol Record Data */ + rdata = &rec[0x2]; + + dmixml_AddAttribute(data_n, "ProtocolID", "%02x", rid); + dmi_protocol_record_type(data_n, rid); + + /* + * Don't decode anything other than Redfish for now + * Note 0x4 is Redfish over IP in 7.43.2 + * and DSP0270: 8.5 + */ + if (rid != 0x4) { + return; + } + + /* + * Ensure that the protocol record is of sufficient length + * For RedFish that means rlen must be at least 91 bytes + * other protcols will need different length checks + */ + if (rlen < 91) { + return; + } + + /* + * DSP0270: 8.6: Redfish Over IP Service UUID + * Note: ver is hardcoded to 0x311 here just for + * convenience. It could get passed from the SMBIOS + * header, but that's a lot of passing of pointers just + * to get that info, and the only thing it is used for is + * to determine the endianess of the field. Since we only + * do this parsing on versions of SMBIOS after 3.1.1, and the + * endianess of the field is always little after version 2.6.0 + * we can just pick a sufficiently recent version here. + */ + xmlNode *subdev_n = dmixml_AddTextChild(data_n, "SubAttr", "%s", "ServiceUUID"); + dmi_system_uuid(subdev_n, &rdata[0], 0x311); + subdev_n = NULL; + + /* + * DSP0270: 8.6: Redfish Over IP Host IP Assignment Type + * Note, using decimal indicies here, as the DSP0270 + * uses decimal, so as to make it more comparable + */ + assign_val = rdata[16]; + subdev_n = dmixml_AddTextChild(data_n, "SubAttr", "%s", "HostIPAssignmentType"); + dmi_protocol_assignment_type(subdev_n, assign_val); + subdev_n = NULL; + + /* DSP0270: 8.6: Redfish Over IP Host Address format */ + addrtype = rdata[17]; + subdev_n = dmixml_AddTextChild(data_n, "SubAttr", "%s", "HostIPAddressFormat"); + dmi_address_type(subdev_n, addrtype); + subdev_n = NULL; + + /* DSP0270: 8.6 IP Assignment types */ + /* We only use the Host IP Address and Mask if the assignment type is static */ + if (assign_val == 0x1 || assign_val == 0x3) { + /* DSP0270: 8.6: the Host IPv[4|6] Address */ + subdev_n = dmixml_AddTextChild(data_n, "SubAttr", "%s", "Address"); + dmi_address_decode(subdev_n, &rdata[18], buf, addrtype); + subdev_n = NULL; + + /* DSP0270: 8.6: Prints the Host IPv[4|6] Mask */ + subdev_n = dmixml_AddTextChild(data_n, "SubAttr", "%s", "Mask"); + dmi_address_decode(subdev_n, &rdata[34], buf, addrtype); + subdev_n = NULL; + } + + /* DSP0270: 8.6: Get the Redfish Service IP Discovery Type */ + assign_val = rdata[50]; + + /* Redfish Service IP Discovery type mirrors Host IP Assignment type */ + subdev_n = dmixml_AddTextChild(data_n, "SubAttr", "%s", "RedfishServiceIPAddressType"); + dmi_protocol_assignment_type(subdev_n, assign_val); + subdev_n = NULL; + + /* DSP0270: 8.6: Get the Redfish Service IP Address Format */ + addrtype = rdata[51]; + subdev_n = dmixml_AddTextChild(data_n, "SubAttr", "%s", "RedfishServiceIPAddressFormat"); + dmi_address_type(subdev_n, addrtype); + subdev_n = NULL; + + if (assign_val == 0x1 || assign_val == 0x3) { + u16 port; + u32 vlan; + + /* DSP0270: 8.6: Prints the Redfish IPv[4|6] Service Address */ + subdev_n = dmixml_AddTextChild(data_n, "SubAttr", "%s", "RedfishServiceAddress"); + dmi_address_decode(subdev_n, &rdata[52], buf, addrtype); + subdev_n = NULL; + + /* DSP0270: 8.6: Prints the Redfish IPv[4|6] Service Mask */ + xmlNode *subdev_n = dmixml_AddTextChild(data_n, "SubAttr", "%s", "RedfishServiceMask"); + dmi_address_decode(subdev_n, &rdata[68], buf, addrtype); + subdev_n = NULL; + + /* DSP0270: 8.6: Redfish vlan and port info */ + port = WORD(&rdata[84]); + vlan = DWORD(&rdata[86]); + subdev_n = dmixml_AddTextChild(data_n, "SubAttr", "%s", "RedfishServicePort"); + dmixml_AddAttribute(subdev_n, "RedfishServicePort", "%hu", port); + subdev_n = NULL; + + subdev_n = dmixml_AddTextChild(data_n, "SubAttr", "%s", "RedfishServiceVlan"); + dmixml_AddAttribute(subdev_n, "RedfishServiceVlan", "%u", vlan); + subdev_n = NULL; + } + + /* DSP0270: 8.6: Redfish host length and name */ + hlen = rdata[90]; + + /* + * DSP0270: 8.6: The length of the host string + 91 (the minimum + * size of a protocol record) cannot exceed the record length + * (rec[0x1]) + */ + hname = (const char *)&rdata[91]; + if (hlen + 91 > rlen) { + hname = OUT_OF_SPEC; + hlen = strlen(OUT_OF_SPEC); + } + subdev_n = dmixml_AddTextChild(data_n, "SubAttr", "%s", "RedfishServiceHostname"); + dmixml_AddTextContent(subdev_n, "%.*s", hlen, hname); + subdev_n = NULL; +} + +/* + * DSP0270: 8.3: Device type ennumeration + */ +void dmi_parse_device_type(xmlNode *node, u8 type) +{ + const char *devname[] = { + "USB", /* 0x2 */ + "PCI/PCIe" /* 0x3 */ + }; + + xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *)"ParseDeviceType", NULL); + assert(data_n != NULL); + + if (type >= 0x2 && type <= 0x3) { + dmixml_AddTextContent(data_n, "Type", "%s", devname[type - 0x2]); + } else if (type >= 0x80) { + dmixml_AddTextContent(data_n, "Type", "OEM"); + } else { + dmixml_AddAttribute(data_n, OUT_OF_SPEC, "1"); + } +} + +void dmi_parse_controller_structure(xmlNode *node, struct dmi_header *h) +{ + xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) "ControllerStructure", NULL); + assert(data_n != NULL); + + int i; + u8 *data = h->data; + /* Host interface type */ + u8 type; + /* Host Interface specific data length */ + u8 len; + u8 count; + u32 total_read; + + /* + * Minimum length of this struct is 0xB bytes + */ + if (h->length < 0xB) + return; + + /* + * Also need to ensure that the interface specific data length + * plus the size of the structure to that point don't exceed + * the defined length of the structure, or we will overrun its + * bounds + */ + len = data[0x5]; + total_read = len + 0x6; + + if (total_read > h->length) { + return; + } + type = data[0x4]; + + dmixml_AddAttribute(data_n, "Type", "%s", "HostInterfaceType"); + dmi_management_controller_host_type(data_n, type); + + /* + * The following decodes are code for Network interface host types only + * As defined in DSP0270 + */ + if (type != 0x40) { + return; + } + + if (len != 0) { + /* DSP0270: 8.3 Table 2: Device Type */ + type = data[0x6]; + + dmi_parse_device_type(data_n, type); + + if (type == 0x2 && len >= 5) { + /* USB Device Type - need at least 6 bytes */ + u8 *usbdata = &data[0x7]; + + /* USB Device Descriptor: idVendor */ + dmixml_AddTextContent(data_n, "idVendor", "0x%04x", WORD(&usbdata[0x0])); + + /* USB Device Descriptor: idProduct */ + dmixml_AddTextContent(data_n, "idProduct", "0x%04x", WORD(&usbdata[0x2])); + + /* + * USB Serial number is here, but its useless, don't + * bother decoding it + */ + } else if (type == 0x3 && len >= 9) { + /* PCI Device Type - Need at least 8 bytes */ + u8 *pcidata = &data[0x7]; + + /* PCI Device Descriptor: VendorID */ + dmixml_AddTextContent(data_n, "VendorID", "0x%04x", WORD(&pcidata[0x0])); + + /* PCI Device Descriptor: DeviceID */ + dmixml_AddTextContent(data_n, "DeviceID", "0x%04x", WORD(&pcidata[0x2])); + + /* PCI Device Descriptor: PCI SubvendorID */ + dmixml_AddTextContent(data_n, "SubVendorID", "0x%04x", WORD(&pcidata[0x4])); + + /* PCI Device Descriptor: PCI SubdeviceID */ + dmixml_AddTextContent(data_n, "SubDeviceID", "0x%04x", WORD(&pcidata[0x6])); + } else if (type == 0x4 && len >= 5) { + /* OEM Device Type - Need at least 4 bytes */ + u8 *oemdata = &data[0x7]; + + /* OEM Device Descriptor: IANA */ + dmixml_AddTextContent(data_n, "VendorID", "0x%02x:0x%02x:0x%02x:0x%02x", oemdata[0x0], oemdata[0x1], oemdata[0x2], oemdata[0x3]); + } + /* Don't mess with unknown types for now */ + } + + /* + * DSP0270: 8.2 and 8.5: Protocol record count and protocol records + * Move to the Protocol Count. + */ + data = &data[total_read]; + + /* + * We've validated up to 0x6 + len bytes, but we need to validate + * the next byte below, the count value. + */ + total_read++; + if (total_read > h->length) { + fprintf(stderr, "Total read length %d exceeds total structure length %d (handle 0x%04hx)\n", total_read, h->length, h->handle); + return; + } + + /* Get the protocol records count */ + count = data[0x0]; + if (count) { + u8 *rec = &data[0x1]; + for (i = 0; i < count; i++) { + /* + * Need to ensure that this record doesn't overrun + * the total length of the type 42 struct. Note the +2 + * is added for the two leading bytes of a protocol + * record representing the type and length bytes. + */ + total_read += rec[1] + 2; + if (total_read > h->length) { + fprintf(stderr, "Total read length %d exceeds total structure length %d (handle 0x%04hx, record %d)\n", total_read, h->length, h->handle, i + 1); + return; + } + + dmi_parse_protocol_record(data_n, rec); + + /* + * DSP0270: 8.6 + * Each record is rec[1] bytes long, starting at the + * data byte immediately following the length field. + * That means we need to add the byte for the rec id, + * the byte for the length field, and the value of the + * length field itself. + */ + rec += rec[1] + 2; + } + } +} + +/* + * 7.44 TPM Device (Type 43) + */ +void dmi_tpm_vendor_id(xmlNode *node, const u8 *p) +{ + + xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *)"TpmVendorId", NULL); + assert(data_n != NULL); + dmixml_AddAttribute(data_n, "dmispec", "7.44"); + dmixml_AddAttribute(data_n, "flags", "0x%04x", p); + + char vendor_id[5]; + int i; + + /* ASCII filtering */ + for (i = 0; i < 4 && p[i] != 0; i++) { + if (p[i] < 32 || p[i] >= 127) + vendor_id[i] = '.'; + else + vendor_id[i] = p[i]; + } + + /* Terminate the string */ + vendor_id[i] = '\0'; + + dmixml_AddTextContent(data_n, "VendorId", "%s", vendor_id); +} + +void dmi_tpm_characteristics(xmlNode *node, u64 code) +{ + xmlNode *data_n = xmlNewChild(node, NULL, (xmlChar *) "TpmCharacteristics", NULL); + assert(data_n != NULL); + + /* 7.1.1 */ + static const char *characteristics[] = { + "TPM Device characteristics not supported", /* 2 */ + "Family configurable via firmware update", + "Family configurable via platform software support", + "Family configurable via OEM proprietary mechanism" /* 5 */ + }; + int i; + + /* + * This isn't very clear what this bit is supposed to mean + */ + if (code.l & (1 << 2)) { + dmixml_AddTextContent(data_n, "%s", characteristics[0]); + return data_n; + } + + for (i = 3; i <= 5; i++) + if (code.l & (1 << i)) { + xmlNode *dev_n = xmlNewChild(data_n, NULL, (xmlChar *) "Device", NULL); + dmixml_AddAttribute(dev_n, "index", "%i", i); + dmixml_AddTextContent(dev_n, "%s", characteristics[i - 2]); + dev_n = NULL; + } +} /******************************************************************************* ** Main @@ -4017,8 +4837,7 @@ xmlNode *dmi_decode(xmlNode *prnt_n, dmi_codes_major *dmiMajor, struct dmi_heade dmi_bios_runtime_size(sect_n, (0x10000 - WORD(data + 0x06)) << 4); } - sub_n = dmixml_AddTextChild(sect_n, "ROMsize", "%i", (data[0x09] + 1) << 6); - dmixml_AddAttribute(sub_n, "unit", "KB"); + dmi_bios_rom_size(sub_n, data[0x09], h->length < 0x1A ? 16 : WORD(data + 0x18)); sub_n = NULL; sub_n = xmlNewChild(sect_n, NULL, (xmlChar *) "Characteristics", NULL); @@ -4352,8 +5171,16 @@ xmlNode *dmi_decode(xmlNode *prnt_n, dmi_codes_major *dmiMajor, struct dmi_heade sub_n = NULL; dmi_cache_location(sect_n, (WORD(data + 0x05) >> 5) & 0x0003); - dmi_cache_size(sect_n, "InstalledSize", WORD(data + 0x09)); - dmi_cache_size(sect_n, "MaximumSize", WORD(data + 0x07)); + + if (h->length >= 0x1B) + dmi_cache_size_2(sect_n, "InstalledSize", DWORD(data + 0x17)); + else + dmi_cache_size(sect_n, "InstalledSize", WORD(data + 0x09)); + + if (h->length >= 0x17) + dmi_cache_size_2(sect_n, "Maximumsize", DWORD(data + 0x13)); + else + dmi_cache_size(sect_n, "Maximumsize", WORD(data + 0x07)); dmi_cache_types(sect_n, "SupportedSRAMtypes", WORD(data + 0x0B)); dmi_cache_types(sect_n, "InstalledSRAMtypes", WORD(data + 0x0D)); @@ -4407,6 +5234,19 @@ xmlNode *dmi_decode(xmlNode *prnt_n, dmi_codes_major *dmiMajor, struct dmi_heade } else { dmi_slot_characteristics(sect_n, data[0x0B], data[0x0C]); } + + if(h->length < 0x11){ + break; + } + dmi_slot_segment_bus_func(sub_n, WORD(data + 0x0D), data[0x0F], data[0x10]); + + if (h->length < 0x13){ + break; + } + dmixml_AddAttribute(sect_n, "Databuswidth", "%i", data[0x11]); + + if( h->length - 0x13 >= data[0x12] * 5) + dmi_slot_peers(sect_n, data[0x12], h, data+0x13); break; case 10: /* 7.11 On Board Devices Information */ @@ -4434,9 +5274,17 @@ xmlNode *dmi_decode(xmlNode *prnt_n, dmi_codes_major *dmiMajor, struct dmi_heade break; } + if (ver >= 0x0201){ + dmixml_AddAttribute(sect_n, "Language_description_format", "%s", + dmi_bios_language_format(data[0x05])); + } + dmixml_AddAttribute(sect_n, "installable_languages", "%i", data[0x04]); dmi_bios_languages(sect_n, h, data[0x05]); + + dmixml_AddAttribute(sect_n, "currently_installed_language", "%s", dmi_string(h, data[0x15])); + break; case 14: /* 7.15 Group Associations */ @@ -4487,7 +5335,6 @@ xmlNode *dmi_decode(xmlNode *prnt_n, dmi_codes_major *dmiMajor, struct dmi_heade // SysEventLog/Access/Header/Format - sub2_n dmi_event_log_header_type(sub2_n, data[0x14]); - sub2_n = NULL; sub_n = NULL; @@ -4519,7 +5366,7 @@ xmlNode *dmi_decode(xmlNode *prnt_n, dmi_codes_major *dmiMajor, struct dmi_heade dmi_memory_array_use(sect_n, data[0x05]); dmi_memory_array_ec_type(sect_n, data[0x06]); dmi_memory_array_capacity(sect_n, h, data); - dmi_memory_array_error_handle(sect_n, WORD(data + 0x0B)); + dmi_memory_array_error_handle(sect_n, WORD(data + 0x0D)); break; case 17: /* 7.18 Memory Device */ @@ -4646,16 +5493,28 @@ xmlNode *dmi_decode(xmlNode *prnt_n, dmi_codes_major *dmiMajor, struct dmi_heade break; } - dmixml_AddTextChild(sect_n, "StartAddress", "0x%08x%03x", - (DWORD(data + 0x04) >> 2), - (DWORD(data + 0x04) & 0x3) << 10); + if (h->length >= 0x23 && DWORD(data + 0x04) == 0xFFFFFFFF){ + u64 start, end; - dmixml_AddTextChild(sect_n, "EndAddress", "0x%08x%03x", - (DWORD(data + 0x08) >> 2), - ((DWORD(data + 0x08) & 0x3) << 10) + 0x3FF); + start = QWORD(data + 0x13); + end = QWORD(data + 0x1B); - dmi_mapped_address_size(sect_n, DWORD(data + 0x08) - DWORD(data + 0x04) + 1); + dmixml_AddTextChild(sect_n, "StartAddress", "0x%08X%08Xk", + start.h, start.l); + dmixml_AddTextChild(sect_n, "StartAddress", "0x%08X%08Xk", + end.h, end.l); + dmi_mapped_address_extended_size(sect_n, start, end); + } else { + dmixml_AddTextChild(sect_n, "StartAddress", "0x%08x%03x", + (DWORD(data + 0x04) >> 2), + (DWORD(data + 0x04) & 0x3) << 10); + + dmixml_AddTextChild(sect_n, "EndAddress", "0x%08x%03x", + (DWORD(data + 0x08) >> 2), + ((DWORD(data + 0x08) & 0x3) << 10) + 0x3FF); + dmi_mapped_address_size(sect_n, DWORD(data + 0x08) - DWORD(data + 0x04) + 1); + } dmixml_AddTextChild(sect_n, "PhysicalDeviceHandle", "0x%04x", WORD(data + 0x0C)); dmixml_AddTextChild(sect_n, "MemArrayMappedAddrHandle", "0x%04x", WORD(data + 0x0E)); @@ -4697,7 +5556,7 @@ xmlNode *dmi_decode(xmlNode *prnt_n, dmi_codes_major *dmiMajor, struct dmi_heade dmi_battery_chemistry(sect_n, data[0x09]); } - dmi_battery_capacity(sect_n, WORD(data + 0x0A), (h->length < 0x1A ? 1 : data[0x15])); + dmi_battery_capacity(sect_n, WORD(data + 0x0A), (h->length < 0x16 ? 1 : data[0x15])); dmi_battery_voltage(sect_n, WORD(data + 0x0C)); dmixml_AddDMIstring(sect_n, "SBDSversion", h, data[0x0E]); @@ -4889,7 +5748,14 @@ xmlNode *dmi_decode(xmlNode *prnt_n, dmi_codes_major *dmiMajor, struct dmi_heade break; case 31: /* 7.32 Boot Integrity Services Entry Point */ - dmixml_AddAttribute(sect_n, "NOT_IMPLEMENTED", "1"); + if(h->length < 0x1C){ + break; + } + + dmixml_AddAttribute(sect_n, "Checksum", "%s", checksum(data, h->length) ? "OK" : "Invalid"); + dmixml_AddAttribute(sect_n, "16BitEntryPointAddress", "%04X:%04X", + DWORD(data + 0x08) >> 16, DWORD(data + 0x08) & 0xFFFF); + dmixml_AddAttribute(sect_n, "32BitEntryPointAddress", "0x%08X", DWORD(data + 0x0C)); break; case 32: /* 7.33 System Boot Information */ @@ -5135,26 +6001,63 @@ xmlNode *dmi_decode(xmlNode *prnt_n, dmi_codes_major *dmiMajor, struct dmi_heade break; case 42: /* 7.43 Management Controller Host Interface */ - if (h->length < 0x05) { + if (ver < 0x0302){ + if (h->length < 0x05){ + break; + } + dmixml_AddAttribute(sect_n, "subtype", "InterfaceType"); + dmi_management_controller_host_type(sect_n, data[0x04]); + /* + * There you have a type-dependent, variable-length + * part in the middle of the structure, with no + * length specifier, so no easy way to decode the + * common, final part of the structure. What a pity. + */ + if (h->length < 0x09) { + break; + } + if (data[0x04] == 0xF0) { /* OEM */ + dmixml_AddAttribute(sect_n, "subtype", "VendorID"); + dmixml_AddTextContent(sect_n, "0x%02X%02X%02X%02X\n", + data[0x05], data[0x06], data[0x07], + data[0x08]); + } + sub_n = NULL; + } else { + dmi_parse_controller_structure(sect_n, h); + } + break; + case 43: + if (h->length < 0x1B){ break; } - - sub_n = dmi_management_controller_host_type(sect_n, data[0x04]); - /* - * There you have a type-dependent, variable-length - * part in the middle of the structure, with no - * length specifier, so no easy way to decode the - * common, final part of the structure. What a pity. - */ - if (h->length < 0x09) { + dmi_tpm_vendor_id(sect_n, data[0x04]); + switch (data[0x08]) { + case 0x01: + /* + * We skip the first 2 bytes, which are + * redundant with the above, and uncoded + * in a silly way. + */ + dmixml_AddTextContent(sect_n, "FirmwareRevision", "%u", data[0x0C]); + dmixml_AddTextContent(sect_n, "FirmwareRevision", "%u", data[0x0D]); + break; + case 0x02: + /* + * We skip the next 4 bytes, as their + * format is not standardized and their + * usefulness seems limited anyway. + */ + dmixml_AddTextContent(sect_n, "FirmwareRevision", "%i", DWORD(data + 0x0A) >> 16); + dmixml_AddTextContent(sect_n, "FirmwareRevision", "%i", DWORD(data + 0x0A) & 0xFFFF); break; } - if (data[0x04] == 0xF0) { /* OEM */ - dmixml_AddTextChild(sub_n, "VendorID", "0x%02X%02X%02X%02X\n", - data[0x05], data[0x06], data[0x07], - data[0x08]); + dmixml_AddDMIstring(sect_n, "Description", h, data[0x12]); + dmi_tpm_characteristics(sect_n, QWORD(data + 0x13)); + if (h->length < 0x1F){ + break; } - sub_n = NULL; + dmixml_AddAttribute(sect_n, "OEMSpecificInformation", "0x%08X", DWORD(data + 0x1B)); break; case 126: /* 7.43 Inactive */ case 127: /* 7.44 End Of Table */ @@ -5277,6 +6180,11 @@ static void dmi_table(Log_t *logp, int type, u32 base, u32 len, u16 num, u32 ver dmi_set_vendor(&h); } + /* Fixup a common mistake */ + if(h.type == 34){ + dmi_fixup_type_34(&h); + } + /* look for the next handle */ next = data + h.length; while(next - buf + 1 < len && (next[0] != 0 || next[1] != 0)) { diff --git a/src/dmidecode.h b/src/dmidecode.h index 22d70e1..8279b74 100644 --- a/src/dmidecode.h +++ b/src/dmidecode.h @@ -37,7 +37,8 @@ struct dmi_header { u8 *data; }; -void dmi_dump(xmlNode *node, struct dmi_header * h); +int is_printable(const u8 *data, int len); +void dmi_dump(xmlNode *node, struct dmi_header *h); xmlNode *dmi_decode(xmlNode *parent_n, dmi_codes_major *dmiMajor, struct dmi_header * h, u16 ver); void to_dmi_header(struct dmi_header *h, u8 * data); diff --git a/src/pymap.xml b/src/pymap.xml index 7325a85..5ecc7eb 100644 --- a/src/pymap.xml +++ b/src/pymap.xml @@ -786,6 +786,9 @@ + + + From 2f4d895c32e7de1e1fba680aebdfc091c4ff835a Mon Sep 17 00:00:00 2001 From: Zhongze Hu Date: Sat, 22 Oct 2022 17:21:12 +0800 Subject: [PATCH 06/27] fix warning argument 1 null where non-null expected src/dmidecodemodule.c:154:27: Warning argument 1 null where non-null expected [-Wnonnull] 154 | } else if(memcmp(buf, "_SM_", 4) == 0) { | ^~~~~~~~~~~~~~~~~~~~~~ src/dmidecodemodule.c:158:27: Warning argument 1 null where non-null expected [-Wnonnull] 158 | } else if(memcmp(buf, "_DMI_", 5) == 0) { | ^~~~~~~~~~~~~~~~~~~~~~~ --- src/dmidecodemodule.c | 32 +++++++++++++++++--------------- 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/src/dmidecodemodule.c b/src/dmidecodemodule.c index d3ac7ff..7d3ba71 100644 --- a/src/dmidecodemodule.c +++ b/src/dmidecodemodule.c @@ -144,22 +144,24 @@ xmlNode *dmidecode_get_version(options *opt) if(opt->dumpfile != NULL) { //. printf("Reading SMBIOS/DMI data from file %s.\n", dumpfile); if((buf = mem_chunk(opt->logdata, 0, 0x20, opt->dumpfile)) != NULL) { - ver_n = NULL; - goto exit_free; - } - if(memcmp(buf, "_SM3_", 5) == 0){ - ver_n = smbios3_decode_get_version(buf, opt->dumpfile); - if ( dmixml_GetAttrValue(ver_n, "unknown") == NULL ) - found++; - } else if(memcmp(buf, "_SM_", 4) == 0) { - ver_n = smbios_decode_get_version(buf, opt->dumpfile); - if( dmixml_GetAttrValue(ver_n, "unknown") == NULL ) - found++; - } else if(memcmp(buf, "_DMI_", 5) == 0) { - ver_n = legacy_decode_get_version(buf, opt->dumpfile); - if( dmixml_GetAttrValue(ver_n, "unknown") == NULL ) - found++; + if (memcmp(buf, "_SM3_", 5) == 0) { + ver_n = smbios3_decode_get_version(buf, opt->dumpfile); + if (dmixml_GetAttrValue(ver_n, "unknown") == NULL) + found++; + } else if (memcmp(buf, "_SM_", 4) == 0) { + ver_n = smbios_decode_get_version(buf, opt->dumpfile); + if (dmixml_GetAttrValue(ver_n, "unknown") == NULL) + found++; + } else if (memcmp(buf, "_DMI_", 5) == 0) { + ver_n = legacy_decode_get_version(buf, opt->dumpfile); + if (dmixml_GetAttrValue(ver_n, "unknown") == NULL) + found++; + } + } else { + ver_n = NULL; + goto exit_free; } + } /* From 5c2d56c901c86a27f6e86913892da17c983fda46 Mon Sep 17 00:00:00 2001 From: Zhongze Hu Date: Sat, 22 Oct 2022 17:25:59 +0800 Subject: [PATCH 07/27] fix warning: ignoring return value of 'legacy_decode' src/dmidump.c:157:1:warning: ignoring return value of 'legacy_decode' [-Wreturn-type] 157 | } | ^ --- src/dmidump.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/dmidump.c b/src/dmidump.c index da0d676..07f24e9 100644 --- a/src/dmidump.c +++ b/src/dmidump.c @@ -154,6 +154,8 @@ static int legacy_decode(u8 *buf, const char *devmem, u32 flags, const char *du 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) From 163fe6edce3d1c94ddbd1008325e634c9abf53ee Mon Sep 17 00:00:00 2001 From: Zhongze Hu Date: Sat, 22 Oct 2022 17:43:20 +0800 Subject: [PATCH 08/27] fix warning: comparison of integer expressions of different signedness src/util.c:225:76: warning: comparison of integer expressions of different signedness: 'long unsigned int' and '__off_t' {aka 'long int'} [-Wsign-compare] 225 | if (sigill_error || S_ISREG(statbuf.st_mode) && base + (off_t)len > statbuf.st_size ) | ^ src/util.c:225:55: warning: suggest parentheses around '&&' within '||' [-Wparentheses] 225 | if (sigill_error || S_ISREG(statbuf.st_mode) && base + (off_t)len > statbuf.st_size ) | --- src/util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util.c b/src/util.c index 465376e..aabeafc 100644 --- a/src/util.c +++ b/src/util.c @@ -222,7 +222,7 @@ void *mem_chunk(Log_t *logp, size_t base, size_t len, const char *devmem) * mmap() will fail with SIGBUS if trying to map beyond the end of * the file. */ - if (sigill_error || S_ISREG(statbuf.st_mode) && base + (off_t)len > statbuf.st_size ) + if (sigill_error || S_ISREG(statbuf.st_mode) && (__off_t)(base + (off_t)len) > statbuf.st_size ) { log_append(logp, LOGFL_NORMAL, LOG_WARNING, "mmap: Can't map beyond end of file %s: %s", From 4b3d528afccdf5c64b5dccc2d3d488f7cfc75c0f Mon Sep 17 00:00:00 2001 From: Zhongze Hu Date: Sat, 22 Oct 2022 17:46:54 +0800 Subject: [PATCH 09/27] fix warning: suggest parentheses around '&&' within '||' src/util.c:225:55: warning: suggest parentheses around '&&' within '||' [-Wparentheses] 225 | if (sigill_error || S_ISREG(statbuf.st_mode) && (__off_t)(base + (off_t)len) > statbuf.st_size ) | --- src/util.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/util.c b/src/util.c index aabeafc..7f61e55 100644 --- a/src/util.c +++ b/src/util.c @@ -222,7 +222,7 @@ void *mem_chunk(Log_t *logp, size_t base, size_t len, const char *devmem) * mmap() will fail with SIGBUS if trying to map beyond the end of * the file. */ - if (sigill_error || S_ISREG(statbuf.st_mode) && (__off_t)(base + (off_t)len) > statbuf.st_size ) + if ((sigill_error || S_ISREG(statbuf.st_mode)) && (__off_t)(base + (off_t)len) > statbuf.st_size ) { log_append(logp, LOGFL_NORMAL, LOG_WARNING, "mmap: Can't map beyond end of file %s: %s", From b9d8101a01ec629109e0da0574f6c91bad09ecf1 Mon Sep 17 00:00:00 2001 From: Zhongze Hu Date: Sat, 22 Oct 2022 17:50:53 +0800 Subject: [PATCH 10/27] fix warning: variable 'eptype' set but not used src/efi.c:52:21: warning: variable 'eptype' set but not used [-Wunused-but-set-variable] 52 | const char *eptype; | --- src/efi.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/efi.c b/src/efi.c index 362e2f9..901803e 100644 --- a/src/efi.c +++ b/src/efi.c @@ -83,6 +83,10 @@ int address_from_efi(Log_t *logp, size_t * address) log_append(logp, LOGFL_NODUPS, LOG_WARNING, "%s: SMBIOS entry point missing", filename); } + if(ret == 0){ + log_append(logp, LOGFL_NODUPS, LOG_WARNING, "%s: entry point at 0x%08llx", eptype, (unsigned long long)*address); + } + return ret; } From 168cc81eb24f650959c28388397cfdb3f6864fc0 Mon Sep 17 00:00:00 2001 From: Zhongze Hu Date: Sat, 22 Oct 2022 17:59:45 +0800 Subject: [PATCH 11/27] fix warning: unused variable 'ver' src/dmidecode.c:6274:21: warning: unused variable 'ver' [-Wunused-variable] 6274 | u32 ver = (buf[0x07] << 16) + (buf[0x08] << 8) + buf[0x09]; | ^~~ --- src/dmidecode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dmidecode.c b/src/dmidecode.c index 9d755a5..ce105f6 100644 --- a/src/dmidecode.c +++ b/src/dmidecode.c @@ -6271,7 +6271,7 @@ xmlNode *smbios3_decode_get_version(u8 * buf, const char *devmem) dmixml_AddAttribute(data_n, "type", "SMBIOS"); if(check == 1) { - u32 ver = (buf[0x07] << 16) + (buf[0x08] << 8) + buf[0x09]; + // u32 ver = (buf[0x07] << 16) + (buf[0x08] << 8) + buf[0x09]; dmixml_AddTextContent(data_n, "SMBIOS %i.%i.%i present", buf[0x07], buf[0x08], buf[0x09]); dmixml_AddAttribute(data_n, "version", "%i.%i.%i", buf[0x07], buf[0x08],buf[0x09]); } else if(check == 0) { From 369c9be943ea9427b61fc712034bc57b591687a5 Mon Sep 17 00:00:00 2001 From: Zhongze Hu Date: Sat, 22 Oct 2022 18:04:34 +0800 Subject: [PATCH 12/27] fix warning: passing argument 3 of 'dmi_slot_peers' from incompatible pointer type src/dmidecode.c:5248:60: warning: passing argument 3 of 'dmi_slot_peers' from incompatible pointer type [-Wincompatible-pointer-types] 5248 | dmi_slot_peers(sect_n, data[0x12], h, data+0x13); | ^ | | | struct dmi_header * src/dmidecode.c:2471:52: note: expected 'const u8 *' {aka 'const unsigned char *'} but argument is of type 'struct dmi_header *' 2471 | void dmi_slot_peers(xmlNode *node, u8 n, const u8 *data, struct dmi_header *h) | ~~~~~~~~~~^~~~ src/dmidecode.c:5248:67: warning: passing argument 4 of 'dmi_slot_peers' from incompatible pointer type [-Wincompatible-pointer-types] 5248 | dmi_slot_peers(sect_n, data[0x12], h, data+0x13); | ~~~~^~~~~ | | | const u8 * {aka const unsigned char *} src/dmidecode.c:2471:77: note: expected 'struct dmi_header *' but argument is of type 'const u8 *' {aka 'const unsigned char *'} 2471 | void dmi_slot_peers(xmlNode *node, u8 n, const u8 *data, struct dmi_header *h) --- src/dmidecode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dmidecode.c b/src/dmidecode.c index ce105f6..2c1f45e 100644 --- a/src/dmidecode.c +++ b/src/dmidecode.c @@ -5245,7 +5245,7 @@ xmlNode *dmi_decode(xmlNode *prnt_n, dmi_codes_major *dmiMajor, struct dmi_heade dmixml_AddAttribute(sect_n, "Databuswidth", "%i", data[0x11]); if( h->length - 0x13 >= data[0x12] * 5) - dmi_slot_peers(sect_n, data[0x12], h, data+0x13); + dmi_slot_peers(sect_n, data[0x12], data+0x13, h); break; case 10: /* 7.11 On Board Devices Information */ From e438d9134450ebcdf4359a2bf17bf3ddad45d78e Mon Sep 17 00:00:00 2001 From: Zhongze Hu Date: Sat, 22 Oct 2022 18:10:57 +0800 Subject: [PATCH 13/27] src/dmidecode.c: In function 'dmi_tpm_characteristics': src/dmidecode.c:4788:24: warning: 'return' with a value, in function returning void [-Wreturn-type] 4788 | return data_n; | ^~~~~~ --- src/dmidecode.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/dmidecode.c b/src/dmidecode.c index 2c1f45e..555dc7a 100644 --- a/src/dmidecode.c +++ b/src/dmidecode.c @@ -4785,7 +4785,6 @@ void dmi_tpm_characteristics(xmlNode *node, u64 code) */ if (code.l & (1 << 2)) { dmixml_AddTextContent(data_n, "%s", characteristics[0]); - return data_n; } for (i = 3; i <= 5; i++) From 2e29bf2aa195b58c5a6e5e9cdbaaf2b27dd9e5da Mon Sep 17 00:00:00 2001 From: Zhongze Hu Date: Sat, 22 Oct 2022 18:15:06 +0800 Subject: [PATCH 14/27] fix warning: suggest parentheses around assignment used as truth value src/dmidecodemodule.c:350:12: warning: suggest parentheses around assignment used as truth value [-Wparentheses] 350 | if(buf = mem_chunk(opt->logdata, fp, 0x20, opt->devmem) == NULL ){ | ^~~ --- src/dmidecodemodule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dmidecodemodule.c b/src/dmidecodemodule.c index 7d3ba71..932e5a5 100644 --- a/src/dmidecodemodule.c +++ b/src/dmidecodemodule.c @@ -347,7 +347,7 @@ int dmidecode_get_xml(options *opt, xmlNode* dmixml_n) goto exit_free; } - if(buf = mem_chunk(opt->logdata, fp, 0x20, opt->devmem) == NULL ){ + if((buf = mem_chunk(opt->logdata, fp, 0x20, opt->devmem)) == NULL ){ ret = 1; goto exit_free; } From ddc6e0da1d2da885e3b918f74ffebc05393b9631 Mon Sep 17 00:00:00 2001 From: Zhongze Hu Date: Sat, 22 Oct 2022 18:16:21 +0800 Subject: [PATCH 15/27] fix warning: suggest parentheses around assignment used as truth value src/dmidecodemodule.c:206:12: warning: suggest parentheses around assignment used as truth value [-Wparentheses] 206 | if(buf = mem_chunk(opt->logdata, fp, 0x20, opt->devmem) == NULL){ | ^~~ --- src/dmidecodemodule.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dmidecodemodule.c b/src/dmidecodemodule.c index 932e5a5..0da3baf 100644 --- a/src/dmidecodemodule.c +++ b/src/dmidecodemodule.c @@ -203,7 +203,7 @@ xmlNode *dmidecode_get_version(options *opt) goto exit_free; } - if(buf = mem_chunk(opt->logdata, fp, 0x20, opt->devmem) == NULL){ + if((buf = mem_chunk(opt->logdata, fp, 0x20, opt->devmem)) == NULL){ ver_n = NULL; goto exit_free; } From 4c547ef8b025cb48eef5267c3381fe1a702756b1 Mon Sep 17 00:00:00 2001 From: Zhongze Hu Date: Sat, 22 Oct 2022 18:26:46 +0800 Subject: [PATCH 16/27] fix warning: unused variable 'addrstr' src/dmidecode.c:4446:21: warning: unused variable 'addrstr' [-Wunused-variable] 4446 | const char *addrstr; | ^~~~~~~ --- src/dmidecode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dmidecode.c b/src/dmidecode.c index 555dc7a..ebcd608 100644 --- a/src/dmidecode.c +++ b/src/dmidecode.c @@ -4443,7 +4443,7 @@ void dmi_parse_protocol_record(xmlNode *node, u8 *rec) u8 assign_val; u8 addrtype; u8 hlen; - const char *addrstr; + // const char *addrstr; const char *hname; char attr[38]; From 6e24d9be5b93201cf09fa8a78a8f8d05ec4ee8cd Mon Sep 17 00:00:00 2001 From: Zhongze Hu Date: Sat, 22 Oct 2022 18:33:39 +0800 Subject: [PATCH 17/27] fix warning: unused variable 'attr' src/dmidecode.c: In function 'dmi_parse_protocol_record': src/dmidecode.c:4448:14: warning: unused variable 'attr' [-Wunused-variable] 4448 | char attr[38]; | ^~~~ --- src/dmidecode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dmidecode.c b/src/dmidecode.c index ebcd608..49313f8 100644 --- a/src/dmidecode.c +++ b/src/dmidecode.c @@ -4445,7 +4445,7 @@ void dmi_parse_protocol_record(xmlNode *node, u8 *rec) u8 hlen; // const char *addrstr; const char *hname; - char attr[38]; + // char attr[38]; /* DSP0270: 8.5: Protocol Identifier */ rid = rec[0x0]; From d52d234893ac6a8587ce0711a2c9d33d14bdd2f1 Mon Sep 17 00:00:00 2001 From: Zhongze Hu Date: Sat, 22 Oct 2022 18:35:58 +0800 Subject: [PATCH 18/27] fix warning: passing argument 2 of 'dmi_tpm_vendor_id' makes pointer from integer without a cast src/dmidecode.c: In function 'dmi_decode': src/dmidecode.c:6032:47: warning: passing argument 2 of 'dmi_tpm_vendor_id' makes pointer from integer without a cast [-Wint-conversion] 6032 | dmi_tpm_vendor_id(sect_n, data[0x04]); | ~~~~^~~~~~ | | | u8 {aka unsigned char} --- src/dmidecode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dmidecode.c b/src/dmidecode.c index 49313f8..64680e2 100644 --- a/src/dmidecode.c +++ b/src/dmidecode.c @@ -6029,7 +6029,7 @@ xmlNode *dmi_decode(xmlNode *prnt_n, dmi_codes_major *dmiMajor, struct dmi_heade if (h->length < 0x1B){ break; } - dmi_tpm_vendor_id(sect_n, data[0x04]); + dmi_tpm_vendor_id(sect_n, data + 0x04); switch (data[0x08]) { case 0x01: /* From a8755eaa5bf3e0d240aa2247570b1d08763768b3 Mon Sep 17 00:00:00 2001 From: Zhongze Hu Date: Sat, 22 Oct 2022 18:40:23 +0800 Subject: [PATCH 19/27] fix warning: variable 'str_n' set but not used src/dmidecode.c: In function 'dmi_additional_info': src/dmidecode.c:4262:42: warning: variable 'str_n' set but not used [-Wunused-but-set-variable] 4262 | xmlNode *data_n = NULL, *str_n = NULL, *val_n = NULL; | ^~~~~ --- src/dmidecode.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dmidecode.c b/src/dmidecode.c index 64680e2..d297bb6 100644 --- a/src/dmidecode.c +++ b/src/dmidecode.c @@ -4259,7 +4259,7 @@ void dmi_additional_info(xmlNode *node, const struct dmi_header *h) assert( node != NULL ); for(i = 0; i < count; i++) { - xmlNode *data_n = NULL, *str_n = NULL, *val_n = NULL; + xmlNode *data_n = NULL, *val_n = NULL; /* Check for short entries */ if(h->length < offset + 1) { @@ -4277,7 +4277,7 @@ void dmi_additional_info(xmlNode *node, const struct dmi_header *h) dmixml_AddAttribute(data_n, "ReferenceHandle", "0x%04x", WORD(p + 0x01)); dmixml_AddAttribute(data_n, "ReferenceOffset", "0x%02x", p[0x03]); - str_n = dmixml_AddDMIstring(data_n, "String", h, p[0x04]); + dmixml_AddDMIstring(data_n, "String", h, p[0x04]); switch (length - 0x05) { case 1: From b76eadfc067a9a2fea9d7425de96e758c0b16111 Mon Sep 17 00:00:00 2001 From: Zhongze Hu Date: Sat, 22 Oct 2022 18:41:44 +0800 Subject: [PATCH 20/27] fix warning: this 'if' clause does not guard src/dmidecodemodule.c: In function 'dmidecode_get_xml': src/dmidecodemodule.c:394:25: warning: this 'if' clause does not guard... [-Wmisleading-indentation] 394 | if(legacy_decode(opt->logdata, opt->type, | ^~ src/dmidecodemodule.c:397:33: note: ...this statement, but the latter is misleadingly indented as if it were guarded by the 'if' 397 | goto done; | ^~~~ --- src/dmidecodemodule.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/dmidecodemodule.c b/src/dmidecodemodule.c index 0da3baf..efa730b 100644 --- a/src/dmidecodemodule.c +++ b/src/dmidecodemodule.c @@ -392,9 +392,10 @@ int dmidecode_get_xml(options *opt, xmlNode* dmixml_n) } } else if(memcmp(buf + fp, "_DMI_", 5) == 0) { if(legacy_decode(opt->logdata, opt->type, - buf + fp, opt->devmem, 0, dmixml_n)) + buf + fp, opt->devmem, 0, dmixml_n)) { found++; goto done; + } } } #endif From d682a1226e1d0ba60ac4a528dd888ba3db2eb3b9 Mon Sep 17 00:00:00 2001 From: Zhongze Hu Date: Mon, 24 Oct 2022 14:29:39 +0800 Subject: [PATCH 21/27] fix function dmi_slot_segment_bus_func null point error in system slot Case 13(System Slot): function dmi_slot_segment_bus_func may cause core dump error by null point sub_n. --- src/dmidecode.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dmidecode.c b/src/dmidecode.c index d297bb6..7fb1c89 100644 --- a/src/dmidecode.c +++ b/src/dmidecode.c @@ -5236,7 +5236,7 @@ xmlNode *dmi_decode(xmlNode *prnt_n, dmi_codes_major *dmiMajor, struct dmi_heade if(h->length < 0x11){ break; } - dmi_slot_segment_bus_func(sub_n, WORD(data + 0x0D), data[0x0F], data[0x10]); + dmi_slot_segment_bus_func(sect_n, WORD(data + 0x0D), data[0x0F], data[0x10]); if (h->length < 0x13){ break; From 5fdcb2b432d812ffdd4a9c8d60087561b4e305f8 Mon Sep 17 00:00:00 2001 From: Zhongze Hu Date: Wed, 26 Oct 2022 11:30:46 +0800 Subject: [PATCH 22/27] fix address_from_efi ret=0 message change LOG_WARNING level into LOG_DEBUG --- src/efi.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/efi.c b/src/efi.c index 901803e..e519257 100644 --- a/src/efi.c +++ b/src/efi.c @@ -84,7 +84,7 @@ int address_from_efi(Log_t *logp, size_t * address) } if(ret == 0){ - log_append(logp, LOGFL_NODUPS, LOG_WARNING, "%s: entry point at 0x%08llx", eptype, (unsigned long long)*address); + log_append(logp, LOGFL_NODUPS, LOG_DEBUG, "%s: entry point at 0x%08llx", eptype, (unsigned long long)*address); } return ret; From 50e959317d627ed3b6bfa762d3f558e70bd19058 Mon Sep 17 00:00:00 2001 From: Zhongze Hu Date: Wed, 16 Nov 2022 23:59:20 +0800 Subject: [PATCH 23/27] Add bus address for type 09 in pymap.xml The bus address should be added to pymap.xml, otherwise the python interface will not know about it. Signed-off-by: Zhongze Hu --- src/pymap.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/src/pymap.xml b/src/pymap.xml index 5ecc7eb..d021d00 100644 --- a/src/pymap.xml +++ b/src/pymap.xml @@ -304,6 +304,7 @@ + From a6c522c4b5a88b6053e5ef0e429a1c7df5bc1bde Mon Sep 17 00:00:00 2001 From: Zhongze Hu Date: Thu, 17 Nov 2022 00:02:27 +0800 Subject: [PATCH 24/27] Solve dmi_memory_device_extended_size WORD issue In case 17: dmi_memory_device_extended_size(sect_n, WORD(data + 0x1C)); may cause memory capcity read error. This because WORD and DWORD have different byte size, the DWORD is double long of WORD. After SMBIOS v2.8.0, the structures assume to be little-endian order. So redefine the WORD and DWORD in types.h. Signed-off-by: Zhongze Hu --- src/dmidecode.c | 2 +- src/types.h | 22 ++++++++++------------ 2 files changed, 11 insertions(+), 13 deletions(-) diff --git a/src/dmidecode.c b/src/dmidecode.c index 7fb1c89..d1a10c1 100644 --- a/src/dmidecode.c +++ b/src/dmidecode.c @@ -5378,7 +5378,7 @@ xmlNode *dmi_decode(xmlNode *prnt_n, dmi_codes_major *dmiMajor, struct dmi_heade dmi_memory_device_width(sect_n, "TotalWidth", WORD(data + 0x08)); dmi_memory_device_width(sect_n, "DataWidth", WORD(data + 0x0A)); if (h->length >= 0x20 && WORD(data + 0x0C) == 0x7FFF) { - dmi_memory_device_extended_size(sect_n, WORD(data + 0x1C)); + dmi_memory_device_extended_size(sect_n, DWORD(data + 0x1C)); } else { dmi_memory_device_size(sect_n, WORD(data + 0x0C)); } diff --git a/src/types.h b/src/types.h index 5f3dcd4..2570c7c 100644 --- a/src/types.h +++ b/src/types.h @@ -69,20 +69,18 @@ static inline u64 U64(u32 low, u32 high) } #endif -#ifdef ALIGNMENT_WORKAROUND -# ifdef BIGENDIAN -# define WORD(x) (u16)((x)[1]+((x)[0]<<8)) -# define DWORD(x) (u32)((x)[3]+((x)[2]<<8)+((x)[1]<<16)+((x)[0]<<24)) -# define QWORD(x) (U64(DWORD(x+4), DWORD(x))) -# else /* BIGENDIAN */ -# define WORD(x) (u16)((x)[0]+((x)[1]<<8)) -# define DWORD(x) (u32)((x)[0]+((x)[1]<<8)+((x)[2]<<16)+((x)[3]<<24)) -# define QWORD(x) (U64(DWORD(x), DWORD(x+4))) -# endif /* BIGENDIAN */ -#else /* ALIGNMENT_WORKAROUND */ +/* + * Per SMBIOS v2.8.0 and later, all structures assume a little-endian + * ordering convention. + */ +#if defined(ALIGNMENT_WORKAROUND) || defined(BIGENDIAN) +#define WORD(x) (u16)((x)[0] + ((x)[1] << 8)) +#define DWORD(x) (u32)((x)[0] + ((x)[1] << 8) + ((x)[2] << 16) + ((x)[3] << 24)) +#define QWORD(x) (U64(DWORD(x), DWORD(x + 4))) +#else /* ALIGNMENT_WORKAROUND || BIGENDIAN */ #define WORD(x) (u16)(*(const u16 *)(x)) #define DWORD(x) (u32)(*(const u32 *)(x)) #define QWORD(x) (*(const u64 *)(x)) -#endif /* ALIGNMENT_WORKAROUND */ +#endif /* ALIGNMENT_WORKAROUND || BIGENDIAN */ #endif From 9456ca94685e5666569feba02fabc4711550ee3b Mon Sep 17 00:00:00 2001 From: Zhongze Hu Date: Thu, 17 Nov 2022 12:58:22 +0800 Subject: [PATCH 25/27] Add defined BIGENDIAN in types.h Since ALIGNMENT_WORKAROUND and BIGENDIAN are merged into one if macro in the new line 76, BIGENDIAN should also be added in line 60's ifdef macro, otherwise U64 will be undefined when only BIGENDIAN is defined. Signed-off-by: Zhongze Hu --- src/types.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/types.h b/src/types.h index 2570c7c..218f31a 100644 --- a/src/types.h +++ b/src/types.h @@ -57,7 +57,7 @@ typedef struct { } u64; #endif -#ifdef ALIGNMENT_WORKAROUND +#if defined(ALIGNMENT_WORKAROUND) || defined(BIGENDIAN) static inline u64 U64(u32 low, u32 high) { u64 self; From 48618016d85d0890e1675b9e7bee18ee0bc63712 Mon Sep 17 00:00:00 2001 From: Lianbo Jiang Date: Fri, 18 Nov 2022 10:12:42 +0800 Subject: [PATCH 26/27] v3.12.3 Signed-off-by: Lianbo Jiang --- contrib/python-dmidecode.spec | 5 ++++- src/version.h | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/contrib/python-dmidecode.spec b/contrib/python-dmidecode.spec index 2c74597..2c7f942 100644 --- a/contrib/python-dmidecode.spec +++ b/contrib/python-dmidecode.spec @@ -3,7 +3,7 @@ Summary: Python module to access DMI data Name: python-dmidecode -Version: 3.12.2 +Version: 3.12.3 Release: 1%{?dist} License: GPLv2 Group: System Environment/Libraries @@ -49,6 +49,9 @@ rm -rf $RPM_BUILD_ROOT %{_datadir}/python-dmidecode/ %changelog +* Thu Nov 17 2022 Lianbo Jiang - 3.12.3-1 +- Update to new release + * Mon Jun 08 2015 Nima Talebi - 3.12.2-1 - Update to new release diff --git a/src/version.h b/src/version.h index 9938205..68d060d 100644 --- a/src/version.h +++ b/src/version.h @@ -1 +1 @@ -#define VERSION "3.12.2" +#define VERSION "3.12.3" From c217e2bd9dfbd23c04dac19759a2d59845fcd6f6 Mon Sep 17 00:00:00 2001 From: Lichen Liu Date: Mon, 6 Feb 2023 14:46:47 +0800 Subject: [PATCH 27/27] Fix dmi_cache_size_2 will add unit twice. Signed-off-by: Lichen Liu --- src/dmidecode.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/dmidecode.c b/src/dmidecode.c index d1a10c1..d40f0ee 100644 --- a/src/dmidecode.c +++ b/src/dmidecode.c @@ -1843,8 +1843,6 @@ void dmi_cache_size_2(xmlNode *node, const char *tagname, u32 code) size.l = code << 6; size.h = code >> 26; } else { - dmixml_AddAttribute(caches_n, "unit", "KB"); - dmixml_AddTextContent(caches_n, "%i", code); size.l = code; size.h = 0; }