--- dmi.c	2010-07-09 04:27:29.000000000 +0200
+++ dmi_sn.c	2010-07-09 04:39:25.000000000 +0200
@@ -2,6 +2,7 @@
  * This file is part of the flashrom project.
  *
  * Copyright (C) 2009,2010 Michael Karcher
+ * Copyright (C) 2010 Sean Nelson
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
@@ -22,6 +23,10 @@
 #include <stdio.h>
 #include <stdlib.h>
 
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/mman.h>
+
 #include "flash.h"
 
 int has_dmi_support = 0;
@@ -44,23 +49,172 @@
 
 #else /* STANDALONE */
 
-static const char *dmidecode_names[] = {
-	"system-manufacturer",
-	"system-product-name",
-	"system-version",
-	"baseboard-manufacturer",
-	"baseboard-product-name",
-	"baseboard-version",
+/* the actual code, based on the dmidecode parsing logic */
+static const struct string_keyword {
+	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 },
 };
 
+#if 1
 #define DMI_COMMAND_LEN_MAX 260
 static const char *dmidecode_command = "dmidecode";
+char *external_dmi[ARRAY_SIZE(flashrom_dmi_strings)];
+#define DMI_MAX_ANSWER_LEN 4096
+#endif
 
-static char *dmistrings[ARRAY_SIZE(dmidecode_names)];
+static char *dmistrings[ARRAY_SIZE(flashrom_dmi_strings)];
 
-/* Strings longer than 4096 in DMI are just insane. */
-#define DMI_MAX_ANSWER_LEN 4096
+#define WORD(x) (unsigned short)(*(const unsigned short *)(x))
+#define DWORD(x) (unsigned int)(*(const unsigned int *)(x))
+
+static int 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 *bp, unsigned char length, unsigned char s)
+{
+	size_t i, len;
+
+	if (s == 0)
+		return "Not Specified";
+
+	bp += length;
+	while (s > 1 && *bp) {
+		bp += strlen(bp);
+		bp++;
+		s--;
+	}
+
+	if (!*bp)
+		return "<BAD INDEX>";
 
+	len = strlen(bp);
+	for (i = 0; i < len; i++)
+		if (bp[i] < 32 || bp[i] == 127)
+			bp[i] = '.';
+
+	return bp;
+}
+
+static int dmi_chassis_type(unsigned char code)
+{
+	switch(code) {
+		case 0x08: /* Portable */
+		case 0x09: /* Laptop */
+		case 0x0A: /* Notebook */
+		case 0x0E: /* Sub Notebook */
+			return 1;
+		default:
+			return 0;
+	}
+}
+
+static void dmi_table(unsigned int base, unsigned short len, unsigned short num)
+{
+	unsigned char *data;
+	unsigned char *dmi_table_mem;
+	int key;
+	int i=0, j=0;
+
+	dmi_table_mem = physmap_try_ro("DMI Tables", base, len);
+	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;
+
+			key = (type << 8) | offset;
+
+			switch (key)
+			{
+			case 0x305: /* detect if laptop */
+				if (dmi_chassis_type(data[offset])) {
+					msg_pdbg("Laptop detected via DMI\n");
+					is_laptop = 1;
+				}
+				break;
+			default:
+				if (type == data[0]) {
+					dmistrings[j] = dmi_string((char*)data,	data[1], data[offset]);
+					msg_pinfo("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 (!checksum(buf, buf[0x05]) 
+		|| (memcmp(buf + 0x10, "_DMI_", 5) != 0) 
+		|| !checksum(buf + 0x10, 0x0F))
+			return 0;
+
+	dmi_table(DWORD(buf + 0x18), WORD(buf + 0x16), WORD(buf + 0x1C));
+
+	return 1;
+}
+
+static int legacy_decode(unsigned char *buf)
+{
+	if (!checksum(buf, 0x0F))
+		return 0;
+
+	dmi_table(DWORD(buf + 0x08), WORD(buf + 0x06), WORD(buf + 0x0C));
+
+	return 1;
+}
+
+#if 1
 static char *get_dmi_string(const char *string_name)
 {
 	FILE *dmidecode_pipe;
@@ -106,28 +260,59 @@
 
 	return result;
 }
+#endif
 
 void dmi_init(void)
 {
-	int i;
-	char *chassis_type;
+	int i = 0;
+	int found = 0;
+	size_t fp;
+	unsigned char *dmi_mem;
 
 	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;
+
+	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++;
+	}
+
+#if 1
+	for (i = 0;  i < ARRAY_SIZE(flashrom_dmi_strings); i++)
+	{
+		external_dmi[i] = get_dmi_string(flashrom_dmi_strings[i].keyword);
+		if (!external_dmi[i])
+			goto func_exit;
 	}
 
-	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");
-		is_laptop = 1;
+	for (i = 0;  i < ARRAY_SIZE(flashrom_dmi_strings)-1; i++)
+	{
+		if (strcmp(dmistrings[i], external_dmi[i])) 
+			msg_perr("dmidecode vs internal-dmi differs: %s\n", flashrom_dmi_strings[i].keyword);
+		else
+			msg_pspew("Matching of dmidecode and internal-dmi succeeded!\n");
 	}
-	free(chassis_type);
+#endif
+
+func_exit:
+	if (!found)
+	{
+		msg_pinfo("No DMI table found.\n");
+		has_dmi_support = 0;
+	}
+
+	physunmap(dmi_mem, 0x10000);
 }
 
 /**
@@ -185,7 +370,7 @@
 	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;
 
