|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [PATCH v4 8/8] xen/common: dom0less: introduce common dom0less-build.c
On Mon, 5 May 2025, Oleksii Kurochko wrote:
> Part of Arm's dom0less-build.c could be common between architectures which are
> using device tree files to create guest domains. Thereby move some parts of
> Arm's dom0less-build.c to common code with minor changes.
>
> As a part of theses changes the following changes are introduced:
> - Introduce make_arch_nodes() to cover arch-specific nodes. For example, in
> case of Arm, it is PSCI and vpl011 nodes.
> - Introduce set_domain_type() to abstract a way how setting of domain type
> happens. For example, RISC-V won't have this member of arch_domain structure
> as vCPUs will always have the same bitness as hypervisor. In case of Arm, it
> is possible that Arm64 could create 32-bit and 64-bit domains.
> - Introduce init_vuart() to cover details of virtual uart initialization.
> - Introduce init_intc_phandle() to cover some details of interrupt controller
> phandle initialization. As an example, RISC-V could have different name for
> interrupt controller node ( APLIC, PLIC, IMSIC, etc ) but the code in
> domain_handle_dtb_bootmodule() could handle only one interrupt controller
> node name.
> - s/make_gic_domU_node/make_intc_domU_node as GIC is Arm specific naming and
> add prototype of make_intc_domU_node() to dom0less-build.h
>
> The following functions are moved to xen/common/device-tree:
> - Functions which are moved as is:
> - domain_p2m_pages().
> - handle_passthrough_prop().
> - handle_prop_pfdt().
> - scan_pfdt_node().
> - check_partial_fdt().
> - Functions which are moved with some minor changes:
> - alloc_xenstore_evtchn():
> - ifdef-ing by CONFIG_HVM accesses to hvm.params.
> - prepare_dtb_domU():
> - ifdef-ing access to gnttab_{start,size} by CONFIG_GRANT_TABLE.
> - s/make_gic_domU_node/make_intc_domU_node.
> - Add call of make_arch_nodes().
> - domain_handle_dtb_bootmodule():
> - hide details of interrupt controller phandle initialization by calling
> init_intc_phandle().
> - Update the comment above init_intc_phandle(): s/gic/interrupt controller.
> - construct_domU():
> - ifdef-ing by CONFIG_HVM accesses to hvm.params.
> - Call init_vuart() to hide Arm's vpl011_init() details there.
> - Add call of set_domain_type() instead of setting kinfo->arch.type
> explicitly.
>
> Some parts of dom0less-build.c are wraped by #ifdef
> CONFIG_STATIC_{SHMEM,MEMORY}
> as not all archs support these configs.
>
> Signed-off-by: Oleksii Kurochko <oleksii.kurochko@xxxxxxxxx>
> ---
> Changes in v4:
> - Add a chunk of code, which was introduced in the patch:
> "xen/arm: dom0less hwdom construction", in moved to common
> construct_domU(). The part which re-uses construct_hwdom().
> - Use __has_include() instead of #ifdef-ing for inclusion of
> asm/static-{memory, shmem}.h in the common code.
> ---
> Change in v3:
> - Align construct_domU() with the current staging:
> - Align alloc_xenstore_params() with the current staging.
> - Move defintion of XENSTORE_PFN_LATE_ALLOC to common and
> declaration of need_xenstore to common.
> ---
> Change in v2:
> - Wrap by #ifdef CONFIG_STATIC_* inclusions of <asm/static-memory.h> and
> <asm/static-shmem.h>. Wrap also the code which uses something from the
> mentioned headers.
> - Add handling of legacy case in construct_domU().
> - Use xen/fdt-kernel.h and xen/fdt-domain-build.h instead of asm/*.
> - Update the commit message.
> ---
> xen/arch/arm/dom0less-build.c | 714 ++---------------------
> xen/common/device-tree/dom0less-build.c | 708 ++++++++++++++++++++++
> xen/include/asm-generic/dom0less-build.h | 18 +-
> 3 files changed, 760 insertions(+), 680 deletions(-)
>
> diff --git a/xen/arch/arm/dom0less-build.c b/xen/arch/arm/dom0less-build.c
> index 47eb38b9ad..ebb1c58f0e 100644
> --- a/xen/arch/arm/dom0less-build.c
> +++ b/xen/arch/arm/dom0less-build.c
> @@ -25,8 +25,6 @@
> #include <asm/static-memory.h>
> #include <asm/static-shmem.h>
>
> -bool __initdata need_xenstore;
> -
> #ifdef CONFIG_VGICV2
> static int __init make_gicv2_domU_node(struct kernel_info *kinfo)
> {
> @@ -152,7 +150,7 @@ static int __init make_gicv3_domU_node(struct kernel_info
> *kinfo)
> }
> #endif
>
> -static int __init make_gic_domU_node(struct kernel_info *kinfo)
> +int __init make_intc_domU_node(struct kernel_info *kinfo)
> {
> switch ( kinfo->d->arch.vgic.version )
> {
> @@ -218,708 +216,60 @@ static int __init make_vpl011_uart_node(struct
> kernel_info *kinfo)
> }
> #endif
>
> -/*
> - * Scan device tree properties for passthrough specific information.
> - * Returns < 0 on error
> - * 0 on success
> - */
> -static int __init handle_passthrough_prop(struct kernel_info *kinfo,
> - const struct fdt_property *xen_reg,
> - const struct fdt_property
> *xen_path,
> - bool xen_force,
> - uint32_t address_cells,
> - uint32_t size_cells)
> -{
> - const __be32 *cell;
> - unsigned int i, len;
> - struct dt_device_node *node;
> - int res;
> - paddr_t mstart, size, gstart;
> -
> - /* xen,reg specifies where to map the MMIO region */
> - cell = (const __be32 *)xen_reg->data;
> - len = fdt32_to_cpu(xen_reg->len) / ((address_cells * 2 + size_cells) *
> - sizeof(uint32_t));
> -
> - for ( i = 0; i < len; i++ )
> - {
> - device_tree_get_reg(&cell, address_cells, size_cells,
> - &mstart, &size);
> - gstart = dt_next_cell(address_cells, &cell);
> -
> - if ( gstart & ~PAGE_MASK || mstart & ~PAGE_MASK || size & ~PAGE_MASK
> )
> - {
> - printk(XENLOG_ERR
> - "DomU passthrough config has not page aligned
> addresses/sizes\n");
> - return -EINVAL;
> - }
> -
> - res = iomem_permit_access(kinfo->d, paddr_to_pfn(mstart),
> - paddr_to_pfn(PAGE_ALIGN(mstart + size -
> 1)));
> - if ( res )
> - {
> - printk(XENLOG_ERR "Unable to permit to dom%d access to"
> - " 0x%"PRIpaddr" - 0x%"PRIpaddr"\n",
> - kinfo->d->domain_id,
> - mstart & PAGE_MASK, PAGE_ALIGN(mstart + size) - 1);
> - return res;
> - }
> -
> - res = map_regions_p2mt(kinfo->d,
> - gaddr_to_gfn(gstart),
> - PFN_DOWN(size),
> - maddr_to_mfn(mstart),
> - p2m_mmio_direct_dev);
> - if ( res < 0 )
> - {
> - printk(XENLOG_ERR
> - "Failed to map %"PRIpaddr" to the guest at%"PRIpaddr"\n",
> - mstart, gstart);
> - return -EFAULT;
> - }
> - }
> -
> - /*
> - * If xen_force, we let the user assign a MMIO region with no
> - * associated path.
> - */
> - if ( xen_path == NULL )
> - return xen_force ? 0 : -EINVAL;
> -
> - /*
> - * xen,path specifies the corresponding node in the host DT.
> - * Both interrupt mappings and IOMMU settings are based on it,
> - * as they are done based on the corresponding host DT node.
> - */
> - node = dt_find_node_by_path(xen_path->data);
> - if ( node == NULL )
> - {
> - printk(XENLOG_ERR "Couldn't find node %s in host_dt!\n",
> - xen_path->data);
> - return -EINVAL;
> - }
> -
> - res = map_device_irqs_to_domain(kinfo->d, node, true, NULL);
> - if ( res < 0 )
> - return res;
> -
> - res = iommu_add_dt_device(node);
> - if ( res < 0 )
> - return res;
> -
> - /* If xen_force, we allow assignment of devices without IOMMU
> protection. */
> - if ( xen_force && !dt_device_is_protected(node) )
> - return 0;
> -
> - return iommu_assign_dt_device(kinfo->d, node);
> -}
> -
> -static int __init handle_prop_pfdt(struct kernel_info *kinfo,
> - const void *pfdt, int nodeoff,
> - uint32_t address_cells, uint32_t
> size_cells,
> - bool scan_passthrough_prop)
> -{
> - void *fdt = kinfo->fdt;
> - int propoff, nameoff, res;
> - const struct fdt_property *prop, *xen_reg = NULL, *xen_path = NULL;
> - const char *name;
> - bool found, xen_force = false;
> -
> - for ( propoff = fdt_first_property_offset(pfdt, nodeoff);
> - propoff >= 0;
> - propoff = fdt_next_property_offset(pfdt, propoff) )
> - {
> - if ( !(prop = fdt_get_property_by_offset(pfdt, propoff, NULL)) )
> - return -FDT_ERR_INTERNAL;
> -
> - found = false;
> - nameoff = fdt32_to_cpu(prop->nameoff);
> - name = fdt_string(pfdt, nameoff);
> -
> - if ( scan_passthrough_prop )
> - {
> - if ( dt_prop_cmp("xen,reg", name) == 0 )
> - {
> - xen_reg = prop;
> - found = true;
> - }
> - else if ( dt_prop_cmp("xen,path", name) == 0 )
> - {
> - xen_path = prop;
> - found = true;
> - }
> - else if ( dt_prop_cmp("xen,force-assign-without-iommu",
> - name) == 0 )
> - {
> - xen_force = true;
> - found = true;
> - }
> - }
> -
> - /*
> - * Copy properties other than the ones above: xen,reg, xen,path,
> - * and xen,force-assign-without-iommu.
> - */
> - if ( !found )
> - {
> - res = fdt_property(fdt, name, prop->data,
> fdt32_to_cpu(prop->len));
> - if ( res )
> - return res;
> - }
> - }
> -
> - /*
> - * Only handle passthrough properties if both xen,reg and xen,path
> - * are present, or if xen,force-assign-without-iommu is specified.
> - */
> - if ( xen_reg != NULL && (xen_path != NULL || xen_force) )
> - {
> - res = handle_passthrough_prop(kinfo, xen_reg, xen_path, xen_force,
> - address_cells, size_cells);
> - if ( res < 0 )
> - {
> - printk(XENLOG_ERR "Failed to assign device to %pd\n", kinfo->d);
> - return res;
> - }
> - }
> - else if ( (xen_path && !xen_reg) || (xen_reg && !xen_path && !xen_force)
> )
> - {
> - printk(XENLOG_ERR "xen,reg or xen,path missing for %pd\n",
> - kinfo->d);
> - return -EINVAL;
> - }
> -
> - /* FDT_ERR_NOTFOUND => There is no more properties for this node */
> - return ( propoff != -FDT_ERR_NOTFOUND ) ? propoff : 0;
> -}
> -
> -static int __init scan_pfdt_node(struct kernel_info *kinfo, const void *pfdt,
> - int nodeoff,
> - uint32_t address_cells, uint32_t size_cells,
> - bool scan_passthrough_prop)
> -{
> - int rc = 0;
> - void *fdt = kinfo->fdt;
> - int node_next;
> -
> - rc = fdt_begin_node(fdt, fdt_get_name(pfdt, nodeoff, NULL));
> - if ( rc )
> - return rc;
> -
> - rc = handle_prop_pfdt(kinfo, pfdt, nodeoff, address_cells, size_cells,
> - scan_passthrough_prop);
> - if ( rc )
> - return rc;
> -
> - address_cells = device_tree_get_u32(pfdt, nodeoff, "#address-cells",
> - DT_ROOT_NODE_ADDR_CELLS_DEFAULT);
> - size_cells = device_tree_get_u32(pfdt, nodeoff, "#size-cells",
> - DT_ROOT_NODE_SIZE_CELLS_DEFAULT);
> -
> - node_next = fdt_first_subnode(pfdt, nodeoff);
> - while ( node_next > 0 )
> - {
> - rc = scan_pfdt_node(kinfo, pfdt, node_next, address_cells,
> size_cells,
> - scan_passthrough_prop);
> - if ( rc )
> - return rc;
> -
> - node_next = fdt_next_subnode(pfdt, node_next);
> - }
> -
> - return fdt_end_node(fdt);
> -}
> -
> -static int __init check_partial_fdt(void *pfdt, size_t size)
> +int __init make_arch_nodes(struct kernel_info *kinfo)
> {
> - int res;
> -
> - if ( fdt_magic(pfdt) != FDT_MAGIC )
> - {
> - dprintk(XENLOG_ERR, "Partial FDT is not a valid Flat Device Tree");
> - return -EINVAL;
> - }
> -
> - res = fdt_check_header(pfdt);
> - if ( res )
> - {
> - dprintk(XENLOG_ERR, "Failed to check the partial FDT (%d)", res);
> - return -EINVAL;
> - }
> -
> - if ( fdt_totalsize(pfdt) > size )
> - {
> - dprintk(XENLOG_ERR, "Partial FDT totalsize is too big");
> - return -EINVAL;
> - }
> -
> - return 0;
> -}
> -
> -static int __init domain_handle_dtb_bootmodule(struct domain *d,
> - struct kernel_info *kinfo)
> -{
> - void *pfdt;
> - int res, node_next;
> -
> - pfdt = ioremap_cache(kinfo->dtb_bootmodule->start,
> - kinfo->dtb_bootmodule->size);
> - if ( pfdt == NULL )
> - return -EFAULT;
> -
> - res = check_partial_fdt(pfdt, kinfo->dtb_bootmodule->size);
> - if ( res < 0 )
> - goto out;
> -
> - for ( node_next = fdt_first_subnode(pfdt, 0);
> - node_next > 0;
> - node_next = fdt_next_subnode(pfdt, node_next) )
> - {
> - const char *name = fdt_get_name(pfdt, node_next, NULL);
> -
> - if ( name == NULL )
> - continue;
> -
> - /*
> - * Only scan /gic /aliases /passthrough, ignore the rest.
> - * They don't have to be parsed in order.
> - *
> - * Take the GIC phandle value from the special /gic node in the
> - * DTB fragment.
> - */
> - if ( dt_node_cmp(name, "gic") == 0 )
> - {
> - uint32_t phandle_intc = fdt_get_phandle(pfdt, node_next);
> -
> - if ( phandle_intc != 0 )
> - kinfo->phandle_intc = phandle_intc;
> - continue;
> - }
> -
> - if ( dt_node_cmp(name, "aliases") == 0 )
> - {
> - res = scan_pfdt_node(kinfo, pfdt, node_next,
> - DT_ROOT_NODE_ADDR_CELLS_DEFAULT,
> - DT_ROOT_NODE_SIZE_CELLS_DEFAULT,
> - false);
> - if ( res )
> - goto out;
> - continue;
> - }
> - if ( dt_node_cmp(name, "passthrough") == 0 )
> - {
> - res = scan_pfdt_node(kinfo, pfdt, node_next,
> - DT_ROOT_NODE_ADDR_CELLS_DEFAULT,
> - DT_ROOT_NODE_SIZE_CELLS_DEFAULT,
> - true);
> - if ( res )
> - goto out;
> - continue;
> - }
> - }
> -
> - out:
> - iounmap(pfdt);
> -
> - return res;
> -}
> -
> -/*
> - * The max size for DT is 2MB. However, the generated DT is small (not
> including
> - * domU passthrough DT nodes whose size we account separately), 4KB are
> enough
> - * for now, but we might have to increase it in the future.
> - */
> -#define DOMU_DTB_SIZE 4096
> -static int __init prepare_dtb_domU(struct domain *d, struct kernel_info
> *kinfo)
> -{
> - int addrcells, sizecells;
> - int ret, fdt_size = DOMU_DTB_SIZE;
> -
> - kinfo->phandle_intc = GUEST_PHANDLE_GIC;
> - kinfo->gnttab_start = GUEST_GNTTAB_BASE;
> - kinfo->gnttab_size = GUEST_GNTTAB_SIZE;
> -
> - addrcells = GUEST_ROOT_ADDRESS_CELLS;
> - sizecells = GUEST_ROOT_SIZE_CELLS;
> -
> - /* Account for domU passthrough DT size */
> - if ( kinfo->dtb_bootmodule )
> - fdt_size += kinfo->dtb_bootmodule->size;
> -
> - /* Cap to max DT size if needed */
> - fdt_size = min(fdt_size, SZ_2M);
> -
> - kinfo->fdt = xmalloc_bytes(fdt_size);
> - if ( kinfo->fdt == NULL )
> - return -ENOMEM;
> -
> - ret = fdt_create(kinfo->fdt, fdt_size);
> - if ( ret < 0 )
> - goto err;
> -
> - ret = fdt_finish_reservemap(kinfo->fdt);
> - if ( ret < 0 )
> - goto err;
> -
> - ret = fdt_begin_node(kinfo->fdt, "");
> - if ( ret < 0 )
> - goto err;
> -
> - ret = fdt_property_cell(kinfo->fdt, "#address-cells", addrcells);
> - if ( ret )
> - goto err;
> -
> - ret = fdt_property_cell(kinfo->fdt, "#size-cells", sizecells);
> - if ( ret )
> - goto err;
> -
> - ret = make_chosen_node(kinfo);
> - if ( ret )
> - goto err;
> + int ret;
>
> ret = make_psci_node(kinfo->fdt);
> if ( ret )
> - goto err;
> -
> - ret = make_cpus_node(d, kinfo->fdt);
> - if ( ret )
> - goto err;
> -
> - ret = make_memory_node(kinfo, addrcells, sizecells,
> - kernel_info_get_mem(kinfo));
> - if ( ret )
> - goto err;
> -
> - ret = make_resv_memory_node(kinfo, addrcells, sizecells);
> - if ( ret )
> - goto err;
> -
> - /*
> - * domain_handle_dtb_bootmodule has to be called before the rest of
> - * the device tree is generated because it depends on the value of
> - * the field phandle_intc.
> - */
> - if ( kinfo->dtb_bootmodule )
> - {
> - ret = domain_handle_dtb_bootmodule(d, kinfo);
> - if ( ret )
> - goto err;
> - }
> -
> - ret = make_gic_domU_node(kinfo);
> - if ( ret )
> - goto err;
> -
> - ret = make_timer_node(kinfo);
> - if ( ret )
> - goto err;
> + return -EINVAL;
>
> if ( kinfo->arch.vpl011 )
> {
> - ret = -EINVAL;
> #ifdef CONFIG_SBSA_VUART_CONSOLE
> ret = make_vpl011_uart_node(kinfo);
> #endif
> if ( ret )
> - goto err;
> - }
> -
> - if ( kinfo->dom0less_feature & DOM0LESS_ENHANCED_NO_XS )
> - {
> - ret = make_hypervisor_node(d, kinfo, addrcells, sizecells);
> - if ( ret )
> - goto err;
> + return -EINVAL;
> }
>
> - ret = fdt_end_node(kinfo->fdt);
> - if ( ret < 0 )
> - goto err;
> -
> - ret = fdt_finish(kinfo->fdt);
> - if ( ret < 0 )
> - goto err;
> -
> return 0;
> -
> - err:
> - printk("Device tree generation failed (%d).\n", ret);
> - xfree(kinfo->fdt);
> -
> - return -EINVAL;
> }
>
> -#define XENSTORE_PFN_OFFSET 1
> -static int __init alloc_xenstore_page(struct domain *d)
> +/* TODO: make arch.type generic ? */
> +#ifdef CONFIG_ARM_64
> +void __init set_domain_type(struct domain *d, struct kernel_info *kinfo)
> {
> - struct page_info *xenstore_pg;
> - struct xenstore_domain_interface *interface;
> - mfn_t mfn;
> - gfn_t gfn;
> - int rc;
> -
> - if ( (UINT_MAX - d->max_pages) < 1 )
> - {
> - printk(XENLOG_ERR "%pd: Over-allocation for d->max_pages by 1
> page.\n",
> - d);
> - return -EINVAL;
> - }
> -
> - d->max_pages += 1;
> - xenstore_pg = alloc_domheap_page(d, MEMF_bits(32));
> - if ( xenstore_pg == NULL && is_64bit_domain(d) )
> - xenstore_pg = alloc_domheap_page(d, 0);
> - if ( xenstore_pg == NULL )
> - return -ENOMEM;
> -
> - mfn = page_to_mfn(xenstore_pg);
> - if ( !mfn_x(mfn) )
> - return -ENOMEM;
> -
> - if ( !is_domain_direct_mapped(d) )
> - gfn = gaddr_to_gfn(GUEST_MAGIC_BASE +
> - (XENSTORE_PFN_OFFSET << PAGE_SHIFT));
> - else
> - gfn = gaddr_to_gfn(mfn_to_maddr(mfn));
> -
> - rc = guest_physmap_add_page(d, gfn, mfn, 0);
> - if ( rc )
> - {
> - free_domheap_page(xenstore_pg);
> - return rc;
> - }
> -
> - d->arch.hvm.params[HVM_PARAM_STORE_PFN] = gfn_x(gfn);
> - interface = map_domain_page(mfn);
> - interface->connection = XENSTORE_RECONNECT;
> - unmap_domain_page(interface);
> -
> - return 0;
> + /* type must be set before allocate memory */
> + d->arch.type = kinfo->arch.type;
> }
> -
> -static int __init alloc_xenstore_params(struct kernel_info *kinfo)
> +#else
> +void __init set_domain_type(struct domain *d, struct kernel_info *kinfo)
> {
> - struct domain *d = kinfo->d;
> - int rc = 0;
> -
> - if ( (kinfo->dom0less_feature & (DOM0LESS_XENSTORE | DOM0LESS_XS_LEGACY))
> - == (DOM0LESS_XENSTORE | DOM0LESS_XS_LEGACY)
> )
> - d->arch.hvm.params[HVM_PARAM_STORE_PFN] = XENSTORE_PFN_LATE_ALLOC;
> - else if ( kinfo->dom0less_feature & DOM0LESS_XENSTORE )
> - {
> - rc = alloc_xenstore_page(d);
> - if ( rc < 0 )
> - return rc;
> - }
> -
> - return rc;
> + /* Nothing to do */
> }
> +#endif
>
> -static void __init domain_vcpu_affinity(struct domain *d,
> - const struct dt_device_node *node)
> +int __init init_vuart(struct domain *d, struct kernel_info *kinfo,
> + const struct dt_device_node *node)
> {
> - struct dt_device_node *np;
> -
> - dt_for_each_child_node(node, np)
> - {
> - const char *hard_affinity_str = NULL;
> - uint32_t val;
> - int rc;
> - struct vcpu *v;
> - cpumask_t affinity;
> -
> - if ( !dt_device_is_compatible(np, "xen,vcpu") )
> - continue;
> -
> - if ( !dt_property_read_u32(np, "id", &val) )
> - panic("Invalid xen,vcpu node for domain %s\n",
> dt_node_name(node));
> -
> - if ( val >= d->max_vcpus )
> - panic("Invalid vcpu_id %u for domain %s, max_vcpus=%u\n", val,
> - dt_node_name(node), d->max_vcpus);
> -
> - v = d->vcpu[val];
> - rc = dt_property_read_string(np, "hard-affinity",
> &hard_affinity_str);
> - if ( rc < 0 )
> - continue;
> -
> - cpumask_clear(&affinity);
> - while ( *hard_affinity_str != '\0' )
> - {
> - unsigned int start, end;
> -
> - start = simple_strtoul(hard_affinity_str, &hard_affinity_str, 0);
> -
> - if ( *hard_affinity_str == '-' ) /* Range */
> - {
> - hard_affinity_str++;
> - end = simple_strtoul(hard_affinity_str, &hard_affinity_str,
> 0);
> - }
> - else /* Single value */
> - end = start;
> -
> - if ( end >= nr_cpu_ids )
> - panic("Invalid pCPU %u for domain %s\n", end,
> dt_node_name(node));
> -
> - for ( ; start <= end; start++ )
> - cpumask_set_cpu(start, &affinity);
> -
> - if ( *hard_affinity_str == ',' )
> - hard_affinity_str++;
> - else if ( *hard_affinity_str != '\0' )
> - break;
> - }
> + int rc = 0;
>
> - rc = vcpu_set_hard_affinity(v, &affinity);
> - if ( rc )
> - panic("vcpu%d: failed (rc=%d) to set hard affinity for domain
> %s\n",
> - v->vcpu_id, rc, dt_node_name(node));
> - }
> -}
> + kinfo->arch.vpl011 = dt_property_read_bool(node, "vpl011");
>
> -#ifdef CONFIG_ARCH_PAGING_MEMPOOL
> -static unsigned long __init domain_p2m_pages(unsigned long maxmem_kb,
> - unsigned int smp_cpus)
> -{
> /*
> - * Keep in sync with libxl__get_required_paging_memory().
> - * 256 pages (1MB) per vcpu, plus 1 page per MiB of RAM for the P2M map,
> - * plus 128 pages to cover extended regions.
> + * Base address and irq number are needed when creating vpl011 device
> + * tree node in prepare_dtb_domU, so initialization on related variables
> + * shall be done first.
> */
> - unsigned long memkb = 4 * (256 * smp_cpus + (maxmem_kb / 1024) + 128);
> -
> - BUILD_BUG_ON(PAGE_SIZE != SZ_4K);
> -
> - return DIV_ROUND_UP(memkb, 1024) << (20 - PAGE_SHIFT);
> -}
> -
> -static int __init domain_p2m_set_allocation(struct domain *d, uint64_t mem,
> - const struct dt_device_node
> *node)
> -{
> - unsigned long p2m_pages;
> - uint32_t p2m_mem_mb;
> - int rc;
> -
> - rc = dt_property_read_u32(node, "xen,domain-p2m-mem-mb", &p2m_mem_mb);
> - /* If xen,domain-p2m-mem-mb is not specified, use the default value. */
> - p2m_pages = rc ?
> - p2m_mem_mb << (20 - PAGE_SHIFT) :
> - domain_p2m_pages(mem, d->max_vcpus);
> -
> - spin_lock(&d->arch.paging.lock);
> - rc = p2m_set_allocation(d, p2m_pages, NULL);
> - spin_unlock(&d->arch.paging.lock);
> -
> - return rc;
> -}
> -#else /* !CONFIG_ARCH_PAGING_MEMPOOL */
> -static inline int domain_p2m_set_allocation(struct domain *d, uint64_t mem,
> - const struct dt_device_node
> *node)
> -{
> - return 0;
> -}
> -#endif /* CONFIG_ARCH_PAGING_MEMPOOL */
> -
> -int __init construct_domU(struct domain *d,
> - const struct dt_device_node *node)
> -{
> - struct kernel_info kinfo = KERNEL_INFO_INIT;
> - const char *dom0less_enhanced;
> - int rc;
> - u64 mem;
> -
> - rc = dt_property_read_u64(node, "memory", &mem);
> - if ( !rc )
> - {
> - printk("Error building DomU: cannot read \"memory\" property\n");
> - return -EINVAL;
> - }
> - kinfo.unassigned_mem = (paddr_t)mem * SZ_1K;
> -
> - rc = domain_p2m_set_allocation(d, mem, node);
> - if ( rc != 0 )
> - return rc;
> -
> - printk("*** LOADING DOMU cpus=%u memory=%#"PRIx64"KB ***\n",
> - d->max_vcpus, mem);
> -
> - kinfo.arch.vpl011 = dt_property_read_bool(node, "vpl011");
> - if ( kinfo.arch.vpl011 && is_hardware_domain(d) )
> - panic("hardware domain cannot specify vpl011\n");
> -
> - rc = dt_property_read_string(node, "xen,enhanced", &dom0less_enhanced);
> - if ( rc == -EILSEQ ||
> - rc == -ENODATA ||
> - (rc == 0 && !strcmp(dom0less_enhanced, "enabled")) )
> - {
> - need_xenstore = true;
> - kinfo.dom0less_feature = DOM0LESS_ENHANCED;
> - }
> - else if ( rc == 0 && !strcmp(dom0less_enhanced, "legacy") )
> - {
> - need_xenstore = true;
> - kinfo.dom0less_feature = DOM0LESS_ENHANCED_LEGACY;
> - }
> - else if ( rc == 0 && !strcmp(dom0less_enhanced, "no-xenstore") )
> - kinfo.dom0less_feature = DOM0LESS_ENHANCED_NO_XS;
> -
> - if ( vcpu_create(d, 0) == NULL )
> - return -ENOMEM;
> -
> - d->max_pages = ((paddr_t)mem * SZ_1K) >> PAGE_SHIFT;
> -
> - kinfo.d = d;
> -
> - rc = kernel_probe(&kinfo, node);
> - if ( rc < 0 )
> - return rc;
> -
> -#ifdef CONFIG_ARM_64
> - /* type must be set before allocate memory */
> - d->arch.type = kinfo.arch.type;
> -#endif
> - if ( is_hardware_domain(d) )
> - {
> - rc = construct_hwdom(&kinfo, node);
> - if ( rc < 0 )
> - return rc;
> - }
> - else
> + if ( kinfo->arch.vpl011 )
> {
> - if ( !dt_find_property(node, "xen,static-mem", NULL) )
> - allocate_memory(d, &kinfo);
> - else if ( !is_domain_direct_mapped(d) )
> - allocate_static_memory(d, &kinfo, node);
> - else
> - assign_static_memory_11(d, &kinfo, node);
> -
> - rc = process_shm(d, &kinfo, node);
> - if ( rc < 0 )
> - return rc;
> -
> - /*
> - * Base address and irq number are needed when creating vpl011 device
> - * tree node in prepare_dtb_domU, so initialization on related
> variables
> - * shall be done first.
> - */
> - if ( kinfo.arch.vpl011 )
> - {
> - rc = domain_vpl011_init(d, NULL);
> - if ( rc < 0 )
> - return rc;
> - }
> -
> - rc = prepare_dtb_domU(d, &kinfo);
> - if ( rc < 0 )
> - return rc;
> -
> - rc = construct_domain(d, &kinfo);
> + rc = domain_vpl011_init(d, NULL);
> if ( rc < 0 )
> return rc;
> }
>
> - domain_vcpu_affinity(d, node);
> -
> - return alloc_xenstore_params(&kinfo);
> + return rc;
> }
>
> void __init arch_create_domUs(struct dt_device_node *node,
> @@ -995,6 +345,22 @@ void __init arch_create_domUs(struct dt_device_node
> *node,
> }
> }
>
> +int __init init_intc_phandle(struct kernel_info *kinfo, const char *name,
> + const int node_next, const void *pfdt)
> +{
> + if ( dt_node_cmp(name, "gic") == 0 )
> + {
> + uint32_t phandle_intc = fdt_get_phandle(pfdt, node_next);
> +
> + if ( phandle_intc != 0 )
> + kinfo->phandle_intc = phandle_intc;
> +
> + return 0;
> + }
> +
> + return 1;
> +}
> +
> /*
> * Local variables:
> * mode: C
> diff --git a/xen/common/device-tree/dom0less-build.c
> b/xen/common/device-tree/dom0less-build.c
> index 203b762e2c..e1d68cb373 100644
> --- a/xen/common/device-tree/dom0less-build.c
> +++ b/xen/common/device-tree/dom0less-build.c
> @@ -3,24 +3,43 @@
> #include <xen/bootfdt.h>
> #include <xen/device_tree.h>
> #include <xen/domain.h>
> +#include <xen/domain_page.h>
> #include <xen/err.h>
> #include <xen/event.h>
> +#include <xen/fdt-domain-build.h>
> +#include <xen/fdt-kernel.h>
> #include <xen/grant_table.h>
> #include <xen/init.h>
> +#include <xen/iocap.h>
> #include <xen/iommu.h>
> +#include <xen/libfdt/libfdt.h>
> #include <xen/llc-coloring.h>
> +#include <xen/sizes.h>
> #include <xen/sched.h>
> #include <xen/stdbool.h>
> #include <xen/types.h>
> +#include <xen/vmap.h>
>
> #include <public/bootfdt.h>
> #include <public/domctl.h>
> #include <public/event_channel.h>
> +#include <public/io/xs_wire.h>
>
> #include <asm/dom0less-build.h>
> #include <asm/setup.h>
>
> +#if __has_include(<asm/static-memory.h>)
> +# include <asm/static-memory.h>
> +#endif
> +
> +#if __has_include(<asm/static-shmem.h>)
> +#include <asm/static-shmem.h>
NIT: code style. I can fix on commit.
> +#endif
> +
> +#define XENSTORE_PFN_LATE_ALLOC UINT64_MAX
> +
> static domid_t __initdata xs_domid = DOMID_INVALID;
> +static bool __initdata need_xenstore;
>
> void __init set_xs_domain(struct domain *d)
> {
> @@ -109,6 +128,695 @@ static void __init initialize_domU_xenstore(void)
> }
> }
>
> +/*
> + * Scan device tree properties for passthrough specific information.
> + * Returns < 0 on error
> + * 0 on success
> + */
> +static int __init handle_passthrough_prop(struct kernel_info *kinfo,
> + const struct fdt_property *xen_reg,
> + const struct fdt_property
> *xen_path,
> + bool xen_force,
> + uint32_t address_cells,
> + uint32_t size_cells)
> +{
> + const __be32 *cell;
> + unsigned int i, len;
> + struct dt_device_node *node;
> + int res;
> + paddr_t mstart, size, gstart;
> +
> + /* xen,reg specifies where to map the MMIO region */
> + cell = (const __be32 *)xen_reg->data;
> + len = fdt32_to_cpu(xen_reg->len) / ((address_cells * 2 + size_cells) *
> + sizeof(uint32_t));
> +
> + for ( i = 0; i < len; i++ )
> + {
> + device_tree_get_reg(&cell, address_cells, size_cells,
> + &mstart, &size);
> + gstart = dt_next_cell(address_cells, &cell);
> +
> + if ( gstart & ~PAGE_MASK || mstart & ~PAGE_MASK || size & ~PAGE_MASK
> )
> + {
> + printk(XENLOG_ERR
> + "DomU passthrough config has not page aligned
> addresses/sizes\n");
> + return -EINVAL;
> + }
> +
> + res = iomem_permit_access(kinfo->d, paddr_to_pfn(mstart),
> + paddr_to_pfn(PAGE_ALIGN(mstart + size -
> 1)));
> + if ( res )
> + {
> + printk(XENLOG_ERR "Unable to permit to dom%d access to"
> + " 0x%"PRIpaddr" - 0x%"PRIpaddr"\n",
> + kinfo->d->domain_id,
> + mstart & PAGE_MASK, PAGE_ALIGN(mstart + size) - 1);
> + return res;
> + }
> +
> + res = map_regions_p2mt(kinfo->d,
> + gaddr_to_gfn(gstart),
> + PFN_DOWN(size),
> + maddr_to_mfn(mstart),
> + p2m_mmio_direct_dev);
> + if ( res < 0 )
> + {
> + printk(XENLOG_ERR
> + "Failed to map %"PRIpaddr" to the guest at%"PRIpaddr"\n",
> + mstart, gstart);
> + return -EFAULT;
> + }
> + }
> +
> + /*
> + * If xen_force, we let the user assign a MMIO region with no
> + * associated path.
> + */
> + if ( xen_path == NULL )
> + return xen_force ? 0 : -EINVAL;
> +
> + /*
> + * xen,path specifies the corresponding node in the host DT.
> + * Both interrupt mappings and IOMMU settings are based on it,
> + * as they are done based on the corresponding host DT node.
> + */
> + node = dt_find_node_by_path(xen_path->data);
> + if ( node == NULL )
> + {
> + printk(XENLOG_ERR "Couldn't find node %s in host_dt!\n",
> + xen_path->data);
> + return -EINVAL;
> + }
> +
> + res = map_device_irqs_to_domain(kinfo->d, node, true, NULL);
> + if ( res < 0 )
> + return res;
> +
> + res = iommu_add_dt_device(node);
> + if ( res < 0 )
> + return res;
> +
> + /* If xen_force, we allow assignment of devices without IOMMU
> protection. */
> + if ( xen_force && !dt_device_is_protected(node) )
> + return 0;
> +
> + return iommu_assign_dt_device(kinfo->d, node);
> +}
> +
> +static int __init handle_prop_pfdt(struct kernel_info *kinfo,
> + const void *pfdt, int nodeoff,
> + uint32_t address_cells, uint32_t
> size_cells,
> + bool scan_passthrough_prop)
> +{
> + void *fdt = kinfo->fdt;
> + int propoff, nameoff, res;
> + const struct fdt_property *prop, *xen_reg = NULL, *xen_path = NULL;
> + const char *name;
> + bool found, xen_force = false;
> +
> + for ( propoff = fdt_first_property_offset(pfdt, nodeoff);
> + propoff >= 0;
> + propoff = fdt_next_property_offset(pfdt, propoff) )
> + {
> + if ( !(prop = fdt_get_property_by_offset(pfdt, propoff, NULL)) )
> + return -FDT_ERR_INTERNAL;
> +
> + found = false;
> + nameoff = fdt32_to_cpu(prop->nameoff);
> + name = fdt_string(pfdt, nameoff);
> +
> + if ( scan_passthrough_prop )
> + {
> + if ( dt_prop_cmp("xen,reg", name) == 0 )
> + {
> + xen_reg = prop;
> + found = true;
> + }
> + else if ( dt_prop_cmp("xen,path", name) == 0 )
> + {
> + xen_path = prop;
> + found = true;
> + }
> + else if ( dt_prop_cmp("xen,force-assign-without-iommu",
> + name) == 0 )
> + {
> + xen_force = true;
> + found = true;
> + }
> + }
> +
> + /*
> + * Copy properties other than the ones above: xen,reg, xen,path,
> + * and xen,force-assign-without-iommu.
> + */
> + if ( !found )
> + {
> + res = fdt_property(fdt, name, prop->data,
> fdt32_to_cpu(prop->len));
> + if ( res )
> + return res;
> + }
> + }
> +
> + /*
> + * Only handle passthrough properties if both xen,reg and xen,path
> + * are present, or if xen,force-assign-without-iommu is specified.
> + */
> + if ( xen_reg != NULL && (xen_path != NULL || xen_force) )
> + {
> + res = handle_passthrough_prop(kinfo, xen_reg, xen_path, xen_force,
> + address_cells, size_cells);
> + if ( res < 0 )
> + {
> + printk(XENLOG_ERR "Failed to assign device to %pd\n", kinfo->d);
> + return res;
> + }
> + }
> + else if ( (xen_path && !xen_reg) || (xen_reg && !xen_path && !xen_force)
> )
> + {
> + printk(XENLOG_ERR "xen,reg or xen,path missing for %pd\n",
> + kinfo->d);
> + return -EINVAL;
> + }
> +
> + /* FDT_ERR_NOTFOUND => There is no more properties for this node */
> + return ( propoff != -FDT_ERR_NOTFOUND ) ? propoff : 0;
> +}
> +
> +static int __init scan_pfdt_node(struct kernel_info *kinfo, const void *pfdt,
> + int nodeoff,
> + uint32_t address_cells, uint32_t size_cells,
> + bool scan_passthrough_prop)
> +{
> + int rc = 0;
> + void *fdt = kinfo->fdt;
> + int node_next;
> +
> + rc = fdt_begin_node(fdt, fdt_get_name(pfdt, nodeoff, NULL));
> + if ( rc )
> + return rc;
> +
> + rc = handle_prop_pfdt(kinfo, pfdt, nodeoff, address_cells, size_cells,
> + scan_passthrough_prop);
> + if ( rc )
> + return rc;
> +
> + address_cells = device_tree_get_u32(pfdt, nodeoff, "#address-cells",
> + DT_ROOT_NODE_ADDR_CELLS_DEFAULT);
> + size_cells = device_tree_get_u32(pfdt, nodeoff, "#size-cells",
> + DT_ROOT_NODE_SIZE_CELLS_DEFAULT);
> +
> + node_next = fdt_first_subnode(pfdt, nodeoff);
> + while ( node_next > 0 )
> + {
> + rc = scan_pfdt_node(kinfo, pfdt, node_next, address_cells,
> size_cells,
> + scan_passthrough_prop);
> + if ( rc )
> + return rc;
> +
> + node_next = fdt_next_subnode(pfdt, node_next);
> + }
> +
> + return fdt_end_node(fdt);
> +}
> +
> +static int __init check_partial_fdt(void *pfdt, size_t size)
> +{
> + int res;
> +
> + if ( fdt_magic(pfdt) != FDT_MAGIC )
> + {
> + dprintk(XENLOG_ERR, "Partial FDT is not a valid Flat Device Tree");
> + return -EINVAL;
> + }
> +
> + res = fdt_check_header(pfdt);
> + if ( res )
> + {
> + dprintk(XENLOG_ERR, "Failed to check the partial FDT (%d)", res);
> + return -EINVAL;
> + }
> +
> + if ( fdt_totalsize(pfdt) > size )
> + {
> + dprintk(XENLOG_ERR, "Partial FDT totalsize is too big");
> + return -EINVAL;
> + }
> +
> + return 0;
> +}
> +
> +static int __init domain_handle_dtb_bootmodule(struct domain *d,
> + struct kernel_info *kinfo)
> +{
> + void *pfdt;
> + int res, node_next;
> +
> + pfdt = ioremap_cache(kinfo->dtb_bootmodule->start,
> + kinfo->dtb_bootmodule->size);
> + if ( pfdt == NULL )
> + return -EFAULT;
> +
> + res = check_partial_fdt(pfdt, kinfo->dtb_bootmodule->size);
> + if ( res < 0 )
> + goto out;
> +
> + for ( node_next = fdt_first_subnode(pfdt, 0);
> + node_next > 0;
> + node_next = fdt_next_subnode(pfdt, node_next) )
> + {
> + const char *name = fdt_get_name(pfdt, node_next, NULL);
> +
> + if ( name == NULL )
> + continue;
> +
> + /*
> + * Only scan /$(interrupt_controller) /aliases /passthrough,
> + * ignore the rest.
> + * They don't have to be parsed in order.
> + *
> + * Take the interrupt controller phandle value from the special
> + * interrupt controller node in the DTB fragment.
> + */
> + if ( init_intc_phandle(kinfo, name, node_next, pfdt) == 0 )
> + continue;
> +
> + if ( dt_node_cmp(name, "aliases") == 0 )
> + {
> + res = scan_pfdt_node(kinfo, pfdt, node_next,
> + DT_ROOT_NODE_ADDR_CELLS_DEFAULT,
> + DT_ROOT_NODE_SIZE_CELLS_DEFAULT,
> + false);
> + if ( res )
> + goto out;
> + continue;
> + }
> + if ( dt_node_cmp(name, "passthrough") == 0 )
> + {
> + res = scan_pfdt_node(kinfo, pfdt, node_next,
> + DT_ROOT_NODE_ADDR_CELLS_DEFAULT,
> + DT_ROOT_NODE_SIZE_CELLS_DEFAULT,
> + true);
> + if ( res )
> + goto out;
> + continue;
> + }
> + }
> +
> + out:
> + iounmap(pfdt);
> +
> + return res;
> +}
> +
> +/*
> + * The max size for DT is 2MB. However, the generated DT is small (not
> including
> + * domU passthrough DT nodes whose size we account separately), 4KB are
> enough
> + * for now, but we might have to increase it in the future.
> + */
> +#define DOMU_DTB_SIZE 4096
> +static int __init prepare_dtb_domU(struct domain *d, struct kernel_info
> *kinfo)
> +{
> + int addrcells, sizecells;
> + int ret, fdt_size = DOMU_DTB_SIZE;
> +
> + kinfo->phandle_intc = GUEST_PHANDLE_GIC;
> +
> +#ifdef CONFIG_GRANT_TABLE
> + kinfo->gnttab_start = GUEST_GNTTAB_BASE;
> + kinfo->gnttab_size = GUEST_GNTTAB_SIZE;
> +#endif
> +
> + addrcells = GUEST_ROOT_ADDRESS_CELLS;
> + sizecells = GUEST_ROOT_SIZE_CELLS;
> +
> + /* Account for domU passthrough DT size */
> + if ( kinfo->dtb_bootmodule )
> + fdt_size += kinfo->dtb_bootmodule->size;
> +
> + /* Cap to max DT size if needed */
> + fdt_size = min(fdt_size, SZ_2M);
> +
> + kinfo->fdt = xmalloc_bytes(fdt_size);
> + if ( kinfo->fdt == NULL )
> + return -ENOMEM;
> +
> + ret = fdt_create(kinfo->fdt, fdt_size);
> + if ( ret < 0 )
> + goto err;
> +
> + ret = fdt_finish_reservemap(kinfo->fdt);
> + if ( ret < 0 )
> + goto err;
> +
> + ret = fdt_begin_node(kinfo->fdt, "");
> + if ( ret < 0 )
> + goto err;
> +
> + ret = fdt_property_cell(kinfo->fdt, "#address-cells", addrcells);
> + if ( ret )
> + goto err;
> +
> + ret = fdt_property_cell(kinfo->fdt, "#size-cells", sizecells);
> + if ( ret )
> + goto err;
> +
> + ret = make_chosen_node(kinfo);
> + if ( ret )
> + goto err;
> +
> + ret = make_cpus_node(d, kinfo->fdt);
> + if ( ret )
> + goto err;
> +
> + ret = make_memory_node(kinfo, addrcells, sizecells,
> + kernel_info_get_mem(kinfo));
> + if ( ret )
> + goto err;
> +
> +#ifdef CONFIG_STATIC_SHM
> + ret = make_resv_memory_node(kinfo, addrcells, sizecells);
> + if ( ret )
> + goto err;
> +#endif
> +
> + /*
> + * domain_handle_dtb_bootmodule has to be called before the rest of
> + * the device tree is generated because it depends on the value of
> + * the field phandle_intc.
> + */
> + if ( kinfo->dtb_bootmodule )
> + {
> + ret = domain_handle_dtb_bootmodule(d, kinfo);
> + if ( ret )
> + goto err;
> + }
> +
> + ret = make_intc_domU_node(kinfo);
> + if ( ret )
> + goto err;
> +
> + ret = make_timer_node(kinfo);
> + if ( ret )
> + goto err;
> +
> + if ( kinfo->dom0less_feature & DOM0LESS_ENHANCED_NO_XS )
> + {
> + ret = make_hypervisor_node(d, kinfo, addrcells, sizecells);
> + if ( ret )
> + goto err;
> + }
> +
> + ret = make_arch_nodes(kinfo);
> + if ( ret )
> + goto err;
> +
> + ret = fdt_end_node(kinfo->fdt);
> + if ( ret < 0 )
> + goto err;
> +
> + ret = fdt_finish(kinfo->fdt);
> + if ( ret < 0 )
> + goto err;
> +
> + return 0;
> +
> + err:
> + printk("Device tree generation failed (%d).\n", ret);
> + xfree(kinfo->fdt);
> +
> + return -EINVAL;
> +}
> +
> +#define XENSTORE_PFN_OFFSET 1
> +static int __init alloc_xenstore_page(struct domain *d)
> +{
> + struct page_info *xenstore_pg;
> + struct xenstore_domain_interface *interface;
> + mfn_t mfn;
> + gfn_t gfn;
> + int rc;
> +
> + if ( (UINT_MAX - d->max_pages) < 1 )
> + {
> + printk(XENLOG_ERR "%pd: Over-allocation for d->max_pages by 1
> page.\n",
> + d);
> + return -EINVAL;
> + }
> +
> + d->max_pages += 1;
> + xenstore_pg = alloc_domheap_page(d, MEMF_bits(32));
> + if ( xenstore_pg == NULL && is_64bit_domain(d) )
> + xenstore_pg = alloc_domheap_page(d, 0);
> + if ( xenstore_pg == NULL )
> + return -ENOMEM;
> +
> + mfn = page_to_mfn(xenstore_pg);
> + if ( !mfn_x(mfn) )
> + return -ENOMEM;
> +
> + if ( !is_domain_direct_mapped(d) )
> + gfn = gaddr_to_gfn(GUEST_MAGIC_BASE +
> + (XENSTORE_PFN_OFFSET << PAGE_SHIFT));
> + else
> + gfn = gaddr_to_gfn(mfn_to_maddr(mfn));
> +
> + rc = guest_physmap_add_page(d, gfn, mfn, 0);
> + if ( rc )
> + {
> + free_domheap_page(xenstore_pg);
> + return rc;
> + }
> +
> +#ifdef CONFIG_HVM
> + d->arch.hvm.params[HVM_PARAM_STORE_PFN] = gfn_x(gfn);
> +#endif
> + interface = map_domain_page(mfn);
> + interface->connection = XENSTORE_RECONNECT;
> + unmap_domain_page(interface);
> +
> + return 0;
> +}
> +
> +static int __init alloc_xenstore_params(struct kernel_info *kinfo)
> +{
> + struct domain *d = kinfo->d;
> + int rc = 0;
> +
> +#ifdef CONFIG_HVM
> + if ( (kinfo->dom0less_feature & (DOM0LESS_XENSTORE | DOM0LESS_XS_LEGACY))
> + == (DOM0LESS_XENSTORE | DOM0LESS_XS_LEGACY)
> )
> + d->arch.hvm.params[HVM_PARAM_STORE_PFN] = XENSTORE_PFN_LATE_ALLOC;
> + else
> +#endif
> + if ( kinfo->dom0less_feature & DOM0LESS_XENSTORE )
> + {
> + rc = alloc_xenstore_page(d);
> + if ( rc < 0 )
> + return rc;
> + }
> +
> + return rc;
> +}
> +
> +static void __init domain_vcpu_affinity(struct domain *d,
> + const struct dt_device_node *node)
> +{
> + struct dt_device_node *np;
> +
> + dt_for_each_child_node(node, np)
> + {
> + const char *hard_affinity_str = NULL;
> + uint32_t val;
> + int rc;
> + struct vcpu *v;
> + cpumask_t affinity;
> +
> + if ( !dt_device_is_compatible(np, "xen,vcpu") )
> + continue;
> +
> + if ( !dt_property_read_u32(np, "id", &val) )
> + panic("Invalid xen,vcpu node for domain %s\n",
> dt_node_name(node));
> +
> + if ( val >= d->max_vcpus )
> + panic("Invalid vcpu_id %u for domain %s, max_vcpus=%u\n", val,
> + dt_node_name(node), d->max_vcpus);
> +
> + v = d->vcpu[val];
> + rc = dt_property_read_string(np, "hard-affinity",
> &hard_affinity_str);
> + if ( rc < 0 )
> + continue;
> +
> + cpumask_clear(&affinity);
> + while ( *hard_affinity_str != '\0' )
> + {
> + unsigned int start, end;
> +
> + start = simple_strtoul(hard_affinity_str, &hard_affinity_str, 0);
> +
> + if ( *hard_affinity_str == '-' ) /* Range */
> + {
> + hard_affinity_str++;
> + end = simple_strtoul(hard_affinity_str, &hard_affinity_str,
> 0);
> + }
> + else /* Single value */
> + end = start;
> +
> + if ( end >= nr_cpu_ids )
> + panic("Invalid pCPU %u for domain %s\n", end,
> dt_node_name(node));
> +
> + for ( ; start <= end; start++ )
> + cpumask_set_cpu(start, &affinity);
> +
> + if ( *hard_affinity_str == ',' )
> + hard_affinity_str++;
> + else if ( *hard_affinity_str != '\0' )
> + break;
> + }
> +
> + rc = vcpu_set_hard_affinity(v, &affinity);
> + if ( rc )
> + panic("vcpu%d: failed (rc=%d) to set hard affinity for domain
> %s\n",
> + v->vcpu_id, rc, dt_node_name(node));
> + }
> +}
> +
> +#ifdef CONFIG_ARCH_PAGING_MEMPOOL
> +static unsigned long __init domain_p2m_pages(unsigned long maxmem_kb,
> + unsigned int smp_cpus)
> +{
> + /*
> + * Keep in sync with libxl__get_required_paging_memory().
> + * 256 pages (1MB) per vcpu, plus 1 page per MiB of RAM for the P2M map,
> + * plus 128 pages to cover extended regions.
> + */
> + unsigned long memkb = 4 * (256 * smp_cpus + (maxmem_kb / 1024) + 128);
> +
> + BUILD_BUG_ON(PAGE_SIZE != SZ_4K);
> +
> + return DIV_ROUND_UP(memkb, 1024) << (20 - PAGE_SHIFT);
> +}
> +
> +static int __init domain_p2m_set_allocation(struct domain *d, uint64_t mem,
> + const struct dt_device_node
> *node)
> +{
> + unsigned long p2m_pages;
> + uint32_t p2m_mem_mb;
> + int rc;
> +
> + rc = dt_property_read_u32(node, "xen,domain-p2m-mem-mb", &p2m_mem_mb);
> + /* If xen,domain-p2m-mem-mb is not specified, use the default value. */
> + p2m_pages = rc ?
> + p2m_mem_mb << (20 - PAGE_SHIFT) :
> + domain_p2m_pages(mem, d->max_vcpus);
> +
> + spin_lock(&d->arch.paging.lock);
> + rc = p2m_set_allocation(d, p2m_pages, NULL);
> + spin_unlock(&d->arch.paging.lock);
> +
> + return rc;
> +}
> +#else /* !CONFIG_ARCH_PAGING_MEMPOOL */
> +static inline int domain_p2m_set_allocation(struct domain *d, uint64_t mem,
> + const struct dt_device_node
> *node)
> +{
> + return 0;
> +}
> +#endif /* CONFIG_ARCH_PAGING_MEMPOOL */
> +
> +static int __init construct_domU(struct domain *d,
> + const struct dt_device_node *node)
> +{
> + struct kernel_info kinfo = KERNEL_INFO_INIT;
> + const char *dom0less_enhanced;
> + int rc;
> + u64 mem;
> +
> + rc = dt_property_read_u64(node, "memory", &mem);
> + if ( !rc )
> + {
> + printk("Error building DomU: cannot read \"memory\" property\n");
> + return -EINVAL;
> + }
> + kinfo.unassigned_mem = (paddr_t)mem * SZ_1K;
> +
> + rc = domain_p2m_set_allocation(d, mem, node);
> + if ( rc != 0 )
> + return rc;
> +
> + printk("*** LOADING DOMU cpus=%u memory=%#"PRIx64"KB ***\n",
> + d->max_vcpus, mem);
> +
> + rc = dt_property_read_string(node, "xen,enhanced", &dom0less_enhanced);
> + if ( rc == -EILSEQ ||
> + rc == -ENODATA ||
> + (rc == 0 && !strcmp(dom0less_enhanced, "enabled")) )
> + {
> + need_xenstore = true;
> + kinfo.dom0less_feature = DOM0LESS_ENHANCED;
> + }
> + else if ( rc == 0 && !strcmp(dom0less_enhanced, "legacy") )
> + {
> + need_xenstore = true;
> + kinfo.dom0less_feature = DOM0LESS_ENHANCED_LEGACY;
> + }
> + else if ( rc == 0 && !strcmp(dom0less_enhanced, "no-xenstore") )
> + kinfo.dom0less_feature = DOM0LESS_ENHANCED_NO_XS;
> +
> + if ( vcpu_create(d, 0) == NULL )
> + return -ENOMEM;
> +
> + d->max_pages = ((paddr_t)mem * SZ_1K) >> PAGE_SHIFT;
> +
> + kinfo.d = d;
> +
> + rc = kernel_probe(&kinfo, node);
> + if ( rc < 0 )
> + return rc;
> +
> + set_domain_type(d, &kinfo);
> +
> + if ( is_hardware_domain(d) )
> + {
> + rc = construct_hwdom(&kinfo, node);
> + if ( rc < 0 )
> + return rc;
> + }
> + else
> + {
> + if ( !dt_find_property(node, "xen,static-mem", NULL) )
> + allocate_memory(d, &kinfo);
> + #ifdef CONFIG_STATIC_MEMORY
code style, I can fix on commit
> + else if ( !is_domain_direct_mapped(d) )
> + allocate_static_memory(d, &kinfo, node);
> + else
> + assign_static_memory_11(d, &kinfo, node);
> + #endif
also gere
> + #ifdef CONFIG_STATIC_SHM
and here
> + rc = process_shm(d, &kinfo, node);
> + if ( rc < 0 )
> + return rc;
> + #endif
and here
> + rc = init_vuart(d, &kinfo, node);
> + if ( rc < 0 )
> + return rc;
> +
> + rc = prepare_dtb_domU(d, &kinfo);
> + if ( rc < 0 )
> + return rc;
> +
> + rc = construct_domain(d, &kinfo);
> + if ( rc < 0 )
> + return rc;
> + }
> +
> + domain_vcpu_affinity(d, node);
> +
> + return alloc_xenstore_params(&kinfo);
> +}
> +
> void __init create_domUs(void)
> {
> struct dt_device_node *node;
> diff --git a/xen/include/asm-generic/dom0less-build.h
> b/xen/include/asm-generic/dom0less-build.h
> index 2003be743f..e0ad0429ec 100644
> --- a/xen/include/asm-generic/dom0less-build.h
> +++ b/xen/include/asm-generic/dom0less-build.h
> @@ -12,10 +12,7 @@ struct domain;
> #include <public/domctl.h>
>
> struct dt_device_node;
> -
> -/* TODO: remove both when construct_domU() will be moved to common. */
> -#define XENSTORE_PFN_LATE_ALLOC UINT64_MAX
> -extern bool need_xenstore;
> +struct kernel_info;
>
> /*
> * List of possible features for dom0less domUs
> @@ -49,12 +46,21 @@ void create_domUs(void);
> bool is_dom0less_mode(void);
> void set_xs_domain(struct domain *d);
>
> -int construct_domU(struct domain *d, const struct dt_device_node *node);
> -
> void arch_create_domUs(struct dt_device_node *node,
> struct xen_domctl_createdomain *d_cfg,
> unsigned int flags);
>
> +int init_vuart(struct domain *d, struct kernel_info *kinfo,
> + const struct dt_device_node *node);
> +
> +int make_intc_domU_node(struct kernel_info *kinfo);
> +int make_arch_nodes(struct kernel_info *kinfo);
> +
> +void set_domain_type(struct domain *d, struct kernel_info *kinfo);
> +
> +int init_intc_phandle(struct kernel_info *kinfo, const char *name,
> + const int node_next, const void *pfdt);
> +
> #else /* !CONFIG_DOM0LESS_BOOT */
>
> static inline void create_domUs(void) {}
> --
> 2.49.0
>
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |