--- a/xen/arch/x86/dmi_scan.c
+++ b/xen/arch/x86/dmi_scan.c
@@ -38,6 +38,18 @@ struct __packed smbios_eps {
 	struct dmi_eps dmi;
 };
 
+struct __packed smbios3_eps {
+	char anchor[5];			/* "_SM3_" */
+	u8 checksum;
+	u8 length;
+	u8 major, minor;
+	u8 docrev;
+	u8 revision;
+	u8 _rsrvd_;
+	u32 max_size;
+	u64 address;
+};
+
 struct dmi_header
 {
 	u8	type;
@@ -45,6 +57,53 @@ struct dmi_header
 	u16	handle;
 };
 
+enum dmi_entry_type {
+	DMI_ENTRY_BIOS = 0,
+	DMI_ENTRY_SYSTEM,
+	DMI_ENTRY_BASEBOARD,
+	DMI_ENTRY_CHASSIS,
+	DMI_ENTRY_PROCESSOR,
+	DMI_ENTRY_MEM_CONTROLLER,
+	DMI_ENTRY_MEM_MODULE,
+	DMI_ENTRY_CACHE,
+	DMI_ENTRY_PORT_CONNECTOR,
+	DMI_ENTRY_SYSTEM_SLOT,
+	DMI_ENTRY_ONBOARD_DEVICE,
+	DMI_ENTRY_OEMSTRINGS,
+	DMI_ENTRY_SYSCONF,
+	DMI_ENTRY_BIOS_LANG,
+	DMI_ENTRY_GROUP_ASSOC,
+	DMI_ENTRY_SYSTEM_EVENT_LOG,
+	DMI_ENTRY_PHYS_MEM_ARRAY,
+	DMI_ENTRY_MEM_DEVICE,
+	DMI_ENTRY_32_MEM_ERROR,
+	DMI_ENTRY_MEM_ARRAY_MAPPED_ADDR,
+	DMI_ENTRY_MEM_DEV_MAPPED_ADDR,
+	DMI_ENTRY_BUILTIN_POINTING_DEV,
+	DMI_ENTRY_PORTABLE_BATTERY,
+	DMI_ENTRY_SYSTEM_RESET,
+	DMI_ENTRY_HW_SECURITY,
+	DMI_ENTRY_SYSTEM_POWER_CONTROLS,
+	DMI_ENTRY_VOLTAGE_PROBE,
+	DMI_ENTRY_COOLING_DEV,
+	DMI_ENTRY_TEMP_PROBE,
+	DMI_ENTRY_ELECTRICAL_CURRENT_PROBE,
+	DMI_ENTRY_OOB_REMOTE_ACCESS,
+	DMI_ENTRY_BIS_ENTRY,
+	DMI_ENTRY_SYSTEM_BOOT,
+	DMI_ENTRY_MGMT_DEV,
+	DMI_ENTRY_MGMT_DEV_COMPONENT,
+	DMI_ENTRY_MGMT_DEV_THRES,
+	DMI_ENTRY_MEM_CHANNEL,
+	DMI_ENTRY_IPMI_DEV,
+	DMI_ENTRY_SYS_POWER_SUPPLY,
+	DMI_ENTRY_ADDITIONAL,
+	DMI_ENTRY_ONBOARD_DEV_EXT,
+	DMI_ENTRY_MGMT_CONTROLLER_HOST,
+	DMI_ENTRY_INACTIVE = 126,
+	DMI_ENTRY_END_OF_TABLE = 127,
+};
+
 #undef DMI_DEBUG
 
 #ifdef DMI_DEBUG
@@ -74,7 +133,8 @@ static char * __init dmi_string(struct d
  *	pointing to completely the wrong place for example
  */
  
-static int __init dmi_table(u32 base, int len, int num, void (*decode)(struct dmi_header *))
+static int __init dmi_table(paddr_t base, u32 len, int num,
+			    void (*decode)(struct dmi_header *))
 {
 	u8 *buf;
 	struct dmi_header *dm;
@@ -92,7 +152,7 @@ static int __init dmi_table(u32 base, in
  	 *	OR we run off the end of the table (also happens)
  	 */
  
-	while(i<num && data-buf+sizeof(struct dmi_header)<=len)
+	while((num < 0 || i < num) && data-buf+sizeof(struct dmi_header)<=len)
 	{
 		dm=(struct dmi_header *)data;
 		/*
@@ -105,6 +165,8 @@ static int __init dmi_table(u32 base, in
 			data++;
 		if(data-buf<len-1)
 			decode(dm);
+		if (dm->type == DMI_ENTRY_END_OF_TABLE)
+		    break;
 		data+=2;
 		i++;
 	}
@@ -127,16 +189,28 @@ static inline bool_t __init dmi_checksum
 
 static u32 __initdata efi_dmi_address;
 static u32 __initdata efi_dmi_size;
+static u64 __initdata efi_smbios3_address;
+static u32 __initdata efi_smbios3_size;
 
 /*
  * Important: This function gets called while still in EFI
  * (pseudo-)physical mode.
  */
-void __init dmi_efi_get_table(void *smbios)
+void __init dmi_efi_get_table(const void *smbios, const void *smbios3)
 {
-	struct smbios_eps *eps = smbios;
+	const struct smbios_eps *eps = smbios;
+	const struct smbios3_eps *eps3 = smbios3;
+
+	if (eps3 && memcmp(eps3->anchor, "_SM3_", 5) &&
+	    eps3->length >= sizeof(*eps3) &&
+	    dmi_checksum(eps3, eps3->length)) {
+		efi_smbios3_address = eps3->address;
+		efi_smbios3_size = eps3->max_size;
+		return;
+	}
 
-	if (memcmp(eps->anchor, "_SM_", 4) &&
+	if (eps && memcmp(eps->anchor, "_SM_", 4) &&
+	    eps->length >= sizeof(*eps) &&
 	    dmi_checksum(eps, eps->length) &&
 	    memcmp(eps->dmi.anchor, "_DMI_", 5) == 0 &&
 	    dmi_checksum(&eps->dmi, sizeof(eps->dmi))) {
@@ -145,99 +219,190 @@ void __init dmi_efi_get_table(void *smbi
 	}
 }
 
-int __init dmi_get_table(u32 *base, u32 *len)
+const char *__init dmi_get_table(paddr_t *base, u32 *len)
 {
-	struct dmi_eps eps;
-	char __iomem *p, *q;
+	static unsigned int __initdata instance;
 
 	if (efi_enabled) {
-		if (!efi_dmi_size)
-			return -1;
-		*base = efi_dmi_address;
-		*len = efi_dmi_size;
-		return 0;
-	}
-
-	p = maddr_to_virt(0xF0000);
-	for (q = p; q < p + 0x10000; q += 16) {
-		memcpy_fromio(&eps, q, 15);
-		if (memcmp(eps.anchor, "_DMI_", 5) == 0 &&
-		    dmi_checksum(&eps, sizeof(eps))) {
-			*base = eps.address;
-			*len = eps.size;
-			return 0;
+		if (efi_smbios3_size && !(instance & 1)) {
+			*base = efi_smbios3_address;
+			*len = efi_smbios3_size;
+			instance |= 1;
+			return "SMBIOSv3";
+		}
+		if (efi_dmi_size && !(instance & 2)) {
+			*base = efi_dmi_address;
+			*len = efi_dmi_size;
+			instance |= 2;
+			return "DMI";
+		}
+	} else {
+		char __iomem *p = maddr_to_virt(0xF0000), *q;
+		union {
+			struct dmi_eps dmi;
+			struct smbios3_eps smbios3;
+		} eps;
+
+		for (q = p; q <= p + 0x10000 - sizeof(eps.dmi); q += 16) {
+			memcpy_fromio(&eps, q, sizeof(eps.dmi));
+			if (!(instance & 1) &&
+			    memcmp(eps.dmi.anchor, "_DMI_", 5) == 0 &&
+			    dmi_checksum(&eps.dmi, sizeof(eps.dmi))) {
+				*base = eps.dmi.address;
+				*len = eps.dmi.size;
+				instance |= 1;
+				return "DMI";
+			}
+
+			BUILD_BUG_ON(sizeof(eps.smbios3) <= sizeof(eps.dmi));
+			if ((instance & 2) ||
+			    q > p + 0x10000 - sizeof(eps.smbios3))
+				continue;
+			memcpy_fromio(&eps.dmi + 1, q + sizeof(eps.dmi),
+			              sizeof(eps.smbios3) - sizeof(eps.dmi));
+			if (!memcmp(eps.smbios3.anchor, "_SM3_", 5) &&
+			    eps.smbios3.length >= sizeof(eps.smbios3) &&
+			    q <= p + 0x10000 - eps.smbios3.length &&
+			    dmi_checksum(q, eps.smbios3.length)) {
+				*base = eps.smbios3.address;
+				*len = eps.smbios3.max_size;
+				instance |= 2;
+				return "SMBIOSv3";
+			}
 		}
 	}
-	return -1;
+	return NULL;
 }
 
+typedef union {
+	const struct smbios_eps __iomem *legacy;
+	const struct smbios3_eps __iomem *v3;
+} smbios_eps_u __attribute__((transparent_union));
+
 static int __init _dmi_iterate(const struct dmi_eps *dmi,
-			       const struct smbios_eps __iomem *smbios,
+			       const smbios_eps_u smbios,
 			       void (*decode)(struct dmi_header *))
 {
-	u16 num = dmi->num_structures;
-	u16 len = dmi->size;
-	u32 base = dmi->address;
+	int num;
+	u32 len;
+	paddr_t base;
+
+	if (!dmi) {
+		num = -1;
+		len = smbios.v3->max_size;
+		base = smbios.v3->address;
+		printk(KERN_INFO "SMBIOS %d.%d present.\n",
+		       smbios.v3->major, smbios.v3->minor);
+		dmi_printk((KERN_INFO "SMBIOS v3 table at 0x%"PRIpaddr".\n", base));
+	} else {
+		num = dmi->num_structures;
+		len = dmi->size;
+		base = dmi->address;
 
-	/*
-	 * DMI version 0.0 means that the real version is taken from
-	 * the SMBIOS version, which we may not know at this point.
-	 */
-	if (dmi->revision)
-		printk(KERN_INFO "DMI %d.%d present.\n",
-		       dmi->revision >> 4,  dmi->revision & 0x0f);
-	else if (!smbios)
-		printk(KERN_INFO "DMI present.\n");
-	dmi_printk((KERN_INFO "%d structures occupying %d bytes.\n",
-		    num, len));
-	dmi_printk((KERN_INFO "DMI table at 0x%08X.\n", base));
+		/*
+		 * DMI version 0.0 means that the real version is taken from
+		 * the SMBIOS version, which we may not know at this point.
+		 */
+		if (dmi->revision)
+			printk(KERN_INFO "DMI %d.%d present.\n",
+			       dmi->revision >> 4,  dmi->revision & 0x0f);
+		else if (!smbios.legacy)
+			printk(KERN_INFO "DMI present.\n");
+		dmi_printk((KERN_INFO "%d structures occupying %u bytes.\n",
+			    num, len));
+		dmi_printk((KERN_INFO "DMI table at 0x%08X.\n", (u32)base));
+	}
 	return dmi_table(base, len, num, decode);
 }
 
 static int __init dmi_iterate(void (*decode)(struct dmi_header *))
 {
-	struct dmi_eps eps;
+	struct dmi_eps dmi;
+	struct smbios3_eps smbios3;
 	char __iomem *p, *q;
 
+	dmi.size = 0;
+	smbios3.length = 0;
+
 	p = maddr_to_virt(0xF0000);
 	for (q = p; q < p + 0x10000; q += 16) {
-		memcpy_fromio(&eps, q, sizeof(eps));
-		if (memcmp(eps.anchor, "_DMI_", 5) == 0 &&
-		    dmi_checksum(&eps, sizeof(eps)))
-			return _dmi_iterate(&eps, NULL, decode);
+		if (!dmi.size) {
+			memcpy_fromio(&dmi, q, sizeof(dmi));
+			if (memcmp(dmi.anchor, "_DMI_", 5) ||
+			    !dmi_checksum(&dmi, sizeof(dmi)))
+				dmi.size = 0;
+		}
+		if (!smbios3.length &&
+		    q <= p + 0x10000 - sizeof(smbios3)) {
+			memcpy_fromio(&smbios3, q, sizeof(smbios3));
+			if (memcmp(smbios3.anchor, "_SM3_", 5) ||
+			    smbios3.length < sizeof(smbios3) ||
+			    q < p + 0x10000 - smbios3.length ||
+			    !dmi_checksum(q, smbios3.length))
+				smbios3.length = 0;
+		}
 	}
+
+	if (smbios3.length)
+		return _dmi_iterate(NULL, &smbios3, decode);
+	if (dmi.size)
+		return _dmi_iterate(&dmi, NULL, decode);
 	return -1;
 }
 
 static int __init dmi_efi_iterate(void (*decode)(struct dmi_header *))
 {
-	struct smbios_eps eps;
-	const struct smbios_eps __iomem *p;
 	int ret = -1;
 
-	if (efi.smbios == EFI_INVALID_TABLE_ADDR)
-		return -1;
+	while (efi.smbios3 != EFI_INVALID_TABLE_ADDR) {
+		struct smbios3_eps eps;
+		const struct smbios3_eps __iomem *p;
 
-	p = bt_ioremap(efi.smbios, sizeof(eps));
-	if (!p)
-		return -1;
-	memcpy_fromio(&eps, p, sizeof(eps));
-	bt_iounmap(p, sizeof(eps));
+		p = bt_ioremap(efi.smbios3, sizeof(eps));
+		if (!p)
+			break;
+		memcpy_fromio(&eps, p, sizeof(eps));
+		bt_iounmap(p, sizeof(eps));
 
-	if (memcmp(eps.anchor, "_SM_", 4))
-		return -1;
+		if (memcmp(eps.anchor, "_SM3_", 5) ||
+		    eps.length < sizeof(eps))
+			break;
 
-	p = bt_ioremap(efi.smbios, eps.length);
-	if (!p)
-		return -1;
-	if (dmi_checksum(p, eps.length) &&
-	    memcmp(eps.dmi.anchor, "_DMI_", 5) == 0 &&
-	    dmi_checksum(&eps.dmi, sizeof(eps.dmi))) {
-		printk(KERN_INFO "SMBIOS %d.%d present.\n",
-		       eps.major, eps.minor);
-		ret = _dmi_iterate(&eps.dmi, p, decode);
+		p = bt_ioremap(efi.smbios3, eps.length);
+		if (!p)
+			break;
+		if (dmi_checksum(p, eps.length))
+			ret = _dmi_iterate(NULL, p, decode);
+		bt_iounmap(p, eps.length);
+		break;
+	}
+
+	if (ret != 0 && efi.smbios != EFI_INVALID_TABLE_ADDR) {
+		struct smbios_eps eps;
+		const struct smbios_eps __iomem *p;
+
+		p = bt_ioremap(efi.smbios, sizeof(eps));
+		if (!p)
+			return -1;
+		memcpy_fromio(&eps, p, sizeof(eps));
+		bt_iounmap(p, sizeof(eps));
+
+		if (memcmp(eps.anchor, "_SM_", 4) ||
+		    eps.length < sizeof(eps))
+			return -1;
+
+		p = bt_ioremap(efi.smbios, eps.length);
+		if (!p)
+			return -1;
+		if (dmi_checksum(p, eps.length) &&
+		    memcmp(eps.dmi.anchor, "_DMI_", 5) == 0 &&
+		    dmi_checksum(&eps.dmi, sizeof(eps.dmi))) {
+			printk(KERN_INFO "SMBIOS %d.%d present.\n",
+			       eps.major, eps.minor);
+			ret = _dmi_iterate(&eps.dmi, p, decode);
+		}
+		bt_iounmap(p, eps.length);
 	}
-	bt_iounmap(p, eps.length);
 
 	return ret;
 }
@@ -476,7 +641,7 @@ static void __init dmi_decode(struct dmi
 	
 	switch(dm->type)
 	{
-		case  0:
+		case DMI_ENTRY_BIOS:
 			dmi_printk(("BIOS Vendor: %s\n",
 				dmi_string(dm, data[4])));
 			dmi_save_ident(dm, DMI_BIOS_VENDOR, 4);
@@ -487,7 +652,7 @@ static void __init dmi_decode(struct dmi
 				dmi_string(dm, data[8])));
 			dmi_save_ident(dm, DMI_BIOS_DATE, 8);
 			break;
-		case 1:
+		case DMI_ENTRY_SYSTEM:
 			dmi_printk(("System Vendor: %s\n",
 				dmi_string(dm, data[4])));
 			dmi_save_ident(dm, DMI_SYS_VENDOR, 4);
@@ -500,7 +665,7 @@ static void __init dmi_decode(struct dmi
 			dmi_printk(("Serial Number: %s\n",
 				dmi_string(dm, data[7])));
 			break;
-		case 2:
+		case DMI_ENTRY_BASEBOARD:
 			dmi_printk(("Board Vendor: %s\n",
 				dmi_string(dm, data[4])));
 			dmi_save_ident(dm, DMI_BOARD_VENDOR, 4);
--- a/xen/arch/x86/e820.c
+++ b/xen/arch/x86/e820.c
@@ -504,11 +504,19 @@ static uint64_t __init mtrr_top_of_ram(v
 
 static void __init reserve_dmi_region(void)
 {
-    u32 base, len;
-    if ( (dmi_get_table(&base, &len) == 0) && ((base + len) > base) &&
-         reserve_e820_ram(&e820, base, base + len) )
-        printk("WARNING: DMI table located in E820 RAM %08x-%08x. Fixed.\n",
-               base, base+len);
+    for ( ; ; )
+    {
+        paddr_t base;
+        u32 len;
+        const char *what = dmi_get_table(&base, &len);
+
+        if ( !what )
+            break;
+        if ( ((base + len) > base) &&
+             reserve_e820_ram(&e820, base, base + len) )
+            printk("WARNING: %s table located in E820 RAM %"PRIpaddr"-%"PRIpaddr". Fixed.\n",
+                   what, base, base + len);
+    }
 }
 
 static void __init machine_specific_memory_setup(
--- a/xen/common/efi/boot.c
+++ b/xen/common/efi/boot.c
@@ -32,6 +32,8 @@
 /* Using SetVirtualAddressMap() is incompatible with kexec: */
 #undef USE_SET_VIRTUAL_ADDRESS_MAP
 
+#define SMBIOS3_TABLE_GUID \
+  { 0xf2fd1544, 0x9794, 0x4a2c, {0x99, 0x2e, 0xe5, 0xbb, 0xcf, 0x20, 0xe3, 0x94} }
 #define SHIM_LOCK_PROTOCOL_GUID \
   { 0x605dab50, 0xe046, 0x4300, {0xab, 0xb6, 0x3d, 0xd8, 0x10, 0xdd, 0x8b, 0x23} }
 
@@ -993,6 +995,7 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SY
         static EFI_GUID __initdata acpi_guid = ACPI_TABLE_GUID;
         static EFI_GUID __initdata mps_guid = MPS_TABLE_GUID;
         static EFI_GUID __initdata smbios_guid = SMBIOS_TABLE_GUID;
+        static EFI_GUID __initdata smbios3_guid = SMBIOS3_TABLE_GUID;
 
         if ( match_guid(&acpi2_guid, &efi_ct[i].VendorGuid) )
 	       efi.acpi20 = (long)efi_ct[i].VendorTable;
@@ -1002,11 +1005,15 @@ efi_start(EFI_HANDLE ImageHandle, EFI_SY
 	       efi.mps = (long)efi_ct[i].VendorTable;
         if ( match_guid(&smbios_guid, &efi_ct[i].VendorGuid) )
 	       efi.smbios = (long)efi_ct[i].VendorTable;
+        if ( match_guid(&smbios3_guid, &efi_ct[i].VendorGuid) )
+	       efi.smbios3 = (long)efi_ct[i].VendorTable;
     }
 
 #ifndef CONFIG_ARM /* TODO - disabled until implemented on ARM */
-    if (efi.smbios != EFI_INVALID_TABLE_ADDR)
-        dmi_efi_get_table((void *)(long)efi.smbios);
+    dmi_efi_get_table(efi.smbios != EFI_INVALID_TABLE_ADDR
+                      ? (void *)(long)efi.smbios : NULL,
+                      efi.smbios3 != EFI_INVALID_TABLE_ADDR
+                      ? (void *)(long)efi.smbios3 : NULL);
 #endif
 
     /* Collect PCI ROM contents. */
--- a/xen/common/efi/runtime.c
+++ b/xen/common/efi/runtime.c
@@ -45,6 +45,7 @@ struct efi __read_mostly efi = {
 	.acpi20 = EFI_INVALID_TABLE_ADDR,
 	.mps    = EFI_INVALID_TABLE_ADDR,
 	.smbios = EFI_INVALID_TABLE_ADDR,
+	.smbios3 = EFI_INVALID_TABLE_ADDR,
 };
 
 const struct efi_pci_rom *__read_mostly efi_pci_roms;
--- a/xen/include/xen/dmi.h
+++ b/xen/include/xen/dmi.h
@@ -34,8 +34,8 @@ struct dmi_system_id {
 
 extern int dmi_check_system(struct dmi_system_id *list);
 extern void dmi_scan_machine(void);
-extern int dmi_get_table(u32 *base, u32 *len);
-extern void dmi_efi_get_table(void *);
+extern const char *dmi_get_table(paddr_t *base, u32 *len);
+extern void dmi_efi_get_table(const void *smbios, const void *smbios3);
 bool_t dmi_get_date(int field, int *yearp, int *monthp, int *dayp);
 extern void dmi_end_boot(void);
 
--- a/xen/include/xen/efi.h
+++ b/xen/include/xen/efi.h
@@ -15,6 +15,7 @@ struct efi {
     unsigned long acpi;         /* ACPI table (IA64 ext 0.71) */
     unsigned long acpi20;       /* ACPI table (ACPI 2.0) */
     unsigned long smbios;       /* SM BIOS table */
+    unsigned long smbios3;      /* SMBIOS v3 table */
 };
 
 extern struct efi efi;
      
      
      
      _______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel