diff --git a/tools/libxc/xc_dom.h b/tools/libxc/xc_dom.h index 7099ceebdd..c9af0cef13 100644 --- a/tools/libxc/xc_dom.h +++ b/tools/libxc/xc_dom.h @@ -68,6 +68,14 @@ struct xc_dom_image { /* memory layout */ struct xc_dom_seg kernel_seg; + /* If ramdisk_seg.vstart is non zero then the ramdisk will be + * loaded at that address, otherwise it will automatically placed. + * + * If automatic placement is used and the ramdisk is gzip + * compressed then it will be decompressed as it is loaded. If the + * ramdisk has been explicitly placed then it is loaded as is + * otherwise decompressing risks undoing the manual placement. + */ struct xc_dom_seg ramdisk_seg; struct xc_dom_seg p2m_seg; struct xc_dom_seg pgtables_seg; diff --git a/tools/libxc/xc_dom_arm.c b/tools/libxc/xc_dom_arm.c index a40e04ddfe..f051515404 100644 --- a/tools/libxc/xc_dom_arm.c +++ b/tools/libxc/xc_dom_arm.c @@ -249,6 +249,18 @@ int arch_setup_meminit(struct xc_dom_image *dom) { int rc; xen_pfn_t pfn, allocsz, i; + uint64_t modbase; + + /* Convenient */ + const uint64_t rambase = dom->rambase_pfn << XC_PAGE_SHIFT; + const uint64_t ramend = rambase + ( dom->total_pages << XC_PAGE_SHIFT ); + const uint64_t kernend = ROUNDUP(dom->kernel_seg.vend, 21/*2MB*/); + const uint64_t dtb_size = dom->devicetree_blob ? + ROUNDUP(dom->devicetree_size, XC_PAGE_SHIFT) : 0; + const uint64_t ramdisk_size = dom->ramdisk_blob ? + ROUNDUP(dom->ramdisk_size, XC_PAGE_SHIFT) : 0; + const uint64_t modsize = dtb_size + ramdisk_size; + const uint64_t ram128mb = rambase + (128<<20); rc = set_mode(dom->xch, dom->guest_domid, dom->guest_type); if ( rc ) @@ -278,23 +290,49 @@ int arch_setup_meminit(struct xc_dom_image *dom) 0, 0, &dom->p2m_host[i]); } - if ( dom->devicetree_blob ) + + /* + * Place boot modules at 128MB into RAM if there is enough RAM and + * the kernel does not overlap. Otherwise place them immediately + * after the kernel. If there is no space after the kernel then + * there is insufficient RAM and we fail. + */ + if ( ramend >= ram128mb + modsize && kernend < ram128mb ) + modbase = ram128mb; + else if ( ramend >= kernend + modsize ) + modbase = kernend; + else + return -1; + + DOMPRINTF("%s: placing boot modules at 0x%" PRIx64, __FUNCTION__, modbase); + + /* + * Must map DTB *after* initrd, to satisfy order of calls to + * xc_dom_alloc_segment in xc_dom_build_image, which must map + * things at monotonolically increasing addresses. + */ + if ( ramdisk_size ) { - const uint64_t rambase = dom->rambase_pfn << XC_PAGE_SHIFT; - const uint64_t ramend = rambase + ( dom->total_pages << XC_PAGE_SHIFT ); - const uint64_t dtbsize = ROUNDUP(dom->devicetree_size, XC_PAGE_SHIFT); + dom->ramdisk_seg.vstart = modbase; + dom->ramdisk_seg.vend = modbase + ramdisk_size; - /* Place at 128MB if there is sufficient RAM */ - if ( ramend >= rambase + 128*1024*1024 + dtbsize ) - dom->devicetree_seg.vstart = rambase + 128*1024*1024; - else /* otherwise at top of RAM */ - dom->devicetree_seg.vstart = ramend - dtbsize; + DOMPRINTF("%s: ramdisk: 0x%" PRIx64 " -> 0x%" PRIx64 "", + __FUNCTION__, + dom->ramdisk_seg.vstart, dom->ramdisk_seg.vend); + + modbase += ramdisk_size; + } + + if ( dtb_size ) + { + dom->devicetree_seg.vstart = modbase; + dom->devicetree_seg.vend = modbase + dtb_size; - dom->devicetree_seg.vend = - dom->devicetree_seg.vstart + dom->devicetree_size; DOMPRINTF("%s: devicetree: 0x%" PRIx64 " -> 0x%" PRIx64 "", __FUNCTION__, dom->devicetree_seg.vstart, dom->devicetree_seg.vend); + + modbase += dtb_size; } return 0; diff --git a/tools/libxc/xc_dom_core.c b/tools/libxc/xc_dom_core.c index b9d1015ee9..baa62a197e 100644 --- a/tools/libxc/xc_dom_core.c +++ b/tools/libxc/xc_dom_core.c @@ -955,13 +955,20 @@ int xc_dom_build_image(struct xc_dom_image *dom) size_t unziplen, ramdisklen; void *ramdiskmap; - unziplen = xc_dom_check_gzip(dom->xch, dom->ramdisk_blob, dom->ramdisk_size); - if ( xc_dom_ramdisk_check_size(dom, unziplen) != 0 ) + if ( !dom->ramdisk_seg.vstart ) + { + unziplen = xc_dom_check_gzip(dom->xch, + dom->ramdisk_blob, dom->ramdisk_size); + if ( xc_dom_ramdisk_check_size(dom, unziplen) != 0 ) + unziplen = 0; + } + else unziplen = 0; ramdisklen = unziplen ? unziplen : dom->ramdisk_size; - if ( xc_dom_alloc_segment(dom, &dom->ramdisk_seg, "ramdisk", 0, + if ( xc_dom_alloc_segment(dom, &dom->ramdisk_seg, "ramdisk", + dom->ramdisk_seg.vstart, ramdisklen) != 0 ) goto err; ramdiskmap = xc_dom_seg_to_ptr(dom, &dom->ramdisk_seg); diff --git a/tools/libxl/libxl_arch.h b/tools/libxl/libxl_arch.h index aee0a916fc..d3bc1369ec 100644 --- a/tools/libxl/libxl_arch.h +++ b/tools/libxl/libxl_arch.h @@ -19,7 +19,12 @@ int libxl__arch_domain_create(libxl__gc *gc, libxl_domain_config *d_config, uint32_t domid); -int libxl__arch_domain_configure(libxl__gc *gc, - libxl_domain_build_info *info, - struct xc_dom_image *dom); +/* setup arch specific hardware description, i.e. DTB on ARM */ +int libxl__arch_domain_init_hw_description(libxl__gc *gc, + libxl_domain_build_info *info, + struct xc_dom_image *dom); +/* finalize arch specific hardware description. */ +int libxl__arch_domain_finalise_hw_description(libxl__gc *gc, + libxl_domain_build_info *info, + struct xc_dom_image *dom); #endif diff --git a/tools/libxl/libxl_arm.c b/tools/libxl/libxl_arm.c index 0cfd0cf110..4f0f0e2f54 100644 --- a/tools/libxl/libxl_arm.c +++ b/tools/libxl/libxl_arm.c @@ -2,6 +2,7 @@ #include "libxl_arch.h" #include +#include #include #include @@ -31,6 +32,9 @@ typedef be32 gic_interrupt[3]; #define ROOT_ADDRESS_CELLS 2 #define ROOT_SIZE_CELLS 2 +#define PROP_INITRD_START "linux,initrd-start" +#define PROP_INITRD_END "linux,initrd-end" + static void set_cell(be32 **cellp, int size, uint64_t val) { int cells = size; @@ -155,7 +159,7 @@ static int make_root_properties(libxl__gc *gc, return 0; } -static int make_chosen_node(libxl__gc *gc, void *fdt, +static int make_chosen_node(libxl__gc *gc, void *fdt, bool ramdisk, const libxl_domain_build_info *info) { int res; @@ -169,6 +173,15 @@ static int make_chosen_node(libxl__gc *gc, void *fdt, if (res) return res; } + if (ramdisk) { + uint64_t dummy = 0; + LOG(DEBUG, "/chosen adding placeholder linux,initrd properties"); + res = fdt_property(fdt, PROP_INITRD_START, &dummy, sizeof(dummy)); + if (res) return res; + res = fdt_property(fdt, PROP_INITRD_END, &dummy, sizeof(dummy)); + if (res) return res; + } + res = fdt_end_node(fdt); if (res) return res; @@ -412,9 +425,9 @@ out: #define FDT_MAX_SIZE (1<<20) -int libxl__arch_domain_configure(libxl__gc *gc, - libxl_domain_build_info *info, - struct xc_dom_image *dom) +int libxl__arch_domain_init_hw_description(libxl__gc *gc, + libxl_domain_build_info *info, + struct xc_dom_image *dom) { void *fdt = NULL; int rc, res; @@ -475,7 +488,7 @@ next_resize: FDT( fdt_begin_node(fdt, "") ); FDT( make_root_properties(gc, vers, fdt) ); - FDT( make_chosen_node(gc, fdt, info) ); + FDT( make_chosen_node(gc, fdt, !!dom->ramdisk_blob, info) ); FDT( make_cpus_node(gc, fdt, info->max_vcpus, ainfo) ); FDT( make_psci_node(gc, fdt) ); @@ -505,10 +518,49 @@ next_resize: goto out; } - debug_dump_fdt(gc, fdt); - rc = 0; out: return rc; } + +int libxl__arch_domain_finalise_hw_description(libxl__gc *gc, + libxl_domain_build_info *info, + struct xc_dom_image *dom) +{ + void *fdt = dom->devicetree_blob; + + const struct xc_dom_seg *ramdisk = dom->ramdisk_blob ? + &dom->ramdisk_seg : NULL; + + if (ramdisk) { + int chosen, res; + uint64_t val; + + /* Neither the fdt_path_offset() nor either of the + * fdt_setprop_inplace() calls can fail. If they do then + * make_chosen_node() (see above) has got something very + * wrong. + */ + chosen = fdt_path_offset(fdt, "/chosen"); + assert(chosen > 0); + + LOG(DEBUG, "/chosen updating initrd properties to cover " + "%"PRIx64"-%"PRIx64, + ramdisk->vstart, ramdisk->vend); + + val = cpu_to_fdt64(ramdisk->vstart); + res = fdt_setprop_inplace(fdt, chosen, PROP_INITRD_START, + &val, sizeof(val)); + assert(!res); + + val = cpu_to_fdt64(ramdisk->vend); + res = fdt_setprop_inplace(fdt, chosen,PROP_INITRD_END, + &val, sizeof(val)); + assert(!res); + } + + debug_dump_fdt(gc, fdt); + + return 0; +} diff --git a/tools/libxl/libxl_dom.c b/tools/libxl/libxl_dom.c index 3351c09abd..661999c4e0 100644 --- a/tools/libxl/libxl_dom.c +++ b/tools/libxl/libxl_dom.c @@ -436,8 +436,8 @@ int libxl__build_pv(libxl__gc *gc, uint32_t domid, LOGE(ERROR, "xc_dom_parse_image failed"); goto out; } - if ( (ret = libxl__arch_domain_configure(gc, info, dom)) != 0 ) { - LOGE(ERROR, "libxl__arch_domain_configure failed"); + if ( (ret = libxl__arch_domain_init_hw_description(gc, info, dom)) != 0 ) { + LOGE(ERROR, "libxl__arch_domain_init_hw_description failed"); goto out; } if ( (ret = xc_dom_mem_init(dom, info->target_memkb / 1024)) != 0 ) { @@ -448,6 +448,10 @@ int libxl__build_pv(libxl__gc *gc, uint32_t domid, LOGE(ERROR, "xc_dom_boot_mem_init failed"); goto out; } + if ( (ret = libxl__arch_domain_finalise_hw_description(gc, info, dom)) != 0 ) { + LOGE(ERROR, "libxl__arch_domain_finalise_hw_description failed"); + goto out; + } if ( (ret = xc_dom_build_image(dom)) != 0 ) { LOGE(ERROR, "xc_dom_build_image failed"); goto out; diff --git a/tools/libxl/libxl_x86.c b/tools/libxl/libxl_x86.c index b11d0364df..75890604d7 100644 --- a/tools/libxl/libxl_x86.c +++ b/tools/libxl/libxl_x86.c @@ -311,9 +311,16 @@ int libxl__arch_domain_create(libxl__gc *gc, libxl_domain_config *d_config, return ret; } -int libxl__arch_domain_configure(libxl__gc *gc, - libxl_domain_build_info *info, - struct xc_dom_image *dom) +int libxl__arch_domain_init_hw_description(libxl__gc *gc, + libxl_domain_build_info *info, + struct xc_dom_image *dom) +{ + return 0; +} + +int libxl__arch_domain_finalise_hw_description(libxl__gc *gc, + libxl_domain_build_info *info, + struct xc_dom_image *dom) { return 0; }