#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);
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);
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);
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);
/* 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;
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);
--- /dev/null
+/*
+ * 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);
+}