This patch uses cpuid to determine the number of packages/sockets in which to
generate the proper number of DMI/SMBIOS Type 4 (Processor Information)
records.

Use "dmidevcode -t 4" to show that only the configured number of
packages/sockets are shown versus the number of CPUs (sockets*cores*threads).

Signed-off-by: Bret Ketchum <bcketchum at gmail.com>
---
 src/fw/smbios.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 48 insertions(+), 2 deletions(-)

diff --git a/src/fw/smbios.c b/src/fw/smbios.c
index affb9be..23869b1 100644
--- a/src/fw/smbios.c
+++ b/src/fw/smbios.c
@@ -505,6 +505,52 @@ smbios_init_type_127(void *start)
 
 #define TEMPSMBIOSSIZE (32 * 1024)
 
+static inline void
+cpuid_count(u32 index, u32 sub, u32 *eax, u32 *ebx, u32 *ecx, u32 *edx)
+{
+    asm volatile("cpuid"
+                 : "=a" (*eax), "=b" (*ebx), "=c" (*ecx), "=d" (*edx)
+                 :  "0" (index), "c" (sub));
+}
+
+static int package_count(void)
+{
+    char vendor[12];
+    int ret = CountCPUs;
+    u32 cpuid_features, cpuid_high, cpuid_procinfo, cpuid_signature;
+    u32 eax, ebx, ecx, edx;
+
+    cpuid(0, &cpuid_high, &ebx, &ecx, &edx);
+    ((u32 *)&vendor)[0] = ebx;
+    ((u32 *)&vendor)[1] = edx;
+    ((u32 *)&vendor)[2] = ecx;
+
+    cpuid(1, &cpuid_signature, &cpuid_procinfo, &ecx, &cpuid_features);
+
+    if (memcmp(vendor, "GenuineIntel", sizeof(vendor)) == 0) {
+        int logical =   (cpuid_features & 0x10000000) != 0
+                        ? (cpuid_procinfo >> 16) & 0xff
+                        : 1;
+
+        cpuid_count(4, 0, &eax, &ebx, &ecx, &edx);
+
+        /* number of packages/sockets equals the number ACPI IDs
+         * divided by the "Maximum number of addressable IDs for
+         * logical processors in this physical package.
+         */
+        ret = MaxCountCPUs / ((logical == 1)
+                              ? (((eax >> 26) & 0x3f) + 1)
+                              : logical);
+
+    } else {
+        cpuid(0x80000008, &eax, &ebx, &ecx, &edx);
+
+        ret = ((cpuid_procinfo >> 16) & 0xff) / ((ecx & 0xff) + 1);
+    }
+
+    return(ret);
+}
+
 void
 smbios_setup(void)
 {
@@ -538,8 +584,8 @@ smbios_setup(void)
     add_struct(1, p);
     add_struct(3, p);
 
-    int cpu_num;
-    for (cpu_num = 1; cpu_num <= MaxCountCPUs; cpu_num++)
+    int cpu_num, pkg_count = package_count();
+    for (cpu_num = 1; cpu_num <= pkg_count; cpu_num++)
         add_struct(4, p, cpu_num);
 
     int ram_mb = (RamSize + RamSizeOver4G) >> 20;
--
1.8.3.1