[flashrom] [PATCH] internal dmi decoder
Carl-Daniel Hailfinger
c-d.hailfinger.devel.2006 at gmx.net
Tue Nov 30 15:50:10 CET 2010
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 Nelson<audiohacked at 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 Nelson<audiohacked at 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 */
--
http://www.hailfinger.org/
More information about the flashrom
mailing list