[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [xen stable-4.5] x86/efi: reserve SMBIOS table region when EFI booting



commit d0725109f73c1a400e39862c7eceac72b407b1b5
Author:     Ross Lagerwall <ross.lagerwall@xxxxxxxxxx>
AuthorDate: Tue May 19 11:43:35 2015 +0200
Commit:     Jan Beulich <jbeulich@xxxxxxxx>
CommitDate: Tue May 19 11:43:35 2015 +0200

    x86/efi: reserve SMBIOS table region when EFI booting
    
    Some EFI firmware implementations may place the SMBIOS table in RAM
    marked as BootServicesData, which Xen does not consider as reserved.
    When dom0 tries to access the SMBIOS, the region is not contained in the
    initial P2M and it crashes with a page fault. To fix this, reserve the
    SMBIOS region.
    
    Also, fix the memcmp checks for existence of the SMBIOS.
    
    Signed-off-by: Ross Lagerwall <ross.lagerwall@xxxxxxxxxx>
    Reviewed-by: Jan Beulich <jbeulich@xxxxxxxx>
    master commit: bf68adcadaa2b0885c5d2f1c8e2e068e209eb041
    master date: 2015-04-17 10:44:48 +0200
---
 xen/arch/x86/dmi_scan.c |   67 +++++++++++++++++++++++++++++-----------------
 xen/arch/x86/e820.c     |   18 +++++++++---
 xen/include/xen/dmi.h   |    2 +-
 3 files changed, 56 insertions(+), 31 deletions(-)

diff --git a/xen/arch/x86/dmi_scan.c b/xen/arch/x86/dmi_scan.c
index 500133a..aaba5e7 100644
--- a/xen/arch/x86/dmi_scan.c
+++ b/xen/arch/x86/dmi_scan.c
@@ -127,6 +127,8 @@ static inline bool_t __init dmi_checksum(const void __iomem 
*buf,
 
 static u32 __initdata efi_dmi_address;
 static u32 __initdata efi_dmi_size;
+static u32 __initdata efi_smbios_address;
+static u32 __initdata efi_smbios_size;
 
 /*
  * Important: This function gets called while still in EFI
@@ -136,39 +138,54 @@ void __init dmi_efi_get_table(void *smbios)
 {
        struct smbios_eps *eps = smbios;
 
-       if (memcmp(eps->anchor, "_SM_", 4) &&
-           dmi_checksum(eps, eps->length) &&
-           memcmp(eps->dmi.anchor, "_DMI_", 5) == 0 &&
-           dmi_checksum(&eps->dmi, sizeof(eps->dmi))) {
-               efi_dmi_address = eps->dmi.address;
-               efi_dmi_size = eps->dmi.size;
+       if (memcmp(eps->anchor, "_SM_", 4) == 0 &&
+           eps->length >= sizeof(*eps) &&
+           dmi_checksum(eps, eps->length)) {
+               efi_smbios_address = (u32)(long)eps;
+               efi_smbios_size = eps->length;
+
+               if (memcmp(eps->dmi.anchor, "_DMI_", 5) == 0 &&
+                   dmi_checksum(&eps->dmi, sizeof(eps->dmi))) {
+                       efi_dmi_address = eps->dmi.address;
+                       efi_dmi_size = eps->dmi.size;
+               }
        }
 }
 
-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_dmi_size && !(instance & 2)) {
+                       *base = efi_dmi_address;
+                       *len = efi_dmi_size;
+                       instance |= 2;
+                       return "DMI";
+               }
+               if (efi_smbios_size && !(instance & 4)) {
+                       *base = efi_smbios_address;
+                       *len = efi_smbios_size;
+                       instance |= 4;
+                       return "SMBIOS";
+               }
+       } else {
+               char __iomem *p = maddr_to_virt(0xF0000), *q;
+               struct dmi_eps eps;
+
+               for (q = p; q <= p + 0x10000 - sizeof(eps); q += 16) {
+                       memcpy_fromio(&eps, q, sizeof(eps));
+                       if (!(instance & 1) &&
+                           memcmp(eps.anchor, "_DMI_", 5) == 0 &&
+                           dmi_checksum(&eps, sizeof(eps))) {
+                               *base = eps.address;
+                               *len = eps.size;
+                               instance |= 1;
+                               return "DMI";
+                       }
                }
        }
-       return -1;
+       return NULL;
 }
 
 static int __init _dmi_iterate(const struct dmi_eps *dmi,
diff --git a/xen/arch/x86/e820.c b/xen/arch/x86/e820.c
index bf84bae..743a375 100644
--- a/xen/arch/x86/e820.c
+++ b/xen/arch/x86/e820.c
@@ -504,11 +504,19 @@ static uint64_t __init mtrr_top_of_ram(void)
 
 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(
diff --git a/xen/include/xen/dmi.h b/xen/include/xen/dmi.h
index 8205893..e2fc76d 100644
--- a/xen/include/xen/dmi.h
+++ b/xen/include/xen/dmi.h
@@ -34,7 +34,7 @@ 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 const char *dmi_get_table(paddr_t *base, u32 *len);
 extern void dmi_efi_get_table(void *);
 bool_t dmi_get_date(int field, int *yearp, int *monthp, int *dayp);
 extern void dmi_end_boot(void);
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.5

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.