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

[Xen-devel] [PATCH v6 26/27] ARM: support zImage format kernels for dom0



From: David Vrabel <david.vrabel@xxxxxxxxxx>

Allow a zImage format kernel to be used for dom0.  zImages are (by
default) hardcoded with the RAM location so adjust the RAM in the
memory map to match the physical memory map (0x80000000).

Vmlinux ELF images are loaded using a hack to locate the RAM so the
IPA is the same as the kernel's VA so the elf loader does the right
thing.  If an ELF image is loaded the RAM will be located at
0xC0000000 (as before).

Signed-off-by: David Vrabel <david.vrabel@xxxxxxxxxx>
---
 xen/arch/arm/Makefile       |    1 +
 xen/arch/arm/domain_build.c |   72 ++++--------------
 xen/arch/arm/kernel.c       |  167 +++++++++++++++++++++++++++++++++++++++++++
 xen/arch/arm/kernel.h       |   37 ++++++++++
 4 files changed, 221 insertions(+), 56 deletions(-)
 create mode 100644 xen/arch/arm/kernel.c
 create mode 100644 xen/arch/arm/kernel.h

diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile
index 5a07ae7..9bc2fc8 100644
--- a/xen/arch/arm/Makefile
+++ b/xen/arch/arm/Makefile
@@ -7,6 +7,7 @@ obj-y += domain_build.o
 obj-y += gic.o
 obj-y += io.o
 obj-y += irq.o
+obj-y += kernel.o
 obj-y += mm.o
 obj-y += p2m.o
 obj-y += guestcopy.o
diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
index f73df85..cbbc0b9 100644
--- a/xen/arch/arm/domain_build.c
+++ b/xen/arch/arm/domain_build.c
@@ -4,10 +4,10 @@
 #include <xen/mm.h>
 #include <xen/domain_page.h>
 #include <xen/sched.h>
-#include <xen/libelf.h>
 #include <asm/irq.h>
 
 #include "gic.h"
+#include "kernel.h"
 
 static unsigned int __initdata opt_dom0_max_vcpus;
 integer_param("dom0_max_vcpus", opt_dom0_max_vcpus);
@@ -28,25 +28,6 @@ struct vcpu *__init alloc_dom0_vcpu0(void)
 
 extern void guest_mode_entry(void);
 
-static void copy_from_flash(void *dst, paddr_t flash, unsigned long len)
-{
-    void *src = (void *)FIXMAP_ADDR(FIXMAP_MISC);
-    unsigned long offs;
-
-    printk("Copying %#lx bytes from flash %"PRIpaddr" to %p-%p: [",
-           len, flash, dst, dst+(1<<23));
-    for ( offs = 0; offs < len ; offs += PAGE_SIZE )
-    {
-        if ( ( offs % (1<<20) ) == 0 )
-            printk(".");
-        set_fixmap(FIXMAP_MISC, (flash+offs) >> PAGE_SHIFT, DEV_SHARED);
-        memcpy(dst+offs, src, PAGE_SIZE);
-    }
-    printk("]\n");
-
-    clear_fixmap(FIXMAP_MISC);
-}
-
 static void setup_linux_atag(paddr_t tags, paddr_t ram_s, paddr_t ram_e)
 {
     paddr_t ma = gvirt_to_maddr(tags);
@@ -84,21 +65,14 @@ static void setup_linux_atag(paddr_t tags, paddr_t ram_s, 
paddr_t ram_e)
     unmap_domain_page(map);
 }
 
-/* Store kernel in first 8M of flash */
-#define KERNEL_FLASH_ADDRESS 0x00000000UL
-#define KERNEL_FLASH_SIZE    0x00800000UL
-
 int construct_dom0(struct domain *d)
 {
-    int rc, kernel_order;
-    void *kernel_img;
+    struct kernel_info kinfo = {};
+    int rc;
 
     struct vcpu *v = d->vcpu[0];
     struct cpu_user_regs *regs = &v->arch.user_regs;
 
-    struct elf_binary elf;
-    struct elf_dom_parms parms;
-
     /* Sanity! */
     BUG_ON(d->domain_id != 0);
     BUG_ON(d->vcpu[0] == NULL);
@@ -106,31 +80,22 @@ int construct_dom0(struct domain *d)
 
     printk("*** LOADING DOMAIN 0 ***\n");
 
-    kernel_order = get_order_from_bytes(KERNEL_FLASH_SIZE);
-    kernel_img = alloc_xenheap_pages(kernel_order, 0);
-    if ( kernel_img == NULL )
-        panic("Cannot allocate temporary buffer for kernel.\n");
+    /* 128M at 2G physical */
+    /* TODO size and location from DT. */
+    kinfo.ram_start = 0x80000000;
+    kinfo.ram_end   = 0x88000000;
 
-    copy_from_flash(kernel_img, KERNEL_FLASH_ADDRESS, KERNEL_FLASH_SIZE);
+    rc = kernel_prepare(&kinfo);
+    if (rc < 0)
+        return rc;
 
     d->max_pages = ~0U;
 
-    if ( (rc = elf_init(&elf, kernel_img, KERNEL_FLASH_SIZE )) != 0 )
-        return rc;  memset(regs, 0, sizeof(*regs));
-#ifdef VERBOSE
-    elf_set_verbose(&elf);
-#endif
-    elf_parse_binary(&elf);
-    if ( (rc = elf_xen_parse(&elf, &parms)) != 0 )
-        return rc;
-
     if ( (rc = p2m_alloc_table(d)) != 0 )
         return rc;
 
-    /* 128M at 3G physical */
-    /* TODO size and location according to platform info */
-    printk("Populate P2M %#llx->%#llx\n", 0xc0000000ULL, 0xc8000000ULL);
-    p2m_populate_ram(d, 0xc0000000ULL, 0xc8000000ULL);
+    printk("Populate P2M %#llx->%#llx\n", kinfo.ram_start, kinfo.ram_end);
+    p2m_populate_ram(d, kinfo.ram_start, kinfo.ram_end);
 
     printk("Map CS2 MMIO regions 1:1 in the P2M %#llx->%#llx\n", 
0x18000000ULL, 0x1BFFFFFFULL);
     map_mmio_regions(d, 0x18000000, 0x1BFFFFFF, 0x18000000);
@@ -161,20 +126,15 @@ int construct_dom0(struct domain *d)
     /* The following load uses domain's p2m */
     p2m_load_VTTBR(d);
 
-    printk("Loading ELF image into guest memory\n");
-    elf.dest = (void*)(unsigned long)parms.virt_kstart;
-    elf_load_binary(&elf);
-
-    printk("Free temporary kernel buffer\n");
-    free_xenheap_pages(kernel_img, kernel_order);
+    kernel_load(&kinfo);
 
-    setup_linux_atag(0xc0000100ULL, 0xc0000000ULL, 0xc8000000ULL);
+    setup_linux_atag(kinfo.ram_start + 0x100, kinfo.ram_start, kinfo.ram_end);
 
     clear_bit(_VPF_down, &v->pause_flags);
 
     memset(regs, 0, sizeof(*regs));
 
-    regs->pc = (uint32_t)parms.virt_entry;
+    regs->pc = (uint32_t)kinfo.entry;
 
     regs->cpsr = PSR_ABT_MASK|PSR_FIQ_MASK|PSR_IRQ_MASK|PSR_MODE_SVC;
 
@@ -191,7 +151,7 @@ int construct_dom0(struct domain *d)
 
     regs->r0 = 0; /* SBZ */
     regs->r1 = 2272; /* Machine NR: Versatile Express */
-    regs->r2 = 0xc0000100; /* ATAGS */
+    regs->r2 = kinfo.ram_start + 0x100; /* ATAGS */
 
     WRITE_CP32(SCTLR_BASE, SCTLR);
 
diff --git a/xen/arch/arm/kernel.c b/xen/arch/arm/kernel.c
new file mode 100644
index 0000000..5fb2ba0
--- /dev/null
+++ b/xen/arch/arm/kernel.c
@@ -0,0 +1,167 @@
+/*
+ * Kernel image loading.
+ *
+ * Copyright (C) 2011 Citrix Systems, Inc.
+ */
+#include <xen/config.h>
+#include <xen/errno.h>
+#include <xen/init.h>
+#include <xen/lib.h>
+#include <xen/mm.h>
+#include <xen/domain_page.h>
+#include <xen/sched.h>
+
+#include "kernel.h"
+
+/* Store kernel in first 8M of flash */
+#define KERNEL_FLASH_ADDRESS 0x00000000UL
+#define KERNEL_FLASH_SIZE    0x00800000UL
+
+#define ZIMAGE_MAGIC_OFFSET 0x24
+#define ZIMAGE_START_OFFSET 0x28
+#define ZIMAGE_END_OFFSET   0x2c
+
+#define ZIMAGE_MAGIC 0x016f2818
+
+static void kernel_zimage_load(struct kernel_info *info)
+{
+    paddr_t load_addr = info->zimage.load_addr;
+    paddr_t len = info->zimage.len;
+    paddr_t flash = KERNEL_FLASH_ADDRESS;
+    void *src = (void *)FIXMAP_ADDR(FIXMAP_MISC);
+    unsigned long offs;
+
+    printk("Loading %"PRIpaddr" byte zImage from flash %"PRIpaddr" to 
%"PRIpaddr"-%"PRIpaddr": [",
+           len, flash, load_addr, load_addr + len);
+    for ( offs = 0; offs < len; offs += PAGE_SIZE )
+    {
+        paddr_t ma = gvirt_to_maddr(load_addr + offs);
+        void *dst = map_domain_page(ma>>PAGE_SHIFT);
+
+        if ( ( offs % (1<<20) ) == 0 )
+            printk(".");
+
+        set_fixmap(FIXMAP_MISC, (flash+offs) >> PAGE_SHIFT, DEV_SHARED);
+        memcpy(dst, src, PAGE_SIZE);
+        clear_fixmap(FIXMAP_MISC);
+
+        unmap_domain_page(dst);
+    }
+    printk("]\n");
+}
+
+/**
+ * Check the image is a zImage and return the load address and length
+ * (FIXME: including any appended DTB).
+ */
+static int kernel_try_zimage_prepare(struct kernel_info *info)
+{
+    uint32_t *zimage = (void *)FIXMAP_ADDR(FIXMAP_MISC);
+    uint32_t start, end;
+
+    set_fixmap(FIXMAP_MISC, KERNEL_FLASH_ADDRESS >> PAGE_SHIFT, DEV_SHARED);
+
+    if (zimage[ZIMAGE_MAGIC_OFFSET/4] != ZIMAGE_MAGIC)
+        return -EINVAL;
+
+    start = zimage[ZIMAGE_START_OFFSET/4];
+    end = zimage[ZIMAGE_END_OFFSET/4];
+
+    clear_fixmap(FIXMAP_MISC);
+
+    /* FIXME: get RAM location from appended DTB (if there is one)? */
+
+    /*
+     * If start is zero, the zImage is position independent -- load it
+     * at 32k from start of RAM.
+     */
+    if (start == 0)
+        info->zimage.load_addr = info->ram_start + 0x8000;
+    else
+        info->zimage.load_addr = start;
+    info->zimage.len = end - start;
+
+    info->entry = info->zimage.load_addr;
+    info->load = kernel_zimage_load;
+
+    return 0;
+}
+
+static void kernel_elf_load(struct kernel_info *info)
+{
+    printk("Loading ELF image into guest memory\n");
+    info->elf.elf.dest = (void*)(unsigned long)info->elf.parms.virt_kstart;
+    elf_load_binary(&info->elf.elf);
+
+    printk("Free temporary kernel buffer\n");
+    free_xenheap_pages(info->kernel_img, info->kernel_order);
+}
+
+static void copy_from_flash(void *dst, paddr_t flash, unsigned long len)
+{
+    void *src = (void *)FIXMAP_ADDR(FIXMAP_MISC);
+    unsigned long offs;
+
+    printk("Copying %#lx bytes from flash %"PRIpaddr" to %p-%p: [",
+           len, flash, dst, dst+(1<<23));
+    for ( offs = 0; offs < len ; offs += PAGE_SIZE )
+    {
+        if ( ( offs % (1<<20) ) == 0 )
+            printk(".");
+        set_fixmap(FIXMAP_MISC, (flash+offs) >> PAGE_SHIFT, DEV_SHARED);
+        memcpy(dst+offs, src, PAGE_SIZE);
+    }
+    printk("]\n");
+
+    clear_fixmap(FIXMAP_MISC);
+}
+
+static int kernel_try_elf_prepare(struct kernel_info *info)
+{
+    int rc;
+
+    info->kernel_order = get_order_from_bytes(KERNEL_FLASH_SIZE);
+    info->kernel_img = alloc_xenheap_pages(info->kernel_order, 0);
+    if ( info->kernel_img == NULL )
+        panic("Cannot allocate temporary buffer for kernel.\n");
+
+    copy_from_flash(info->kernel_img, KERNEL_FLASH_ADDRESS, KERNEL_FLASH_SIZE);
+
+    if ( (rc = elf_init(&info->elf.elf, info->kernel_img, KERNEL_FLASH_SIZE )) 
!= 0 )
+        return rc;
+#ifdef VERBOSE
+    elf_set_verbose(&info->elf.elf);
+#endif
+    elf_parse_binary(&info->elf.elf);
+    if ( (rc = elf_xen_parse(&info->elf.elf, &info->elf.parms)) != 0 )
+        return rc;
+
+    /*
+     * FIXME: can the ELF header be used to find the physical address
+     * to load the image to?  Instead of making virt == phys by
+     * relocating the guest's RAM.
+     */
+    info->ram_start = 0xc0000000;
+    info->ram_end   = 0xc8000000;
+
+    info->entry = info->elf.parms.virt_entry;
+    info->load = kernel_elf_load;
+
+    return 0;
+}
+
+int kernel_prepare(struct kernel_info *info)
+{
+    int rc;
+
+    rc = kernel_try_zimage_prepare(info);
+    if (rc < 0)
+        rc = kernel_try_elf_prepare(info);
+
+    return rc;
+}
+
+void kernel_load(struct kernel_info *info)
+{
+    info->load(info);
+}
diff --git a/xen/arch/arm/kernel.h b/xen/arch/arm/kernel.h
new file mode 100644
index 0000000..5caebe5
--- /dev/null
+++ b/xen/arch/arm/kernel.h
@@ -0,0 +1,37 @@
+/*
+ * Kernel image loading.
+ *
+ * Copyright (C) 2011 Citrix Systems, Inc.
+ */
+#ifndef __ARCH_ARM_KERNEL_H__
+#define __ARCH_ARM_KERNEL_H__
+
+#include <xen/libelf.h>
+
+struct kernel_info {
+    paddr_t entry;
+    paddr_t ram_start;
+    paddr_t ram_end;
+
+    void *kernel_img;
+    unsigned kernel_order;
+
+    union {
+        struct {
+            paddr_t load_addr;
+            paddr_t len;
+        } zimage;
+
+        struct {
+            struct elf_binary elf;
+            struct elf_dom_parms parms;
+        } elf;
+    };
+
+    void (*load)(struct kernel_info *info);
+};
+
+int kernel_prepare(struct kernel_info *info);
+void kernel_load(struct kernel_info *info);
+
+#endif /* #ifdef __ARCH_ARM_KERNEL_H__ */
-- 
1.7.2.5


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel


 


Rackspace

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