Ian Campbell
2012-Dec-03 17:10 UTC
[PATCH 00/08 V2] arm: support for initial modules (e.g. dom0) and DTB supplied in RAM
The following series implements support for initial images and DTB in RAM, as opposed to in flash (dom0 kernel) or compiled into the hypervisor (DTB). It arranges to not clobber these with either the h/v text on relocation or with the heaps and frees them as appropriate. Most of this is independent of the specific bootloader protocol which is used to tell Xen where these modules actually are, but I have included a simple PoC bootloader protocol based around device tree which is similar to the protocol used by Linux to find its initrd (where /chosen/linux,initrd-{start,end} indicate the physical address). The PoC protocol is documented in docs/misc/arm/device-tree/booting.txt which is added by this series. Some of the smaller patches went in already, but most of the meat remains. The major change this time is that the protocol now uses a reg property for the address and size, e.g. something like this: /chosen/modules@1 { bootargs = "root=/dev/mmcblk0 ro debug" reg = <0x200000 0x2000> } I have pushed an updated boot-wrapper to: git://xenbits.xen.org/people/ianc/boot-wrapper.git Ian.
Ian Campbell
2012-Dec-03 17:10 UTC
[PATCH 1/8] arm: parse modules from DT during early boot.
The bootloader should populate /chosen/module@<N>/ for each module it wishes to pass to the hypervisor. The content of these nodes is described in docs/misc/arm/device-tree/booting.txt The hypervisor allows for 2 modules (@1==kernel and @2==initrd). Currently we don''t do anything with them. Signed-off-by: Ian Campbell <ian.campbell@citrix.com> --- v3: Use a reg = < > property for the module address/length. v2: Reserve the zeroeth module for Xen itself (not used yet) Use a more idiomatic DT layout Document said layout xen: arm: use a reg for the module addresses --- docs/misc/arm/device-tree/booting.txt | 24 ++++++++++++ xen/common/device_tree.c | 65 +++++++++++++++++++++++++++++++++ xen/include/xen/device_tree.h | 14 +++++++ 3 files changed, 103 insertions(+), 0 deletions(-) create mode 100644 docs/misc/arm/device-tree/booting.txt diff --git a/docs/misc/arm/device-tree/booting.txt b/docs/misc/arm/device-tree/booting.txt new file mode 100644 index 0000000..2761b91 --- /dev/null +++ b/docs/misc/arm/device-tree/booting.txt @@ -0,0 +1,24 @@ +Xen is passed the dom0 kernel and initrd via a reference in the /chosen +node of the device tree. + +Each node has the form /chosen/module@<N> and contains the following +properties: + +- compatible + + Must be "xen,multiboot-module" + +- reg + + Specifies the physical address of the module in RAM and the + length of the module. + +- bootargs (optional) + + Command line associated with this module + +The following modules are understood + +- 1 -- the domain 0 kernel +- 2 -- the domain 0 ramdisk + diff --git a/xen/common/device_tree.c b/xen/common/device_tree.c index da0af77..9eb316f 100644 --- a/xen/common/device_tree.c +++ b/xen/common/device_tree.c @@ -270,6 +270,69 @@ static void __init process_cpu_node(const void *fdt, int node, cpumask_set_cpu(start, &cpu_possible_map); } +static void __init process_chosen_node(const void *fdt, int node, + const char *name, + u32 address_cells, u32 size_cells) +{ + const struct fdt_property *prop; + const u32 *cell; + int nr, depth, nr_modules = 0; + struct dt_mb_module *mod; + int len; + + for ( depth = 0; + depth >= 0; + node = fdt_next_node(fdt, node, &depth) ) + { + name = fdt_get_name(fdt, node, NULL); + if ( strncmp(name, "module@", strlen("module@")) == 0 ) { + + if ( fdt_node_check_compatible(fdt, node, + "xen,multiboot-module" ) != 0 ) + early_panic("%s not a compatible module node\n", name); + + nr = simple_strtol(name + strlen("module@"), NULL, 10); + if ( nr <= 0 ) + early_panic("Invalid module number %d\n", nr); + + if ( nr > NR_MODULES ) + early_panic("too many modules %d > %d\n", nr, NR_MODULES); + if ( nr > nr_modules ) + nr_modules = nr; + + mod = &early_info.modules.module[nr]; + + prop = fdt_get_property(fdt, node, "reg", NULL); + if ( !prop ) + early_panic("node %s missing `reg'' property\n", name); + + cell = (const u32 *)prop->data; + device_tree_get_reg(&cell, address_cells, size_cells, + &mod->start, &mod->size); + + prop = fdt_get_property(fdt, node, "bootargs", &len); + if ( prop ) + { + if ( len > sizeof(mod->cmdline) ) + early_panic("module %d command line too long\n", nr); + + safe_strcpy(mod->cmdline, prop->data); + } + else + mod->cmdline[0] = 0; + } + } + + for ( nr = 1 ; nr < nr_modules ; nr++ ) + { + mod = &early_info.modules.module[nr]; + if ( !mod->start || !mod->size ) + early_panic("module %d missing / invalid\n", nr); + } + + early_info.modules.nr_mods = nr_modules; +} + static int __init early_scan_node(const void *fdt, int node, const char *name, int depth, u32 address_cells, u32 size_cells, @@ -279,6 +342,8 @@ static int __init early_scan_node(const void *fdt, process_memory_node(fdt, node, name, address_cells, size_cells); else if ( device_tree_type_matches(fdt, node, "cpu") ) process_cpu_node(fdt, node, name, address_cells, size_cells); + else if ( device_tree_node_matches(fdt, node, "chosen") ) + process_chosen_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 4d010c0..c383677 100644 --- a/xen/include/xen/device_tree.h +++ b/xen/include/xen/device_tree.h @@ -15,6 +15,7 @@ #define DEVICE_TREE_MAX_DEPTH 16 #define NR_MEM_BANKS 8 +#define NR_MODULES 2 struct membank { paddr_t start; @@ -26,8 +27,21 @@ struct dt_mem_info { struct membank bank[NR_MEM_BANKS]; }; +struct dt_mb_module { + paddr_t start; + paddr_t size; + char cmdline[1024]; +}; + +struct dt_module_info { + int nr_mods; + /* Module 0 is Xen itself, followed by the provided modules-proper */ + struct dt_mb_module module[NR_MODULES + 1]; +}; + struct dt_early_info { struct dt_mem_info mem; + struct dt_module_info modules; }; typedef int (*device_tree_node_func)(const void *fdt, -- 1.7.9.1
This will still fail if the modules are such that Xen is pushed out of the top 32M of RAM since it will then overlap with the domheap (or possibly xenheap). This will be dealt with later. Signed-off-by: Ian Campbell <ian.campbell@citrix.com> Acked-by: Tim Deegan <tim@xen.org> --- v2: Xen is module 0, modules start at 1. --- xen/arch/arm/setup.c | 68 ++++++++++++++++++++++++++++++++++++++++++++----- 1 files changed, 61 insertions(+), 7 deletions(-) diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c index 2076724..a97455e 100644 --- a/xen/arch/arm/setup.c +++ b/xen/arch/arm/setup.c @@ -68,17 +68,55 @@ static void __init processor_id(void) READ_CP32(ID_ISAR3), READ_CP32(ID_ISAR4), READ_CP32(ID_ISAR5)); } +/* + * Returns the end address of the highest region in the range s..e + * with required size and alignment that does not conflict with the + * modules from first_mod to nr_modules. + * + * For non-recursive callers first_mod should normally be 1. + */ +static paddr_t __init consider_modules(paddr_t s, paddr_t e, + uint32_t size, paddr_t align, + int first_mod) +{ + const struct dt_module_info *mi = &early_info.modules; + int i; + + s = (s+align-1) & ~(align-1); + e = e & ~(align-1); + + if ( s > e || e - s < size ) + return 0; + + for ( i = first_mod; i <= mi->nr_mods; i++ ) + { + paddr_t mod_s = mi->module[i].start; + paddr_t mod_e = mod_s + mi->module[i].size; + + if ( s < mod_e && mod_s < e ) + { + mod_e = consider_modules(mod_e, e, size, align, i+1); + if ( mod_e ) + return mod_e; + + return consider_modules(s, mod_s, size, align, i+1); + } + } + + return e; +} + /** * get_xen_paddr - get physical address to relocate Xen to * - * Xen is relocated to the top of RAM and aligned to a XEN_PADDR_ALIGN - * boundary. + * Xen is relocated to as near to the top of RAM as possible and + * aligned to a XEN_PADDR_ALIGN boundary. */ static paddr_t __init get_xen_paddr(void) { struct dt_mem_info *mi = &early_info.mem; paddr_t min_size; - paddr_t paddr = 0, t; + paddr_t paddr = 0; int i; min_size = (_end - _start + (XEN_PADDR_ALIGN-1)) & ~(XEN_PADDR_ALIGN-1); @@ -86,17 +124,33 @@ static paddr_t __init get_xen_paddr(void) /* Find the highest bank with enough space. */ for ( i = 0; i < mi->nr_banks; i++ ) { - if ( mi->bank[i].size >= min_size ) + const struct membank *bank = &mi->bank[i]; + paddr_t s, e; + + if ( bank->size >= min_size ) { - t = mi->bank[i].start + mi->bank[i].size - min_size; - if ( t > paddr ) - paddr = t; + e = consider_modules(bank->start, bank->start + bank->size, + min_size, XEN_PADDR_ALIGN, 1); + if ( !e ) + continue; + + s = e - min_size; + + if ( s > paddr ) + paddr = s; } } if ( !paddr ) early_panic("Not enough memory to relocate Xen\n"); + early_printk("Placing Xen at 0x%"PRIpaddr"-0x%"PRIpaddr"\n", + paddr, paddr + min_size); + + /* Xen is module 0 */ + early_info.modules.module[0].start = paddr; + early_info.modules.module[0].size = min_size; + return paddr; } -- 1.7.9.1
Ian Campbell
2012-Dec-03 17:10 UTC
[PATCH 3/8] arm: avoid allocating the heaps over modules or xen itself.
Signed-off-by: Ian Campbell <ian.campbell@citrix.com> Acked-by: Tim Deegan <tim@xen.org> --- xen/arch/arm/setup.c | 89 +++++++++++++++++++++++++++++++++++++++++++------ 1 files changed, 78 insertions(+), 11 deletions(-) diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c index a97455e..9f08daf 100644 --- a/xen/arch/arm/setup.c +++ b/xen/arch/arm/setup.c @@ -73,7 +73,8 @@ static void __init processor_id(void) * with required size and alignment that does not conflict with the * modules from first_mod to nr_modules. * - * For non-recursive callers first_mod should normally be 1. + * For non-recursive callers first_mod should normally be 0 (all + * modules and Xen itself) or 1 (all modules but not Xen). */ static paddr_t __init consider_modules(paddr_t s, paddr_t e, uint32_t size, paddr_t align, @@ -106,6 +107,34 @@ static paddr_t __init consider_modules(paddr_t s, paddr_t e, return e; } +/* + * Return the end of the non-module region starting at s. In other + * words return s the start of the next modules after s. + * + * Also returns the end of that module in *n. + */ +static paddr_t __init next_module(paddr_t s, paddr_t *n) +{ + struct dt_module_info *mi = &early_info.modules; + paddr_t lowest = ~(paddr_t)0; + int i; + + for ( i = 0; i <= mi->nr_mods; i++ ) + { + paddr_t mod_s = mi->module[i].start; + paddr_t mod_e = mod_s + mi->module[i].size; + + if ( mod_s < s ) + continue; + if ( mod_s > lowest ) + continue; + lowest = mod_s; + *n = mod_e; + } + return lowest; +} + + /** * get_xen_paddr - get physical address to relocate Xen to * @@ -159,6 +188,7 @@ static void __init setup_mm(unsigned long dtb_paddr, size_t dtb_size) paddr_t ram_start; paddr_t ram_end; paddr_t ram_size; + paddr_t s, e; unsigned long ram_pages; unsigned long heap_pages, xenheap_pages, domheap_pages; unsigned long dtb_pages; @@ -176,22 +206,37 @@ static void __init setup_mm(unsigned long dtb_paddr, size_t dtb_size) ram_pages = ram_size >> PAGE_SHIFT; /* - * Calculate the sizes for the heaps using these constraints: + * Locate the xenheap using these constraints: * - * - heaps must be 32 MiB aligned - * - must not include Xen itself - * - xen heap must be at most 1 GiB + * - must be 32 MiB aligned + * - must not include Xen itself or the boot modules + * - must be at most 1 GiB + * - must be at least 128M * - * XXX: needs a platform with at least 1GiB of RAM or the dom - * heap will be empty and no domains can be created. + * We try to allocate the largest xenheap possible within these + * constraints. */ - heap_pages = (ram_size >> PAGE_SHIFT) - (32 << (20 - PAGE_SHIFT)); + heap_pages = (ram_size >> PAGE_SHIFT); xenheap_pages = min(1ul << (30 - PAGE_SHIFT), heap_pages); + + do + { + e = consider_modules(ram_start, ram_end, xenheap_pages<<PAGE_SHIFT, + 32<<20, 0); + if ( e ) + break; + + xenheap_pages >>= 1; + } while ( xenheap_pages > 128<<(20-PAGE_SHIFT) ); + + if ( ! e ) + panic("Not not enough space for xenheap\n"); + domheap_pages = heap_pages - xenheap_pages; printk("Xen heap: %lu pages Dom heap: %lu pages\n", xenheap_pages, domheap_pages); - setup_xenheap_mappings(ram_start >> PAGE_SHIFT, xenheap_pages); + setup_xenheap_mappings((e >> PAGE_SHIFT) - xenheap_pages, xenheap_pages); /* * Need a single mapped page for populating bootmem_region_list @@ -215,8 +260,30 @@ static void __init setup_mm(unsigned long dtb_paddr, size_t dtb_size) copy_from_paddr(device_tree_flattened, dtb_paddr, dtb_size, BUFFERABLE); /* Add non-xenheap memory */ - init_boot_pages(pfn_to_paddr(xenheap_mfn_start + xenheap_pages), - pfn_to_paddr(xenheap_mfn_start + xenheap_pages + domheap_pages)); + s = ram_start; + while ( s < ram_end ) + { + paddr_t n = ram_end; + + e = next_module(s, &n); + + if ( e == ~(paddr_t)0 ) + { + e = n = ram_end; + } + + /* Avoid the xenheap */ + if ( s < ((xenheap_mfn_start+xenheap_pages) << PAGE_SHIFT) + && (xenheap_mfn_start << PAGE_SHIFT) < e ) + { + e = pfn_to_paddr(xenheap_mfn_start); + n = pfn_to_paddr(xenheap_mfn_start+xenheap_pages); + } + + init_boot_pages(s, e); + + s = n; + } setup_frametable_mappings(ram_start, ram_end); max_page = PFN_DOWN(ram_end); -- 1.7.9.1
Ian Campbell
2012-Dec-03 17:10 UTC
[PATCH 4/8] device-tree: get_val cannot cope with cells > 2, add early_panic
Signed-off-by: Ian Campbell <ian.campbell@citrix.com> --- v3: early_panic instead of BUG_ON v2: drop unrelated white space fixup --- xen/common/device_tree.c | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-) diff --git a/xen/common/device_tree.c b/xen/common/device_tree.c index 9eb316f..5a0a1a6 100644 --- a/xen/common/device_tree.c +++ b/xen/common/device_tree.c @@ -58,6 +58,9 @@ static void __init get_val(const u32 **cell, u32 cells, u64 *val) { *val = 0; + if ( cells > 2 ) + early_panic("dtb value contains > 2 cells\n"); + while ( cells-- ) { *val <<= 32; -- 1.7.9.1
Ian Campbell
2012-Dec-03 17:10 UTC
[PATCH 5/8] arm: load dom0 kernel from first boot module
Signed-off-by: Ian Campbell <ian.campbell@citrix.com> --- v3: - correct limit check in try_zimage_prepare - copy zimage header to a local bufffer to avoid issues with crossing page boundaries. - handle non page aligned source and destinations when loading - use a BUFFERABLE mapping when loading kernel from RAM. --- xen/arch/arm/kernel.c | 91 ++++++++++++++++++++++++++++++++++-------------- xen/arch/arm/kernel.h | 11 ++++++ 2 files changed, 75 insertions(+), 27 deletions(-) diff --git a/xen/arch/arm/kernel.c b/xen/arch/arm/kernel.c index 2d56130..c9265d7 100644 --- a/xen/arch/arm/kernel.c +++ b/xen/arch/arm/kernel.c @@ -22,6 +22,7 @@ #define ZIMAGE_MAGIC_OFFSET 0x24 #define ZIMAGE_START_OFFSET 0x28 #define ZIMAGE_END_OFFSET 0x2c +#define ZIMAGE_HEADER_LEN 0x30 #define ZIMAGE_MAGIC 0x016f2818 @@ -65,40 +66,42 @@ void copy_from_paddr(void *dst, paddr_t paddr, unsigned long len, int attrindx) static void kernel_zimage_load(struct kernel_info *info) { paddr_t load_addr = info->zimage.load_addr; + paddr_t paddr = info->zimage.kernel_addr; + paddr_t attr = info->load_attr; 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 ) + printk("Loading zImage from %"PRIpaddr" to %"PRIpaddr"-%"PRIpaddr"\n", + paddr, load_addr, load_addr + len); + for ( offs = 0; offs < len; ) { - paddr_t ma = gvirt_to_maddr(load_addr + offs); + paddr_t s, l, ma = gvirt_to_maddr(load_addr + offs); void *dst = map_domain_page(ma>>PAGE_SHIFT); - if ( ( offs % (1<<20) ) == 0 ) - printk("."); + s = offs & ~PAGE_MASK; + l = min(PAGE_SIZE - s, len); - set_fixmap(FIXMAP_MISC, (flash+offs) >> PAGE_SHIFT, DEV_SHARED); - memcpy(dst, src, PAGE_SIZE); - clear_fixmap(FIXMAP_MISC); + copy_from_paddr(dst + s, paddr + offs, l, attr); unmap_domain_page(dst); + offs += l; } - printk("]\n"); } /** * Check the image is a zImage and return the load address and length */ -static int kernel_try_zimage_prepare(struct kernel_info *info) +static int kernel_try_zimage_prepare(struct kernel_info *info, + paddr_t addr, paddr_t size) { - uint32_t *zimage = (void *)FIXMAP_ADDR(FIXMAP_MISC); + uint32_t zimage[ZIMAGE_HEADER_LEN/4]; uint32_t start, end; struct minimal_dtb_header dtb_hdr; - set_fixmap(FIXMAP_MISC, KERNEL_FLASH_ADDRESS >> PAGE_SHIFT, DEV_SHARED); + if ( size < ZIMAGE_HEADER_LEN ) + return -EINVAL; + + copy_from_paddr(zimage, addr, sizeof(zimage), DEV_SHARED); if (zimage[ZIMAGE_MAGIC_OFFSET/4] != ZIMAGE_MAGIC) return -EINVAL; @@ -106,16 +109,26 @@ static int kernel_try_zimage_prepare(struct kernel_info *info) start = zimage[ZIMAGE_START_OFFSET/4]; end = zimage[ZIMAGE_END_OFFSET/4]; - clear_fixmap(FIXMAP_MISC); + if ( (end - start) > size ) + return -EINVAL; /* * Check for an appended DTB. */ - copy_from_paddr(&dtb_hdr, KERNEL_FLASH_ADDRESS + end - start, sizeof(dtb_hdr), DEV_SHARED); - if (be32_to_cpu(dtb_hdr.magic) == DTB_MAGIC) { - end += be32_to_cpu(dtb_hdr.total_size); + if ( addr + end - start + sizeof(dtb_hdr) <= size ) + { + copy_from_paddr(&dtb_hdr, addr + end - start, + sizeof(dtb_hdr), DEV_SHARED); + if (be32_to_cpu(dtb_hdr.magic) == DTB_MAGIC) { + end += be32_to_cpu(dtb_hdr.total_size); + + if ( end > addr + size ) + return -EINVAL; + } } + info->zimage.kernel_addr = addr; + /* * If start is zero, the zImage is position independent -- load it * at 32k from start of RAM. @@ -142,25 +155,26 @@ static void kernel_elf_load(struct kernel_info *info) free_xenheap_pages(info->kernel_img, info->kernel_order); } -static int kernel_try_elf_prepare(struct kernel_info *info) +static int kernel_try_elf_prepare(struct kernel_info *info, + paddr_t addr, paddr_t size) { int rc; - info->kernel_order = get_order_from_bytes(KERNEL_FLASH_SIZE); + info->kernel_order = get_order_from_bytes(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_paddr(info->kernel_img, KERNEL_FLASH_ADDRESS, KERNEL_FLASH_SIZE, DEV_SHARED); + copy_from_paddr(info->kernel_img, addr, size, info->load_attr); - if ( (rc = elf_init(&info->elf.elf, info->kernel_img, KERNEL_FLASH_SIZE )) != 0 ) - return rc; + if ( (rc = elf_init(&info->elf.elf, info->kernel_img, size )) != 0 ) + goto err; #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; + goto err; /* * TODO: can the ELF header be used to find the physical address @@ -170,15 +184,38 @@ static int kernel_try_elf_prepare(struct kernel_info *info) info->load = kernel_elf_load; return 0; +err: + free_xenheap_pages(info->kernel_img, info->kernel_order); + return rc; } int kernel_prepare(struct kernel_info *info) { int rc; - rc = kernel_try_zimage_prepare(info); + paddr_t start, size; + + if ( early_info.modules.nr_mods > 1 ) + panic("Cannot handle dom0 initrd yet\n"); + + if ( early_info.modules.nr_mods < 1 ) + { + printk("No boot modules found, trying flash\n"); + start = KERNEL_FLASH_ADDRESS; + size = KERNEL_FLASH_SIZE; + info->load_attr = DEV_SHARED; + } + else + { + printk("Loading kernel from boot module 1\n"); + start = early_info.modules.module[1].start; + size = early_info.modules.module[1].size; + info->load_attr = BUFFERABLE; + } + + rc = kernel_try_zimage_prepare(info, start, size); if (rc < 0) - rc = kernel_try_elf_prepare(info); + rc = kernel_try_elf_prepare(info, start, size); return rc; } diff --git a/xen/arch/arm/kernel.h b/xen/arch/arm/kernel.h index 4533568..49fe9da 100644 --- a/xen/arch/arm/kernel.h +++ b/xen/arch/arm/kernel.h @@ -22,6 +22,7 @@ struct kernel_info { union { struct { + paddr_t kernel_addr; paddr_t load_addr; paddr_t len; } zimage; @@ -33,9 +34,19 @@ struct kernel_info { }; void (*load)(struct kernel_info *info); + int load_attr; }; int kernel_prepare(struct kernel_info *info); void kernel_load(struct kernel_info *info); #endif /* #ifdef __ARCH_ARM_KERNEL_H__ */ + +/* + * Local variables: + * mode: C + * c-set-style: "BSD" + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + */ -- 1.7.9.1
Ian Campbell
2012-Dec-03 17:10 UTC
[PATCH 6/8] arm: discard boot modules after building domain 0.
Signed-off-by: Ian Campbell <ian.campbell@citrix.com> Acked-by: Tim Deegan <tim@xen.org> --- xen/arch/arm/domain_build.c | 3 +++ xen/arch/arm/setup.c | 16 ++++++++++++++++ xen/include/asm-arm/setup.h | 2 ++ 3 files changed, 21 insertions(+), 0 deletions(-) diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c index a9e7f43..e96ed10 100644 --- a/xen/arch/arm/domain_build.c +++ b/xen/arch/arm/domain_build.c @@ -10,6 +10,7 @@ #include <xen/device_tree.h> #include <xen/libfdt/libfdt.h> #include <xen/guest_access.h> +#include <asm/setup.h> #include "gic.h" #include "kernel.h" @@ -308,6 +309,8 @@ int construct_dom0(struct domain *d) dtb_load(&kinfo); kernel_load(&kinfo); + discard_initial_modules(); + clear_bit(_VPF_down, &v->pause_flags); memset(regs, 0, sizeof(*regs)); diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c index 9f08daf..1eb8f77 100644 --- a/xen/arch/arm/setup.c +++ b/xen/arch/arm/setup.c @@ -68,6 +68,22 @@ static void __init processor_id(void) READ_CP32(ID_ISAR3), READ_CP32(ID_ISAR4), READ_CP32(ID_ISAR5)); } +void __init discard_initial_modules(void) +{ + struct dt_module_info *mi = &early_info.modules; + int i; + + for ( i = 1; i <= mi->nr_mods; i++ ) + { + paddr_t s = mi->module[i].start; + paddr_t e = s + PAGE_ALIGN(mi->module[i].size); + + init_domheap_pages(s, e); + } + + mi->nr_mods = 0; +} + /* * Returns the end address of the highest region in the range s..e * with required size and alignment that does not conflict with the diff --git a/xen/include/asm-arm/setup.h b/xen/include/asm-arm/setup.h index 8769f66..3267db0 100644 --- a/xen/include/asm-arm/setup.h +++ b/xen/include/asm-arm/setup.h @@ -9,6 +9,8 @@ void arch_get_xen_caps(xen_capabilities_info_t *info); int construct_dom0(struct domain *d); +void discard_initial_modules(void); + #endif /* * Local variables: -- 1.7.9.1
Ian Campbell
2012-Dec-03 17:10 UTC
[PATCH 7/8] arm: use /chosen/module@1/bootargs for domain 0 command line
Fallback to xen,dom0-bootargs if this isn''t present. Ideally this would use module1-args iff the kernel came from module@1/{start,end} and the existing xen,dom0-bootargs if the kernel came from flash, but this approach is simpler and has the same effect in practice. Signed-off-by: Ian Campbell <ian.campbell@citrix.com> Acked-by: Tim Deegan <tim@xen.org> --- v2: update for new DT layout --- xen/arch/arm/domain_build.c | 28 ++++++++++++++++++++++++---- 1 files changed, 24 insertions(+), 4 deletions(-) diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c index e96ed10..7a964f7 100644 --- a/xen/arch/arm/domain_build.c +++ b/xen/arch/arm/domain_build.c @@ -86,8 +86,13 @@ static int write_properties(struct domain *d, struct kernel_info *kinfo, int node, const char *name, int depth, u32 address_cells, u32 size_cells) { + const char *bootargs = NULL; int prop; + if ( early_info.modules.nr_mods >= 1 && + early_info.modules.module[1].cmdline[0] ) + bootargs = &early_info.modules.module[1].cmdline[0]; + for ( prop = fdt_first_property_offset(fdt, node); prop >= 0; prop = fdt_next_property_offset(fdt, prop) ) @@ -104,15 +109,22 @@ static int write_properties(struct domain *d, struct kernel_info *kinfo, prop_len = fdt32_to_cpu(p->len); /* - * In chosen node: replace bootargs with value from - * xen,dom0-bootargs. + * In chosen node: + * + * * remember xen,dom0-bootargs if we don''t already have + * bootargs (from module #1, above). + * * remove bootargs and 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"; + else if ( strcmp(prop_name, "xen,dom0-bootargs") == 0 ) + { + if ( !bootargs ) + bootargs = prop_data; + continue; + } } /* * In a memory node: adjust reg property. @@ -147,6 +159,14 @@ static int write_properties(struct domain *d, struct kernel_info *kinfo, xfree(new_data); } + if ( device_tree_node_matches(fdt, node, "chosen") && bootargs ) + fdt_property(kinfo->fdt, "bootargs", bootargs, strlen(bootargs)); + + /* + * XXX should populate /chosen/linux,initrd-{start,end} here if we + * have module[2] + */ + if ( prop == -FDT_ERR_NOTFOUND ) return 0; return prop; -- 1.7.9.1
Ian Campbell
2012-Dec-03 17:10 UTC
[PATCH 8/8] xen: strip /chosen/module@<N>/* from dom0 device tree
These nodes are used by Xen to find the initial modules. Only drop the "xen,multiboot-module" compatible nodes in case someone else has a similar idea. Signed-off-by: Ian Campbell <ian.campbell@citrix.com> --- v3 - use a helper to filter out DT elements which are not for dom0. Better than an ad-hoc break in the middle of a loop. --- xen/arch/arm/domain_build.c | 39 +++++++++++++++++++++++++++++++++++++-- 1 files changed, 37 insertions(+), 2 deletions(-) diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c index 7a964f7..8624be2 100644 --- a/xen/arch/arm/domain_build.c +++ b/xen/arch/arm/domain_build.c @@ -172,6 +172,39 @@ static int write_properties(struct domain *d, struct kernel_info *kinfo, return prop; } +/* Returns the next node in fdt (starting from offset) which should be + * passed through to dom0. + */ +static int fdt_next_dom0_node(const void *fdt, int node, + int *depth_out, + int parents[DEVICE_TREE_MAX_DEPTH]) +{ + int depth = *depth_out; + + while ( (node = fdt_next_node(fdt, node, &depth)) && + node >= 0 && depth >= 0 ) + { + if ( depth >= DEVICE_TREE_MAX_DEPTH ) + break; + + parents[depth] = node; + + /* Skip /chosen/module@<N>/ and all subnodes */ + if ( depth >= 2 && + device_tree_node_matches(fdt, parents[1], "chosen") && + device_tree_node_matches(fdt, parents[2], "module") && + fdt_node_check_compatible(fdt, parents[2], + "xen,multiboot-module" ) == 0 ) + continue; + + /* We''ve arrived at a node which dom0 is interested in. */ + break; + } + + *depth_out = depth; + return node; +} + static int write_nodes(struct domain *d, struct kernel_info *kinfo, const void *fdt) { @@ -179,11 +212,12 @@ static int write_nodes(struct domain *d, struct kernel_info *kinfo, int depth = 0, last_depth = -1; u32 address_cells[DEVICE_TREE_MAX_DEPTH]; u32 size_cells[DEVICE_TREE_MAX_DEPTH]; + int parents[DEVICE_TREE_MAX_DEPTH]; int ret; for ( node = 0, depth = 0; node >= 0 && depth >= 0; - node = fdt_next_node(fdt, node, &depth) ) + node = fdt_next_dom0_node(fdt, node, &depth, parents) ) { const char *name; @@ -191,7 +225,8 @@ static int write_nodes(struct domain *d, struct kernel_info *kinfo, if ( depth >= DEVICE_TREE_MAX_DEPTH ) { - printk("warning: node `%s'' is nested too deep\n", name); + printk("warning: node `%s'' is nested too deep (%d)\n", + name, depth); continue; } -- 1.7.9.1
Tim Deegan
2012-Dec-06 11:56 UTC
Re: [PATCH 4/8] device-tree: get_val cannot cope with cells > 2, add early_panic
At 17:10 +0000 on 03 Dec (1354554627), Ian Campbell wrote:> Signed-off-by: Ian Campbell <ian.campbell@citrix.com>Acked-by: Tim Deegan <tim@xen.org>> --- > v3: early_panic instead of BUG_ON > v2: drop unrelated white space fixup > --- > xen/common/device_tree.c | 3 +++ > 1 files changed, 3 insertions(+), 0 deletions(-) > > diff --git a/xen/common/device_tree.c b/xen/common/device_tree.c > index 9eb316f..5a0a1a6 100644 > --- a/xen/common/device_tree.c > +++ b/xen/common/device_tree.c > @@ -58,6 +58,9 @@ static void __init get_val(const u32 **cell, u32 cells, u64 *val) > { > *val = 0; > > + if ( cells > 2 ) > + early_panic("dtb value contains > 2 cells\n"); > + > while ( cells-- ) > { > *val <<= 32; > -- > 1.7.9.1 > > > _______________________________________________ > Xen-devel mailing list > Xen-devel@lists.xen.org > http://lists.xen.org/xen-devel
Tim Deegan
2012-Dec-06 12:03 UTC
Re: [PATCH 5/8] arm: load dom0 kernel from first boot module
At 17:10 +0000 on 03 Dec (1354554628), Ian Campbell wrote:> Signed-off-by: Ian Campbell <ian.campbell@citrix.com>Acked-by: Tim Deegan <tim@xen.org>> --- > v3: - correct limit check in try_zimage_prepare > - copy zimage header to a local bufffer to avoid issues with > crossing page boundaries. > - handle non page aligned source and destinations when loading > - use a BUFFERABLE mapping when loading kernel from RAM. > --- > xen/arch/arm/kernel.c | 91 ++++++++++++++++++++++++++++++++++-------------- > xen/arch/arm/kernel.h | 11 ++++++ > 2 files changed, 75 insertions(+), 27 deletions(-) >
David Vrabel
2012-Dec-06 12:13 UTC
Re: [PATCH 4/8] device-tree: get_val cannot cope with cells > 2, add early_panic
On 03/12/12 17:10, Ian Campbell wrote:> Signed-off-by: Ian Campbell <ian.campbell@citrix.com> > --- > v3: early_panic instead of BUG_ON > v2: drop unrelated white space fixup > --- > xen/common/device_tree.c | 3 +++ > 1 files changed, 3 insertions(+), 0 deletions(-) > > diff --git a/xen/common/device_tree.c b/xen/common/device_tree.c > index 9eb316f..5a0a1a6 100644 > --- a/xen/common/device_tree.c > +++ b/xen/common/device_tree.c > @@ -58,6 +58,9 @@ static void __init get_val(const u32 **cell, u32 cells, u64 *val) > { > *val = 0; > > + if ( cells > 2 ) > + early_panic("dtb value contains > 2 cells\n"); > +This seems like overkill to me. get_val() truncates the value down to 64 bits which is fine as no valid physical address is more than 64 bits. I think the device tree parsing code should try to continue as much as possible if it gets a DTB that looks a bit funny. David
Ian Campbell
2012-Dec-06 13:00 UTC
Re: [PATCH 4/8] device-tree: get_val cannot cope with cells > 2, add early_panic
On Thu, 2012-12-06 at 12:13 +0000, David Vrabel wrote:> On 03/12/12 17:10, Ian Campbell wrote: > > Signed-off-by: Ian Campbell <ian.campbell@citrix.com> > > --- > > v3: early_panic instead of BUG_ON > > v2: drop unrelated white space fixup > > --- > > xen/common/device_tree.c | 3 +++ > > 1 files changed, 3 insertions(+), 0 deletions(-) > > > > diff --git a/xen/common/device_tree.c b/xen/common/device_tree.c > > index 9eb316f..5a0a1a6 100644 > > --- a/xen/common/device_tree.c > > +++ b/xen/common/device_tree.c > > @@ -58,6 +58,9 @@ static void __init get_val(const u32 **cell, u32 cells, u64 *val) > > { > > *val = 0; > > > > + if ( cells > 2 ) > > + early_panic("dtb value contains > 2 cells\n"); > > + > > This seems like overkill to me. get_val() truncates the value down to > 64 bits which is fine as no valid physical address is more than 64 bits.If something does end up giving us a >2 cell number (for example a 4 cell thing with an unhelpful endianess) then we will silently end up doing something which is unlikely to be the right thing. Ian.