On 27.09.2010 04:28, Sean Nelson wrote:
On 9/26/10 2:45 PM, Carl-Daniel Hailfinger wrote:
On 20.09.2010 02:28, Sean Nelson wrote:
Updated patch 2010-09-19. Uses its own copy of the dmi_chassis_types list. Each dmi_init prints if its either internal DMI or external Dmidecode. Selectable using -D'STANDALONE=1'
Signed-off-by: Sean Nelsonaudiohacked@gmail.com
I killed some duplicated code, but I'm sure there is more potential for cleanup.
Sean, I remember you originally had some code which compared internal and external DMI decoder results. Do you still have that code somewhere?
Add internal DMI decoder, default it to on.
Signed-off-by: Sean Nelsonaudiohacked@gmail.com
Index: flashrom-snelson_internal_dmi/dmi.c =================================================================== --- flashrom-snelson_internal_dmi/dmi.c (Revision 1237) +++ flashrom-snelson_internal_dmi/dmi.c (Arbeitskopie) @@ -25,33 +25,22 @@ #include "flash.h" #include "programmer.h"
+#define STANDALONE 1 + int has_dmi_support = 0;
-#if STANDALONE - -/* Stub to indicate missing DMI functionality. - * has_dmi_support is 0 by default, so nothing to do here. - * Because dmidecode is not available on all systems, the goal is to implement - * the DMI subset we need directly in this file. - */ -void dmi_init(void) -{ -} - -int dmi_match(const char *pattern) -{ - return 0; -} - -#else /* STANDALONE */ - -static const char *dmidecode_names[] = { - "system-manufacturer", - "system-product-name", - "system-version", - "baseboard-manufacturer", - "baseboard-product-name", - "baseboard-version", +static const struct { + const char *keyword; + unsigned char type; + unsigned char offset; +} flashrom_dmi_strings[] = { + { "system-manufacturer", 1, 0x04 }, + { "system-product-name", 1, 0x05 }, + { "system-version", 1, 0x06 }, + { "baseboard-manufacturer", 2, 0x04 }, + { "baseboard-product-name", 2, 0x05 }, + { "baseboard-version", 2, 0x06 }, + { "chassis-type", 3, 0x05 }, };
/* A full list of chassis types can be found in the System Management BIOS @@ -74,11 +63,197 @@ {0x0e, 1, "Sub Notebook"}, };
+static char *dmistrings[ARRAY_SIZE(flashrom_dmi_strings)]; + +#if STANDALONE +static int dmi_checksum(const unsigned char *buf, size_t len) +{ + unsigned char sum = 0; + size_t a; + + for (a = 0; a < len; a++) + sum += buf[a]; + return (sum == 0); +} + +static char *dmi_string(char *buffer, unsigned char length, unsigned char string_id) +{ + size_t i, len; + + if (string_id == 0) + return "Not Specified"; + + buffer += length; /* skip to after the handle's data length byte */ + /* Continue till we hit a null which denotes end of string in dmi + or as long as we're not grabing the first string. The string + should be no longer than 64 bytes. We continue looping because + we "jump" to the data string. */ + for (; string_id > 1; string_id--) { + buffer += strlen(buffer); /* skip previous data strings */ + buffer++; /* skip the data string length byte */ + } + + if (!*buffer) /* as long as the current byte we're on isn't null */ + return "<BAD INDEX>"; + + len = strlen(buffer); + if (len > 64) + len = 64; + + for (i = 0; i < len; i++) /* sometimes we need to fix junk bytes in the string */ + if (buffer[i] < 32 || buffer[i] == 127) + buffer[i] = '.'; + + return buffer; +} + +static int dmi_chassis_type(unsigned char code) +{ + int i; + for (i = 0; i < ARRAY_SIZE(dmi_chassis_types); i++) { + if (code == dmi_chassis_types[i].type) { + break; + } + } + msg_pdbg("DMI string chassis-type: "%s"\n", dmi_chassis_types[i].name ); + if (dmi_chassis_types[i].is_laptop) { + msg_pdbg("Laptop detected via DMI\n"); + is_laptop = 1; + } + return 0; +} + +static void dmi_table(unsigned int base, unsigned short len, unsigned short num) +{ + unsigned char *data; + unsigned char *dmi_table_mem; + int i = 0, j = 0; + + dmi_table_mem = physmap_try_ro("DMI Tables", base, len); + if (!dmi_table_mem) { + msg_perr("Unable to access DMI Tables\n"); + return; + } + + data = dmi_table_mem; + + /* 4 is the length of an SMBIOS structure header */ + while (i < num && data+4 <= dmi_table_mem + len) { + unsigned char *next; + /* + * If a short entry is found (less than 4 bytes), not only it + * is invalid, but we cannot reliably locate the next entry. + * Better stop at this point, and let the user know his/her + * table is broken. + */ + if (data[1] < 4) { + msg_perr("Invalid entry length (%u). DMI table is " + "broken! Stop.\n\n", (unsigned int)data[1]); + break; + } + + /* Stop decoding after chassis segment */ + if (data[0] == 4) + break; + + /* look for the next handle */ + next = data + data[1]; + while (next - dmi_table_mem + 1 < len && (next[0] != 0 || next[1] != 0)) + next++; + next += 2; + + for (j = 0; j < ARRAY_SIZE(flashrom_dmi_strings); j++) + { + unsigned char offset = flashrom_dmi_strings[j].offset; + unsigned char type = flashrom_dmi_strings[j].type; + + if (offset >= data[1]) + return; + + + switch ((type << 8)|offset) + { + case 0x0305: /* detect if laptop */ + if (type == data[0]) { + dmi_chassis_type(data[offset]); + } + break; + default: + if (type == data[0]) { + dmistrings[j] = dmi_string((char*)data, data[1], data[offset]); + msg_pdbg("DMI string %s: "%s"\n", + flashrom_dmi_strings[j].keyword, dmistrings[j]); + } + } + } + data = next; + i++; + } + + physunmap(dmi_table, len); +} + +static int smbios_decode(unsigned char *buf) +{ + if (!dmi_checksum(buf, buf[0x05]) + || (memcmp(buf + 0x10, "_DMI_", 5) != 0) + || !dmi_checksum(buf + 0x10, 0x0F)) + return 0; + + dmi_table(mmio_readl(buf + 0x18), mmio_readw(buf + 0x16), mmio_readw(buf + 0x1C)); + + return 1; +} + +static int legacy_decode(unsigned char *buf) +{ + if (!dmi_checksum(buf, 0x0F)) + return 0; + + dmi_table(mmio_readl(buf + 0x08), mmio_readw(buf + 0x06), mmio_readw(buf + 0x0C)); + + return 1; +} + +void dmi_init(void) +{ + int found = 0; + size_t fp; + unsigned char *dmi_mem = NULL; + has_dmi_support = 1; + + msg_pdbg("Trying Internal DMI decoder.\n"); + dmi_mem = physmap_try_ro("DMI", 0xF0000, 0x10000); + if (!dmi_mem) + goto func_exit; + + for (fp = 0; fp <= 0xFFF0; fp += 16) { + if (memcmp(dmi_mem + fp, "_SM_", 4) == 0 && fp <= 0xFFE0) { + if (smbios_decode(dmi_mem+fp)) { + found++; + fp += 16; + } + } + else if (memcmp(dmi_mem + fp, "_DMI_", 5) == 0) + if (legacy_decode(dmi_mem + fp)) + found++; + } + +func_exit: + if (!found) + { + msg_pinfo("No DMI table found.\n"); + has_dmi_support = 0; + } + + physunmap(dmi_mem, 0x10000); +} + +#else /* STANDALONE */ + #define DMI_COMMAND_LEN_MAX 260 static const char *dmidecode_command = "dmidecode";
-static char *dmistrings[ARRAY_SIZE(dmidecode_names)]; - /* Strings longer than 4096 in DMI are just insane. */ #define DMI_MAX_ANSWER_LEN 4096
@@ -142,9 +317,10 @@ int i; char *chassis_type;
+ msg_pdbg("Trying External DMI decoder.\n"); has_dmi_support = 1; - for (i = 0; i < ARRAY_SIZE(dmidecode_names); i++) { - dmistrings[i] = get_dmi_string(dmidecode_names[i]); + for (i = 0; i < ARRAY_SIZE(flashrom_dmi_strings); i++) { + dmistrings[i] = get_dmi_string(flashrom_dmi_strings[i].keyword); if (!dmistrings[i]) { has_dmi_support = 0; return; @@ -165,6 +341,8 @@ free(chassis_type); }
+#endif /* STANDALONE */ + /** * Does an substring/prefix/postfix/whole-string match. * @@ -220,11 +398,9 @@ if (!has_dmi_support) return 0;
- for (i = 0; i < ARRAY_SIZE(dmidecode_names); i++) + for (i = 0; i < ARRAY_SIZE(flashrom_dmi_strings); i++) if (dmi_compare(dmistrings[i], pattern)) return 1;
return 0; } - -#endif /* STANDALONE */