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

[Xen-changelog] [xen master] xen/arm: Rework the way to compute dom0 DTB base address



commit bcb49301c21ed69b4e8c164fa215efe9db30621a
Author:     Julien Grall <julien.grall@xxxxxxxxxx>
AuthorDate: Thu Jun 27 18:13:30 2013 +0100
Commit:     Ian Campbell <ian.campbell@xxxxxxxxxx>
CommitDate: Fri Jun 28 12:42:13 2013 +0100

    xen/arm: Rework the way to compute dom0 DTB base address
    
    If the DTB is loading right after the kernel, on some setup, Linux will
    overwrite the DTB during the decompression step.
    
    To be sure the DTB won't be overwritten by the decompression stage, load
    the DTB near the end of the first memory bank and below 4Gib (if memory 
range is
    greater).
    
    Signed-off-by: Julien Grall <julien.grall@xxxxxxxxxx>
    Acked-by: Ian Campbell <ian.campbell@xxxxxxxxxx>
---
 xen/arch/arm/domain_build.c |   27 +++++++++++++++++++++------
 xen/arch/arm/kernel.c       |   18 ++++++++++++++++++
 xen/arch/arm/kernel.h       |    2 ++
 3 files changed, 41 insertions(+), 6 deletions(-)

diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index b92c64b..0423b5a 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -477,6 +477,7 @@ static int prepare_dtb(struct domain *d, struct kernel_info 
*kinfo)
     void *fdt;
     int new_size;
     int ret;
+    paddr_t end;
 
     kinfo->unassigned_mem = dom0_mem;
 
@@ -502,17 +503,26 @@ static int prepare_dtb(struct domain *d, struct 
kernel_info *kinfo)
         goto err;
 
     /*
-     * Put the device tree at the beginning of the first bank.  It
-     * must be below 4 GiB.
+     * DTB must be load below 4GiB and far enough from linux (Linux uses
+     * the space after it to decompress)
+     * Load the DTB at the end of the first bank, while ensuring it is
+     * also below 4G
      */
-    kinfo->dtb_paddr = kinfo->mem.bank[0].start + 0x100;
-    if ( kinfo->dtb_paddr + fdt_totalsize(kinfo->fdt) > (1ull << 32) )
+    end = kinfo->mem.bank[0].start + kinfo->mem.bank[0].size;
+    end = MIN(1ull << 32, end);
+    kinfo->dtb_paddr = end - fdt_totalsize(kinfo->fdt);
+    /* Align the address to 2Mb. Linux only requires 4 byte alignment */
+    kinfo->dtb_paddr &= ~((2 << 20) - 1);
+
+    if ( fdt_totalsize(kinfo->fdt) > end )
     {
-        printk("Not enough memory below 4 GiB for the device tree.");
+        printk(XENLOG_ERR "Not enough memory in the first bank for "
+               "the device tree.");
         ret = -FDT_ERR_XEN(EINVAL);
         goto err;
     }
 
+
     return 0;
 
   err:
@@ -525,6 +535,9 @@ static void dtb_load(struct kernel_info *kinfo)
 {
     void * __user dtb_virt = (void * __user)(register_t)kinfo->dtb_paddr;
 
+    printk("Loading dom0 DTB to 0x%"PRIpaddr"-0x%"PRIpaddr"\n",
+           kinfo->dtb_paddr, kinfo->dtb_paddr + fdt_totalsize(kinfo->fdt));
+
     raw_copy_to_guest(dtb_virt, kinfo->fdt, fdt_totalsize(kinfo->fdt));
     xfree(kinfo->fdt);
 }
@@ -559,10 +572,12 @@ int construct_dom0(struct domain *d)
     if ( rc < 0 )
         return rc;
 
+    if ( kinfo.check_overlap )
+        kinfo.check_overlap(&kinfo);
+
     /* The following loads use the domain's p2m */
     p2m_load_VTTBR(d);
 
-    kinfo.dtb_paddr = kinfo.zimage.load_addr + kinfo.zimage.len;
     kernel_load(&kinfo);
     dtb_load(&kinfo);
 
diff --git a/xen/arch/arm/kernel.c b/xen/arch/arm/kernel.c
index aba5441..3953f0f 100644
--- a/xen/arch/arm/kernel.c
+++ b/xen/arch/arm/kernel.c
@@ -12,6 +12,7 @@
 #include <xen/sched.h>
 #include <asm/byteorder.h>
 #include <asm/setup.h>
+#include <xen/libfdt/libfdt.h>
 
 #include "kernel.h"
 
@@ -64,6 +65,21 @@ void copy_from_paddr(void *dst, paddr_t paddr, unsigned long 
len, int attrindx)
     clear_fixmap(FIXMAP_MISC);
 }
 
+static void kernel_zimage_check_overlap(struct kernel_info *info)
+{
+    paddr_t zimage_start = info->zimage.load_addr;
+    paddr_t zimage_end = info->zimage.load_addr + info->zimage.len;
+    paddr_t dtb_start = info->dtb_paddr;
+    paddr_t dtb_end = info->dtb_paddr + fdt_totalsize(info->fdt);
+
+    if ( (dtb_start > zimage_end) || (dtb_end < zimage_start) )
+        return;
+
+    panic(XENLOG_ERR "The kernel(0x%"PRIpaddr"-0x%"PRIpaddr
+          ") is overlapping the DTB(0x%"PRIpaddr"-0x%"PRIpaddr")\n",
+          zimage_start, zimage_end, dtb_start, dtb_end);
+}
+
 static void kernel_zimage_load(struct kernel_info *info)
 {
     paddr_t load_addr = info->zimage.load_addr;
@@ -152,6 +168,7 @@ static int kernel_try_zimage_prepare(struct kernel_info 
*info,
 
     info->entry = info->zimage.load_addr;
     info->load = kernel_zimage_load;
+    info->check_overlap = kernel_zimage_check_overlap;
 
     return 0;
 }
@@ -197,6 +214,7 @@ static int kernel_try_elf_prepare(struct kernel_info *info,
      */
     info->entry = info->elf.parms.virt_entry;
     info->load = kernel_elf_load;
+    info->check_overlap = NULL;
 
     if ( elf_check_broken(&info->elf.elf) )
         printk("Xen: warning: ELF kernel broken: %s\n",
diff --git a/xen/arch/arm/kernel.h b/xen/arch/arm/kernel.h
index 1776a4d..c900e74 100644
--- a/xen/arch/arm/kernel.h
+++ b/xen/arch/arm/kernel.h
@@ -38,6 +38,8 @@ struct kernel_info {
     };
 
     void (*load)(struct kernel_info *info);
+    /* Callback to check overlap between the kernel and the device tree */
+    void (*check_overlap)(struct kernel_info *kinfo);
     int load_attr;
 };
 
--
generated by git-patchbot for /home/xen/git/xen.git#master

_______________________________________________
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®.