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 Nelson<[email protected]>
Looks like you forgot to attach the patch.

Regards,
Carl-Daniel

Opps!

diff --git a/dmi.c b/dmi.c
index f18907f..3abefba 100644
--- a/dmi.c
+++ b/dmi.c
@@ -18,38 +18,304 @@
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 USA
  */
 
 #include <string.h>
 #include <stdio.h>
 #include <stdlib.h>
 
 #include "flash.h"
 #include "programmer.h"
 
 int has_dmi_support = 0;
 
 #if STANDALONE
+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 },
+};
 
-/* 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.
+/* A full list of chassis types can be found in the System Management BIOS
+ * (SMBIOS) Reference Specification 2.7.0 section 7.4.1 "Chassis Types" at
+ * 
http://www.dmtf.org/sites/default/files/standards/documents/DSP0134_2.7.0.pdf
+ * The types below are the most common ones.
  */
+static const struct {
+       unsigned char type;
+       unsigned char is_laptop;
+       const char *name;
+} dmi_chassis_types[] = {
+       {0x01, 0, "Other"},
+       {0x02, 0, "Unknown"},
+       {0x03, 0, "Desktop",},
+       {0x08, 1, "Portable"},
+       {0x09, 1, "Laptop"},
+       {0x0a, 1, "Notebook"},
+       {0x0b, 1, "Hand Held"},
+       {0x0e, 1, "Sub Notebook"},
+};
+
+static char *dmistrings[ARRAY_SIZE(flashrom_dmi_strings)];
+
+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);
+}
+
+/**
+ * Does an substring/prefix/postfix/whole-string match.
+ *
+ * The pattern is matched as-is. The only metacharacters supported are '^'
+ * at the beginning and '$' at the end. So you can look for "^prefix",
+ * "suffix$", "substring" or "^complete string$".
+ *
+ * @param value The string to check.
+ * @param pattern The pattern.
+ * @return Nonzero if pattern matches.
+ */
+static int dmi_compare(const char *value, const char *pattern)
+{
+       int anchored = 0;
+       int patternlen;
+
+       msg_pspew("matching %s against %s\n", value, pattern);
+       /* The empty string is part of all strings! */
+       if (pattern[0] == 0)
+               return 1;
+
+       if (pattern[0] == '^') {
+               anchored = 1;
+               pattern++;
+       }
+
+       patternlen = strlen(pattern);
+       if (pattern[patternlen - 1] == '$') {
+               int valuelen = strlen(value);
+               patternlen--;
+               if (patternlen > valuelen)
+                       return 0;
+
+               /* full string match: require same length */
+               if (anchored && (valuelen != patternlen))
+                       return 0;
+
+               /* start character to make ends match */
+               value += valuelen - patternlen;
+               anchored = 1;
+       }
+
+       if (anchored)
+               return strncmp(value, pattern, patternlen) == 0;
+       else
+               return strstr(value, pattern) != NULL;
 }
 
 int dmi_match(const char *pattern)
 {
+       int i;
+
+       if (!has_dmi_support)
+               return 0;
+
+       for (i = 0; i < ARRAY_SIZE(flashrom_dmi_strings); i++)
+               if (dmi_compare(dmistrings[i], pattern))
+                       return 1;
+
        return 0;
 }
 
 #else /* STANDALONE */
 
 static const char *dmidecode_names[] = {
        "system-manufacturer",
        "system-product-name",
        "system-version",
        "baseboard-manufacturer",
        "baseboard-product-name",
        "baseboard-version",
 };
@@ -112,26 +378,27 @@ static char *get_dmi_string(const char *string_name)
 
        result = strdup(answerbuf);
        if (!result)
                puts("WARNING: Out of memory - DMI support fails");
 
        return result;
 }
 
 void dmi_init(void)
 {
        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]);
                if (!dmistrings[i]) {
                        has_dmi_support = 0;
                        return;
                }
        }
 
        chassis_type = get_dmi_string("chassis-type");
        if (chassis_type && (!strcmp(chassis_type, "Notebook") ||
                             !strcmp(chassis_type, "Portable"))) {
                msg_pdbg("Laptop detected via DMI\n");
_______________________________________________
flashrom mailing list
[email protected]
http://www.flashrom.org/mailman/listinfo/flashrom

Reply via email to