[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 |