/* 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;
{
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 )
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);
-
- /* 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;
-
- dom->devicetree_seg.vend =
- dom->devicetree_seg.vstart + dom->devicetree_size;
+ dom->ramdisk_seg.vstart = modbase;
+ dom->ramdisk_seg.vend = modbase + ramdisk_size;
+
+ 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;
+
DOMPRINTF("%s: devicetree: 0x%" PRIx64 " -> 0x%" PRIx64 "",
__FUNCTION__,
dom->devicetree_seg.vstart, dom->devicetree_seg.vend);
+
+ modbase += dtb_size;
}
return 0;
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);
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
#include "libxl_arch.h"
#include <xc_dom.h>
+#include <stdbool.h>
#include <libfdt.h>
#include <assert.h>
#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;
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;
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;
#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;
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) );
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;
+}
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 ) {
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;
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;
}