]> xenbits.xensource.com Git - xen.git/commitdiff
xen: arm: probe the kernel to determine the guest type earlier
authorIan Campbell <ian.campbell@citrix.com>
Fri, 4 Apr 2014 12:56:58 +0000 (13:56 +0100)
committerIan Campbell <ian.campbell@citrix.com>
Wed, 16 Apr 2014 15:21:19 +0000 (16:21 +0100)
We need to know if the kernel is 32- or 64- bit capable sooner so that we know
what sort of domain we are building when allocating memory to it (so we can
place appropriate limits when allocating RAM to the guest). At the moment
kernel_prepare() decides this but it needs the memory to have already been
allocated.

Therefore split the probing functionality of kernel_prepare() and call it much
earlier. The remainder of kernel_prepare() deals with where to place the
kernel in RAM which can be deferred until kernel_load() so do so.

Document the input and output of kernel_probe() and _load().

Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
Acked-by: Julien Grall <julien.grall@linaro.org>
[ ijc -- whitespace fixes ]

xen/arch/arm/domain_build.c
xen/arch/arm/kernel.c
xen/arch/arm/kernel.h

index fede5c014534683a3428038afb5ff562984a7582..083bf2dd86613f98b95504fee6103c3e27d42464 100644 (file)
@@ -1002,9 +1002,7 @@ int construct_dom0(struct domain *d)
 
     kinfo.unassigned_mem = dom0_mem;
 
-    allocate_memory(d, &kinfo);
-
-    rc = kernel_prepare(&kinfo);
+    rc = kernel_probe(&kinfo);
     if ( rc < 0 )
         return rc;
 
@@ -1012,6 +1010,8 @@ int construct_dom0(struct domain *d)
     d->arch.type = kinfo.type;
 #endif
 
+    allocate_memory(d, &kinfo);
+
     rc = prepare_dtb(d, &kinfo);
     if ( rc < 0 )
         return rc;
@@ -1024,8 +1024,8 @@ int construct_dom0(struct domain *d)
     p2m_restore_state(v);
 
     /*
-     * kernel_load will determine the placement of the initrd & fdt in
-     * RAM, so call it first.
+     * kernel_load will determine the placement of the kernel as well
+     * as the initrd & fdt in RAM, so call it first.
      */
     kernel_load(&kinfo);
     /* initrd_load will fix up the fdt, so call it before dtb_load */
index 7554479527bce0d1515356e1653942db7176d9e3..c82906fd3aa81ffde9fdbec1bcc0388e1d73127a 100644 (file)
@@ -118,13 +118,47 @@ static void place_modules(struct kernel_info *info,
     info->initrd_paddr = info->dtb_paddr + dtb_len;
 }
 
+static paddr_t kernel_zimage_place(struct kernel_info *info)
+{
+    paddr_t load_addr;
+
+#ifdef CONFIG_ARM_64
+    if ( info->type == DOMAIN_64BIT )
+        return info->mem.bank[0].start + info->zimage.text_offset;
+#endif
+
+    /*
+     * If start is zero, the zImage is position independent, in this
+     * case Documentation/arm/Booting recommends loading below 128MiB
+     * and above 32MiB. Load it as high as possible within these
+     * constraints, while also avoiding the DTB.
+     */
+    if ( info->zimage.start == 0 )
+    {
+        paddr_t load_end;
+
+        load_end = info->mem.bank[0].start + info->mem.bank[0].size;
+        load_end = MIN(info->mem.bank[0].start + MB(128), load_end);
+
+        load_addr = load_end - info->zimage.len;
+        /* Align to 2MB */
+        load_addr &= ~((2 << 20) - 1);
+    }
+    else
+        load_addr = info->zimage.start;
+
+    return load_addr;
+}
+
 static void kernel_zimage_load(struct kernel_info *info)
 {
-    paddr_t load_addr = info->zimage.load_addr;
+    paddr_t load_addr = kernel_zimage_place(info);
     paddr_t paddr = info->zimage.kernel_addr;
     paddr_t len = info->zimage.len;
     unsigned long offs;
 
+    info->entry = load_addr;
+
     place_modules(info, load_addr, load_addr + len);
 
     printk("Loading zImage from %"PRIpaddr" to %"PRIpaddr"-%"PRIpaddr"\n",
@@ -156,10 +190,10 @@ static void kernel_zimage_load(struct kernel_info *info)
 
 #ifdef CONFIG_ARM_64
 /*
- * Check if the image is a 64-bit zImage and setup kernel_info
+ * Check if the image is a 64-bit Image.
  */
-static int kernel_try_zimage64_prepare(struct kernel_info *info,
-                                     paddr_t addr, paddr_t size)
+static int kernel_zimage64_probe(struct kernel_info *info,
+                                 paddr_t addr, paddr_t size)
 {
     /* linux/Documentation/arm64/booting.txt */
     struct {
@@ -198,12 +232,9 @@ static int kernel_try_zimage64_prepare(struct kernel_info *info,
         return -EINVAL;
 
     info->zimage.kernel_addr = addr;
-
-    info->zimage.load_addr = info->mem.bank[0].start
-        + zimage.text_offset;
     info->zimage.len = end - start;
+    info->zimage.text_offset = zimage.text_offset;
 
-    info->entry = info->zimage.load_addr;
     info->load = kernel_zimage_load;
 
     info->type = DOMAIN_64BIT;
@@ -215,8 +246,8 @@ static int kernel_try_zimage64_prepare(struct kernel_info *info,
 /*
  * Check if the image is a 32-bit zImage and setup kernel_info
  */
-static int kernel_try_zimage32_prepare(struct kernel_info *info,
-                                     paddr_t addr, paddr_t size)
+static int kernel_zimage32_probe(struct kernel_info *info,
+                                 paddr_t addr, paddr_t size)
 {
     uint32_t zimage[ZIMAGE32_HEADER_LEN/4];
     uint32_t start, end;
@@ -252,28 +283,9 @@ static int kernel_try_zimage32_prepare(struct kernel_info *info,
 
     info->zimage.kernel_addr = addr;
 
-    /*
-     * If start is zero, the zImage is position independent, in this
-     * case Documentation/arm/Booting recommends loading below 128MiB
-     * and above 32MiB. Load it as high as possible within these
-     * constraints, while also avoiding the DTB.
-     */
-    if (start == 0)
-    {
-        paddr_t load_end;
-
-        load_end = info->mem.bank[0].start + info->mem.bank[0].size;
-        load_end = MIN(info->mem.bank[0].start + MB(128), load_end);
-
-        info->zimage.load_addr = load_end - end;
-        /* Align to 2MB */
-        info->zimage.load_addr &= ~((2 << 20) - 1);
-    }
-    else
-        info->zimage.load_addr = start;
+    info->zimage.start = start;
     info->zimage.len = end - start;
 
-    info->entry = info->zimage.load_addr;
     info->load = kernel_zimage_load;
 
 #ifdef CONFIG_ARM_64
@@ -285,6 +297,12 @@ static int kernel_try_zimage32_prepare(struct kernel_info *info,
 
 static void kernel_elf_load(struct kernel_info *info)
 {
+    /*
+     * TODO: can the ELF header be used to find the physical address
+     * to load the image to?  Instead of assuming virt == phys.
+     */
+    info->entry = info->elf.parms.virt_entry;
+
     place_modules(info,
                   info->elf.parms.virt_kstart,
                   info->elf.parms.virt_kend);
@@ -300,8 +318,8 @@ static void kernel_elf_load(struct kernel_info *info)
     free_xenheap_pages(info->elf.kernel_img, info->elf.kernel_order);
 }
 
-static int kernel_try_elf_prepare(struct kernel_info *info,
-                                  paddr_t addr, paddr_t size)
+static int kernel_elf_probe(struct kernel_info *info,
+                            paddr_t addr, paddr_t size)
 {
     int rc;
 
@@ -336,11 +354,6 @@ static int kernel_try_elf_prepare(struct kernel_info *info,
     }
 #endif
 
-    /*
-     * TODO: can the ELF header be used to find the physical address
-     * to load the image to?  Instead of assuming virt == phys.
-     */
-    info->entry = info->elf.parms.virt_entry;
     info->load = kernel_elf_load;
 
     if ( elf_check_broken(&info->elf.elf) )
@@ -357,7 +370,7 @@ err:
     return rc;
 }
 
-int kernel_prepare(struct kernel_info *info)
+int kernel_probe(struct kernel_info *info)
 {
     int rc;
 
@@ -375,12 +388,12 @@ int kernel_prepare(struct kernel_info *info)
     printk("Loading kernel from boot module %d\n", MOD_KERNEL);
 
 #ifdef CONFIG_ARM_64
-    rc = kernel_try_zimage64_prepare(info, start, size);
+    rc = kernel_zimage64_probe(info, start, size);
     if (rc < 0)
 #endif
-        rc = kernel_try_zimage32_prepare(info, start, size);
+        rc = kernel_zimage32_probe(info, start, size);
     if (rc < 0)
-        rc = kernel_try_elf_prepare(info, start, size);
+        rc = kernel_elf_probe(info, start, size);
 
     return rc;
 }
index 2c27c648c9e945a6d339ebdc9725159b4bd7ee48..fd2f61df2cd8b91512a7ce48b430a8d2a91a4ee2 100644 (file)
@@ -31,8 +31,11 @@ struct kernel_info {
     union {
         struct {
             paddr_t kernel_addr;
-            paddr_t load_addr;
             paddr_t len;
+#ifdef CONFIG_ARM_64
+            paddr_t text_offset; /* 64-bit Image only */
+#endif
+            paddr_t start; /* 32-bit zImage only */
         } zimage;
 
         struct {
@@ -44,7 +47,27 @@ struct kernel_info {
     };
 };
 
-int kernel_prepare(struct kernel_info *info);
+/*
+ * Probe the kernel to detemine its type and select a loader.
+ *
+ * Sets in info:
+ *  ->type
+ *  ->load hook, and sets loader specific variables ->{zimage,elf}
+ */
+int kernel_probe(struct kernel_info *info);
+
+/*
+ * Loads the kernel into guest RAM.
+ *
+ * Expects to be set in info when called:
+ *  ->mem
+ *  ->fdt
+ *
+ * Sets in info:
+ *  ->entry
+ *  ->dtb_paddr
+ *  ->initrd_paddr
+ */
 void kernel_load(struct kernel_info *info);
 
 #endif /* #ifdef __ARCH_ARM_KERNEL_H__ */