Blob Blame History Raw
From 65ce2362e59d8818fb23effb21d96d79334e77f8 Mon Sep 17 00:00:00 2001
From: Jeffrey Bastian <jbastian@redhat.com>
Date: Thu, 10 Sep 2015 16:24:10 -0500
Subject: [PATCH] use sysfs for DMI info when available (#696, #666, #664)

backport from upstream commit 8237f8ebb92e (or r2579 from subversion)
fixes BZ 1261570: lshw triggers kernel "Oops - bad mode: 0 [#1] SMP" on AMD Seattle
---
 src/core/dmi.cc | 183 +++++++++++++++++++++++++++++++++++---------------------
 1 file changed, 114 insertions(+), 69 deletions(-)

diff --git a/src/core/dmi.cc b/src/core/dmi.cc
index ec1e25a2d644..14b1bd3c07e3 100644
--- a/src/core/dmi.cc
+++ b/src/core/dmi.cc
@@ -82,7 +82,9 @@

 #include <map>
 #include <vector>
+#include <fstream>

+#include <stdint.h>
 #include <stdio.h>
 #include <unistd.h>
 #include <fcntl.h>
@@ -92,11 +94,13 @@

 __ID("@(#) $Id: dmi.cc 2520 2013-05-08 13:32:48Z lyonel $");

+#define SYSFSDMI "/sys/firmware/dmi/tables"
+
 static int currentcpu = 0;

-typedef unsigned char u8;
-typedef unsigned short u16;
-typedef unsigned int u32;
+typedef uint8_t u8;
+typedef uint16_t u16;
+typedef uint32_t u32;

 struct dmi_header
 {
@@ -174,7 +178,7 @@ static string cpubusinfo(int cpu)
 }


-static string dmi_uuid(u8 * p)
+static string dmi_uuid(const u8 * p)
 {
   unsigned int i = 0;
   bool valid = false;
@@ -357,7 +361,7 @@ hwNode & bios)
 }


-static void dmi_bios_features_ext(u8 * data,
+static void dmi_bios_features_ext(const u8 * data,
 int len,
 hwNode & bios)
 {
@@ -932,43 +936,22 @@ static string dmi_handle(u16 handle)
 }


-static void dmi_table(int fd,
-u32 base,
+static void dmi_table(const u8 *buf,
 int len,
-int num,
 hwNode & node,
 int dmiversionmaj,
 int dmiversionmin)
 {
-  unsigned char *buf = (unsigned char *) malloc(len);
   struct dmi_header *dm;
   hwNode *hardwarenode = NULL;
-  u8 *data;
+  const u8 *data;
   int i = 0;
   string handle;
-  u32 mmoffset = 0;
-  void *mmp = NULL;

   if (len == 0)
 // no data
     return;

-  if (buf == NULL)
-// memory exhausted
-    return;
-
-  mmoffset = base % getpagesize();
-
-  mmp = mmap(0, mmoffset + len, PROT_READ, MAP_SHARED, fd, base - mmoffset);
-  if (mmp == MAP_FAILED)
-  {
-    free(buf);
-    return;
-  }
-  memcpy(buf, (u8 *) mmp + mmoffset, len);
-
-  munmap(mmp, mmoffset + len);
-
   data = buf;
   while (data + sizeof(struct dmi_header) <= (u8 *) buf + len)
   {
@@ -1276,7 +1259,7 @@ int dmiversionmin)
         {
           hwNode newnode("cache",
             hw::memory);
-          int level;
+	  int level;

           newnode.setSlot(dmi_string(dm, data[4]));
           u = data[6] << 8 | data[5];
@@ -1291,6 +1274,7 @@ int dmiversionmin)
           if (!(u & (1 << 7)))
             newnode.disable();

+          newnode.setConfig("level", level);
           newnode.setSize(dmi_cache_size(data[9] | data[10] << 8));
           newnode.setCapacity(dmi_cache_size(data[7] | (data[8] << 8)));
           if ((dm->length > 0x0F) && (data[0x0F] != 0))
@@ -1713,10 +1697,76 @@ int dmiversionmin)
     data += 2;
     i++;
   }
-  free(buf);
 }


+static bool smbios_entry_point(const u8 *buf, size_t len,
+    hwNode & n, u16 & dmimaj, u16 & dmimin,
+    u16 & table_len, u32 & table_base)
+{
+  if (len < 31 || memcmp(buf, "_SM_", 4) != 0)
+    return false;
+
+  u8 smmajver = buf[6];
+  u8 smminver = buf[7];
+
+  buf += 16;
+  if (smmajver && (memcmp(buf, "_DMI_", 5) == 0) && checksum(buf, 0x0F))
+  {
+    table_len = buf[7] << 8 | buf[6];
+    table_base = buf[11] << 24 | buf[10] << 16 | buf[9] << 8 | buf[8];
+    dmimaj = buf[14] ? buf[14] >> 4 : smmajver;
+    dmimin = buf[14] ? buf[14] & 0x0F : smminver;
+
+    char buffer[20];
+    snprintf(buffer, sizeof(buffer), "%d.%d", smmajver, smminver);
+    n.addCapability("smbios-"+string(buffer), "SMBIOS version "+string(buffer));
+    snprintf(buffer, sizeof(buffer), "%d.%d", dmimaj, dmimin);
+    n.addCapability("dmi-"+string(buffer), "DMI version "+string(buffer));
+
+    return true;
+  }
+
+  return false;
+}
+
+
+static bool scan_dmi_sysfs(hwNode & n)
+{
+  if (!exists(SYSFSDMI "/smbios_entry_point") || !exists(SYSFSDMI "/DMI"))
+    return false;
+
+  u16 table_len = 0;
+  u32 table_base = 0;
+  u16 dmimaj = 0, dmimin = 0;
+
+  ifstream ep_stream(SYSFSDMI "/smbios_entry_point",
+      ifstream::in | ifstream::binary | ifstream::ate);
+  ifstream::pos_type ep_len = ep_stream.tellg();
+  vector < u8 > ep_buf(ep_len);
+  ep_stream.seekg(0, ifstream::beg);
+  ep_stream.read((char *)ep_buf.data(), ep_len);
+  if (!ep_stream)
+    return false;
+  if (!smbios_entry_point(ep_buf.data(), ep_len, n,
+        dmimaj, dmimin, table_len, table_base))
+    return false;
+
+  ifstream dmi_stream(SYSFSDMI "/DMI",
+      ifstream::in | ifstream::binary | ifstream::ate);
+  ifstream::pos_type dmi_len = dmi_stream.tellg();
+  vector < u8 > dmi_buf(dmi_len);
+  dmi_stream.seekg(0, ifstream::beg);
+  dmi_stream.read((char *)dmi_buf.data(), dmi_len);
+  if (!dmi_stream)
+    return false;
+  dmi_table(dmi_buf.data(), dmi_len, n, dmimaj, dmimin);
+
+  return true;
+}
+
+
+#if defined(__i386__) || defined(__x86_64__) || defined(__ia64__)
 long get_efi_systab_smbios()
 {
   long result = 0;
@@ -1739,26 +1789,17 @@ long get_efi_systab_smbios()
 }


-bool scan_dmi(hwNode & n)
+static bool scan_dmi_devmem(hwNode & n)
 {
-  unsigned char buf[20];
+  unsigned char buf[31];
   int fd = open("/dev/mem",
     O_RDONLY);
   long fp = get_efi_systab_smbios();
   u32 mmoffset = 0;
   void *mmp = NULL;
   bool efi = true;
-  u8 smmajver = 0, smminver = 0;
   u16 dmimaj = 0, dmimin = 0;
-  currentcpu = 0;
-
-#if defined(__arm__) || defined (__hppa__)  || defined (__s390x__) || defined (__powerpc__)
-  return false;		// SMBIOS not supported on PA-RISC, S/390, ARM and PowerPC machines
-#endif

-  if (sizeof(u8) != 1 || sizeof(u16) != 2 || sizeof(u32) != 4)
-// compiler incompatibility
-    return false;
   if (fd == -1)
     return false;

@@ -1785,38 +1826,42 @@ bool scan_dmi(hwNode & n)
       close(fd);
       return false;
     }
-    else if (memcmp(buf, "_SM_", 4) == 0)
+    u16 len;
+    u32 base;
+    if (smbios_entry_point(buf, sizeof(buf), n, dmimaj, dmimin, len, base))
     {
-// SMBIOS
-      smmajver = buf[6];
-      smminver = buf[7];
-    }
-    else if (smmajver && (memcmp(buf, "_DMI_", 5) == 0) && checksum(buf, 0x0F))
-    {
-      u16 num = buf[13] << 8 | buf[12];
-      u16 len = buf[7] << 8 | buf[6];
-      u32 base = buf[11] << 24 | buf[10] << 16 | buf[9] << 8 | buf[8];
-      dmimaj = buf[14] ? buf[14] >> 4 : smmajver;
-      dmimin = buf[14] ? buf[14] & 0x0F : smminver;
-      dmi_table(fd, base, len, num, n, dmimaj, dmimin);
-
-      if (efi)
-        break;                                    // we don't need to search the memory for EFI systems
+      u8 *dmi_buf = (u8 *)malloc(len);
+      mmoffset = base % getpagesize();
+      mmp = mmap(0, mmoffset + len, PROT_READ, MAP_SHARED, fd, base - mmoffset);
+      if (mmp == MAP_FAILED)
+      {
+        free(dmi_buf);
+        return false;
+      }
+      memcpy(dmi_buf, (u8 *) mmp + mmoffset, len);
+      munmap(mmp, mmoffset + len);
+      dmi_table(dmi_buf, len, n, dmimaj, dmimin);
+      free(dmi_buf);
+      break;
     }
+
+    if (efi)
+      break;                                    // we don't need to search the memory for EFI systems
   }
   close(fd);
-  if (smmajver != 0)
-  {
-    char buffer[20];
-    snprintf(buffer, sizeof(buffer), "%d.%d", smmajver, smminver);
-    n.addCapability("smbios-"+string(buffer), "SMBIOS version "+string(buffer));
-  }
-  if (dmimaj != 0)
-  {
-    char buffer[20];
-    snprintf(buffer, sizeof(buffer), "%d.%d", dmimaj, dmimin);
-    n.addCapability("dmi-"+string(buffer), "DMI version "+string(buffer));
-  }

   return true;
 }
+#endif // defined(__i386__) || defined(__x86_64__) || defined(__ia64__)
+
+
+bool scan_dmi(hwNode & n)
+{
+  if (scan_dmi_sysfs(n))
+    return true;
+#if defined(__i386__) || defined(__x86_64__) || defined(__ia64__)
+  if (scan_dmi_devmem(n))
+    return true;
+#endif
+  return false;
+}
--
1.8.3.1