|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH 08/11] device tree, arm: supply a flat device tree to dom0
On Mon, 2012-03-19 at 17:52 +0000, David Vrabel wrote:
> From: David Vrabel <david.vrabel@xxxxxxxxxx>
>
> Build a flat device tree for dom0 based on the one supplied to Xen.
> The following changes are made:
>
> * In the /chosen node, the xen,dom0-bootargs parameter is renamed to
> bootargs.
>
> * In all memory nodes, the reg parameters are adjusted to reflect
> the amount of memory dom0 can use. The p2m is updated using this
> info.
>
> Support for passing ATAGS to dom0 is removed.
With the series applied up to and including this patch my dom0 kernel
fails to boot with:
[ 0.000000] Linux version 3.2.0-rc5-arm-native+ (ianc@drall) (gcc version
4.6.0 (GCC) ) #77 Thu Mar 22 13:58:33 GMT 2012
[ 0.000000] CPU: ARMv7 Processor [410fc0f0] revision 0 (ARMv7), cr=10c53c7d
[ 0.000000] CPU: PIPT / VIPT nonaliasing data cache, VIPT aliasing
instruction cache
[ 0.000000] Machine: ARM Versatile Express, model: V2P-AEMv7A
[ 0.000000] bootconsole [earlycon0] enabled
[ 0.000000] Memory policy: ECC disabled, Data cache writeback
[ 0.000000] Kernel panic - not syncing: ERROR: Failed to allocate 0x1000
bytes below 0x0.
[ 0.000000]
[ 0.000000] [<c000d64c>] (unwind_backtrace+0x0/0xe0) from [<c0273558>]
(panic+0x50/0x17c)
[ 0.000000] [<c0273558>] (panic+0x50/0x17c) from [<c032ff04>]
(memblock_alloc_base+0x2c/0x34)
[ 0.000000] [<c032ff04>] (memblock_alloc_base+0x2c/0x34) from [<c0329f30>]
(early_alloc.constprop.3+0x10/0x28)
[ 0.000000] [<c0329f30>] (early_alloc.constprop.3+0x10/0x28) from
[<c032a8c0>] (paging_init+0x48c/0x628)
[ 0.000000] [<c032a8c0>] (paging_init+0x48c/0x628) from [<c0328678>]
(setup_arch+0x508/0x7ac)
[ 0.000000] [<c0328678>] (setup_arch+0x508/0x7ac) from [<c03254dc>]
(start_kernel+0x6c/0x2c0)
[ 0.000000] [<c03254dc>] (start_kernel+0x6c/0x2c0) from [<80008048>]
(0x80008048)
I'm guessing that the memory isn't being passed in correctly?
>
> Signed-off-by: David Vrabel <david.vrabel@xxxxxxxxxx>
> ---
> xen/arch/arm/Makefile | 2 +
> xen/arch/arm/domain_build.c | 253
> ++++++++++++++++++++++++++++++++++-------
> xen/arch/arm/kernel.c | 2 +-
> xen/arch/arm/kernel.h | 8 +-
> xen/common/device_tree.c | 47 +++++---
> xen/include/xen/device_tree.h | 8 ++
> 6 files changed, 260 insertions(+), 60 deletions(-)
>
> diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile
> index d5afb6b..8d6edf5 100644
> --- a/xen/arch/arm/Makefile
> +++ b/xen/arch/arm/Makefile
> @@ -27,6 +27,8 @@ obj-y += vtimer.o
>
> #obj-bin-y += ....o
>
> +CFLAGS += -I../../common/libfdt
> +
> ifdef CONFIG_DTB_FILE
> obj-y += dtb.o
> AFLAGS += -DCONFIG_DTB_FILE=\"$(CONFIG_DTB_FILE)\"
> diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c
> index 15632f7..963f1cf 100644
> --- a/xen/arch/arm/domain_build.c
> +++ b/xen/arch/arm/domain_build.c
> @@ -6,6 +6,10 @@
> #include <xen/sched.h>
> #include <asm/irq.h>
> #include <asm/regs.h>
> +#include <xen/errno.h>
> +#include <xen/device_tree.h>
> +#include <xen/libfdt/libfdt.h>
> +#include <xen/guest_access.h>
>
> #include "gic.h"
> #include "kernel.h"
> @@ -13,6 +17,12 @@
> static unsigned int __initdata opt_dom0_max_vcpus;
> integer_param("dom0_max_vcpus", opt_dom0_max_vcpus);
>
> +/*
> + * Amount of extra space required to dom0's device tree. No new nodes
> + * are added (yet) so no additional space is needed.
> + */
> +#define DOM0_FDT_EXTRA_SIZE 0
> +
> struct vcpu *__init alloc_dom0_vcpu0(void)
> {
> if ( opt_dom0_max_vcpus == 0 )
> @@ -28,43 +38,207 @@ struct vcpu *__init alloc_dom0_vcpu0(void)
> return alloc_vcpu(dom0, 0, 0);
> }
>
> -extern void guest_mode_entry(void);
> +static void set_memory_reg(struct domain *d, struct kernel_info *kinfo,
> + const void *fdt,
> + const u32 *cell, int address_cells, int
> size_cells,
> + u32 *new_cell, int *len)
> +{
> + int reg_size = (address_cells + size_cells) * sizeof(*cell);
> + int l;
> + u64 start;
> + u64 size;
> +
> + l = *len;
> +
> + while ( kinfo->unassigned_mem > 0 && l >= reg_size
> + && kinfo->mem.nr_banks < NR_MEM_BANKS )
> + {
> + device_tree_get_reg(&cell, address_cells, size_cells, &start, &size);
> + if ( size > kinfo->unassigned_mem )
> + size = kinfo->unassigned_mem;
> +
> + device_tree_set_reg(&new_cell, address_cells, size_cells, start,
> size);
> +
> + printk("Populate P2M %#llx->%#llx\n", start, start + size);
> + p2m_populate_ram(d, start, start + size);
> + kinfo->mem.bank[kinfo->mem.nr_banks].start = start;
> + kinfo->mem.bank[kinfo->mem.nr_banks].size = size;
> + kinfo->mem.nr_banks++;
> + kinfo->unassigned_mem -= size;
> +
> + l -= reg_size;
> + }
> +
> + *len -= l;
> +}
> +
> +static int write_properties(struct domain *d, struct kernel_info *kinfo,
> + const void *fdt,
> + int node, const char *name, int depth,
> + u32 address_cells, u32 size_cells)
> +{
> + int prop;
> +
> + for ( prop = fdt_first_property_offset(fdt, node);
> + prop >= 0;
> + prop = fdt_next_property_offset(fdt, prop) )
> + {
> + const struct fdt_property *p;
> + const char *prop_name;
> + const char *prop_data;
> + int prop_len;
> + char *new_data = NULL;
> +
> + p = fdt_get_property_by_offset(fdt, prop, NULL);
> + prop_name = fdt_string(fdt, fdt32_to_cpu(p->nameoff));
> + prop_data = p->data;
> + prop_len = fdt32_to_cpu(p->len);
> +
> + /*
> + * In chosen node: replace bootargs with value from
> + * xen,dom0-bootargs.
> + */
> + if ( device_tree_node_matches(fdt, node, "chosen") )
> + {
> + if ( strcmp(prop_name, "bootargs") == 0 )
> + continue;
> + if ( strcmp(prop_name, "xen,dom0-bootargs") == 0 )
> + prop_name = "bootargs";
> + }
> + /*
> + * In a memory node: adjust reg property.
> + */
> + else if ( device_tree_node_matches(fdt, node, "memory") )
> + {
> + if ( strcmp(prop_name, "reg") == 0 )
> + {
> + new_data = xzalloc_bytes(prop_len);
> + if ( new_data == NULL )
> + return -ENOMEM;
> +
> + set_memory_reg(d, kinfo, fdt,
> + (u32 *)prop_data, address_cells, size_cells,
> + (u32 *)new_data, &prop_len);
> + prop_data = new_data;
> + }
> + }
> +
> + /*
> + * TODO: Should call map_mmio_regions() for all devices in the
> + * tree that have a "reg" parameter (except cpus). This
> + * requires looking into the parent node's "ranges" property
> + * to translate the bus address in the "reg" value into
> + * physical addresses. Regions also need to be rounded up to
> + * whole pages.
> + */
> +
> + fdt_property(kinfo->fdt, prop_name, prop_data, prop_len);
> +
> + xfree(new_data);
> + }
> +
> + if ( prop == -FDT_ERR_NOTFOUND )
> + return 0;
> + return prop;
> +}
>
> -static void setup_linux_atag(paddr_t tags, paddr_t ram_s, paddr_t ram_e)
> +static int write_nodes(struct domain *d, struct kernel_info *kinfo,
> + const void *fdt)
> {
> - paddr_t ma = gvirt_to_maddr(tags);
> - void *map = map_domain_page(ma>>PAGE_SHIFT);
> - void *p = map + (tags & (PAGE_SIZE - 1));
> - char cmdline[] = "earlyprintk=xenboot console=ttyAMA1 root=/dev/mmcblk0
> debug rw";
> + int node;
> + int depth = 0, last_depth = -1;
> + u32 address_cells[DEVICE_TREE_MAX_DEPTH];
> + u32 size_cells[DEVICE_TREE_MAX_DEPTH];
> + int ret;
>
> - /* not enough room on this page for all the tags */
> - BUG_ON(PAGE_SIZE - (tags & (PAGE_SIZE - 1)) < 8 * sizeof(uint32_t));
> + for ( node = 0, depth = 0;
> + node >= 0 && depth >= 0;
> + node = fdt_next_node(fdt, node, &depth) )
> + {
> + const char *name;
>
> -#define TAG(type, val) *(type*)p = val; p+= sizeof(type)
> + name = fdt_get_name(fdt, node, NULL);
>
> - /* ATAG_CORE */
> - TAG(uint32_t, 2);
> - TAG(uint32_t, 0x54410001);
> + if ( depth >= DEVICE_TREE_MAX_DEPTH )
> + {
> + printk("warning: node `%s' is nested too deep\n", name);
> + continue;
> + }
>
> - /* ATAG_MEM */
> - TAG(uint32_t, 4);
> - TAG(uint32_t, 0x54410002);
> - TAG(uint32_t, (ram_e - ram_s) & 0xFFFFFFFF);
> - TAG(uint32_t, ram_s & 0xFFFFFFFF);
> + while ( last_depth-- >= depth )
> + fdt_end_node(kinfo->fdt);
>
> - /* ATAG_CMDLINE */
> - TAG(uint32_t, 2 + ((strlen(cmdline) + 4) >> 2));
> - TAG(uint32_t, 0x54410009);
> - memcpy(p, cmdline, strlen(cmdline) + 1);
> - p += ((strlen(cmdline) + 4) >> 2) << 2;
> + address_cells[depth] = device_tree_get_u32(fdt, node,
> "#address-cells");
> + size_cells[depth] = device_tree_get_u32(fdt, node, "#size-cells");
>
> - /* ATAG_NONE */
> - TAG(uint32_t, 0);
> - TAG(uint32_t, 0);
> + fdt_begin_node(kinfo->fdt, name);
>
> -#undef TAG
> + ret = write_properties(d, kinfo, fdt, node, name, depth,
> + address_cells[depth-1], size_cells[depth-1]);
> + if ( ret < 0 )
> + return ret;
>
> - unmap_domain_page(map);
> + last_depth = depth;
> + }
> +
> + while ( last_depth-- >= 0 )
> + fdt_end_node(kinfo->fdt);
> +
> + return 0;
> +}
> +
> +static int prepare_dtb(struct domain *d, struct kernel_info *kinfo)
> +{
> + void *fdt;
> + int new_size;
> + int ret;
> +
> + fdt = device_tree_flattened;
> +
> + new_size = fdt_totalsize(fdt) + DOM0_FDT_EXTRA_SIZE;
> + kinfo->fdt = xmalloc_bytes(new_size);
> + if ( kinfo->fdt == NULL )
> + return -ENOMEM;
> +
> + ret = fdt_create(kinfo->fdt, new_size);
> + if ( ret < 0 )
> + goto err;
> +
> + fdt_finish_reservemap(kinfo->fdt);
> +
> + ret = write_nodes(d, kinfo, fdt);
> + if ( ret < 0 )
> + goto err;
> +
> + fdt_finish(kinfo->fdt);
> +
> + device_tree_dump(kinfo->fdt);
> +
> + /*
> + * Put the device tree at the beginning of the first bank. It
> + * must be below 4 GiB.
> + */
> + kinfo->dtb_paddr = kinfo->mem.bank[0].start + 0x100;
> + if ( kinfo->dtb_paddr + fdt_totalsize(kinfo->fdt) > (1ull << 32) )
> + {
> + printk("Not enough memory below 4 GiB for the device tree.");
> + ret = -EINVAL;
> + goto err;
> + }
> +
> + return 0;
> +
> + err:
> + xfree(kinfo->fdt);
> + return ret;
> +}
> +
> +static void dtb_load(struct kernel_info *kinfo)
> +{
> + void * __user dtb_virt = (void *)(u32)kinfo->dtb_paddr;
> +
> + raw_copy_to_guest(dtb_virt, kinfo->fdt, fdt_totalsize(kinfo->fdt));
> + xfree(kinfo->fdt);
> }
>
> int construct_dom0(struct domain *d)
> @@ -82,22 +256,20 @@ int construct_dom0(struct domain *d)
>
> printk("*** LOADING DOMAIN 0 ***\n");
>
> - /* 128M at 2G physical */
> - /* TODO size and location from DT. */
> - kinfo.ram_start = 0x80000000;
> - kinfo.ram_end = 0x88000000;
> + d->max_pages = ~0U;
>
> - rc = kernel_prepare(&kinfo);
> - if (rc < 0)
> + if ( (rc = p2m_alloc_table(d)) != 0 )
> return rc;
>
> - d->max_pages = ~0U;
> + kinfo.unassigned_mem = 0x08000000; /* XXX */
>
> - if ( (rc = p2m_alloc_table(d)) != 0 )
> + rc = prepare_dtb(d, &kinfo);
> + if ( rc < 0 )
> return rc;
>
> - printk("Populate P2M %#llx->%#llx\n", kinfo.ram_start, kinfo.ram_end);
> - p2m_populate_ram(d, kinfo.ram_start, kinfo.ram_end);
> + rc = kernel_prepare(&kinfo);
> + if ( rc < 0 )
> + return rc;
>
> printk("Map CS2 MMIO regions 1:1 in the P2M %#llx->%#llx\n",
> 0x18000000ULL, 0x1BFFFFFFULL);
> map_mmio_regions(d, 0x18000000, 0x1BFFFFFF, 0x18000000);
> @@ -125,13 +297,12 @@ int construct_dom0(struct domain *d)
> /* Enable second stage translation */
> WRITE_CP32(READ_CP32(HCR) | HCR_VM, HCR); isb();
>
> - /* The following load uses domain's p2m */
> + /* The following loads use the domain's p2m */
> p2m_load_VTTBR(d);
>
> + dtb_load(&kinfo);
> kernel_load(&kinfo);
>
> - 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));
> @@ -153,7 +324,7 @@ int construct_dom0(struct domain *d)
>
> regs->r0 = 0; /* SBZ */
> regs->r1 = 2272; /* Machine NR: Versatile Express */
> - regs->r2 = kinfo.ram_start + 0x100; /* ATAGS */
> + regs->r2 = kinfo.dtb_paddr;
>
> WRITE_CP32(SCTLR_BASE, SCTLR);
>
> diff --git a/xen/arch/arm/kernel.c b/xen/arch/arm/kernel.c
> index dd757e5..130d488 100644
> --- a/xen/arch/arm/kernel.c
> +++ b/xen/arch/arm/kernel.c
> @@ -121,7 +121,7 @@ static int kernel_try_zimage_prepare(struct kernel_info
> *info)
> * at 32k from start of RAM.
> */
> if (start == 0)
> - info->zimage.load_addr = info->ram_start + 0x8000;
> + info->zimage.load_addr = info->mem.bank[0].start + 0x8000;
> else
> info->zimage.load_addr = start;
> info->zimage.len = end - start;
> diff --git a/xen/arch/arm/kernel.h b/xen/arch/arm/kernel.h
> index 5caebe5..4533568 100644
> --- a/xen/arch/arm/kernel.h
> +++ b/xen/arch/arm/kernel.h
> @@ -7,11 +7,15 @@
> #define __ARCH_ARM_KERNEL_H__
>
> #include <xen/libelf.h>
> +#include <xen/device_tree.h>
>
> struct kernel_info {
> + void *fdt; /* flat device tree */
> + paddr_t unassigned_mem; /* RAM not (yet) assigned to a bank */
> + struct dt_mem_info mem;
> +
> + paddr_t dtb_paddr;
> paddr_t entry;
> - paddr_t ram_start;
> - paddr_t ram_end;
>
> void *kernel_img;
> unsigned kernel_order;
> diff --git a/xen/common/device_tree.c b/xen/common/device_tree.c
> index d4b1556..715fbf6 100644
> --- a/xen/common/device_tree.c
> +++ b/xen/common/device_tree.c
> @@ -23,7 +23,7 @@
> struct dt_early_info __initdata early_info;
> void *device_tree_flattened;
>
> -static bool_t __init node_matches(const void *fdt, int node, const char
> *match)
> +bool_t device_tree_node_matches(const void *fdt, int node, const char *match)
> {
> const char *name;
> size_t match_len;
> @@ -48,16 +48,33 @@ static void __init get_val(const u32 **cell, u32 cells,
> u64 *val)
> }
> }
>
> -static void __init get_register(const u32 **cell,
> - u32 address_cells, u32 size_cells,
> - u64 *start, u64 *size)
> +void device_tree_get_reg(const u32 **cell, u32 address_cells, u32 size_cells,
> + u64 *start, u64 *size)
> {
> get_val(cell, address_cells, start);
> get_val(cell, size_cells, size);
> }
>
> -static u32 __init prop_by_name_u32(const void *fdt, int node,
> - const char *prop_name)
> +static void set_val(u32 **cell, u32 cells, u64 val)
> +{
> + u32 c = cells;
> +
> + while ( c-- )
> + {
> + (*cell)[c] = cpu_to_fdt32(val);
> + val >>= 32;
> + }
> + (*cell) += cells;
> +}
> +
> +void device_tree_set_reg(u32 **cell, u32 address_cells, u32 size_cells,
> + u64 start, u64 size)
> +{
> + set_val(cell, address_cells, start);
> + set_val(cell, size_cells, size);
> +}
> +
> +u32 device_tree_get_u32(const void *fdt, int node, const char *prop_name)
> {
> const struct fdt_property *prop;
>
> @@ -68,8 +85,6 @@ static u32 __init prop_by_name_u32(const void *fdt, int
> node,
> return fdt32_to_cpu(*(uint32_t*)prop->data);
> }
>
> -#define MAX_DEPTH 16
> -
> /**
> * device_tree_for_each_node - iterate over all device tree nodes
> * @fdt: flat device tree.
> @@ -81,19 +96,19 @@ int device_tree_for_each_node(const void *fdt,
> {
> int node;
> int depth;
> - u32 address_cells[MAX_DEPTH];
> - u32 size_cells[MAX_DEPTH];
> + u32 address_cells[DEVICE_TREE_MAX_DEPTH];
> + u32 size_cells[DEVICE_TREE_MAX_DEPTH];
> int ret;
>
> for ( node = 0, depth = 0;
> node >=0 && depth >= 0;
> node = fdt_next_node(fdt, node, &depth) )
> {
> - if ( depth >= MAX_DEPTH )
> + if ( depth >= DEVICE_TREE_MAX_DEPTH )
> continue;
>
> - address_cells[depth] = prop_by_name_u32(fdt, node, "#address-cells");
> - size_cells[depth] = prop_by_name_u32(fdt, node, "#size-cells");
> + address_cells[depth] = device_tree_get_u32(fdt, node,
> "#address-cells");
> + size_cells[depth] = device_tree_get_u32(fdt, node, "#size-cells");
>
> ret = func(fdt, node, fdt_get_name(fdt, node, NULL), depth,
> address_cells[depth-1], size_cells[depth-1], data);
> @@ -106,7 +121,7 @@ int device_tree_for_each_node(const void *fdt,
> static int dump_node(const void *fdt, int node, const char *name, int depth,
> u32 address_cells, u32 size_cells, void *data)
> {
> - char prefix[2*MAX_DEPTH + 1] = "";
> + char prefix[2*DEVICE_TREE_MAX_DEPTH + 1] = "";
> int i;
> int prop;
>
> @@ -172,7 +187,7 @@ static void __init process_memory_node(const void *fdt,
> int node,
>
> for ( i = 0; i < banks && early_info.mem.nr_banks < NR_MEM_BANKS; i++ )
> {
> - get_register(&cell, address_cells, size_cells, &start, &size);
> + device_tree_get_reg(&cell, address_cells, size_cells, &start, &size);
> early_info.mem.bank[early_info.mem.nr_banks].start = start;
> early_info.mem.bank[early_info.mem.nr_banks].size = size;
> early_info.mem.nr_banks++;
> @@ -184,7 +199,7 @@ static int __init early_scan_node(const void *fdt,
> u32 address_cells, u32 size_cells,
> void *data)
> {
> - if ( node_matches(fdt, node, "memory") )
> + if ( device_tree_node_matches(fdt, node, "memory") )
> process_memory_node(fdt, node, name, address_cells, size_cells);
>
> return 0;
> diff --git a/xen/include/xen/device_tree.h b/xen/include/xen/device_tree.h
> index b91b39f..510b5b4 100644
> --- a/xen/include/xen/device_tree.h
> +++ b/xen/include/xen/device_tree.h
> @@ -12,6 +12,8 @@
>
> #include <xen/types.h>
>
> +#define DEVICE_TREE_MAX_DEPTH 16
> +
> #define NR_MEM_BANKS 8
>
> struct membank {
> @@ -39,6 +41,12 @@ extern void *device_tree_flattened;
> size_t device_tree_early_init(const void *fdt);
> paddr_t device_tree_get_xen_paddr(void);
>
> +void device_tree_get_reg(const u32 **cell, u32 address_cells, u32 size_cells,
> + u64 *start, u64 *size);
> +void device_tree_set_reg(u32 **cell, u32 address_cells, u32 size_cells,
> + u64 start, u64 size);
> +u32 device_tree_get_u32(const void *fdt, int node, const char *prop_name);
> +bool_t device_tree_node_matches(const void *fdt, int node, const char
> *match);
> int device_tree_for_each_node(const void *fdt,
> device_tree_node_func func, void *data);
> void device_tree_dump(const void *fdt);
> --
> 1.7.2.5
>
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |