diff --git a/xen/arch/arm/Kconfig b/xen/arch/arm/Kconfig index f73b62e50d..50e9bfae1a 100644 --- a/xen/arch/arm/Kconfig +++ b/xen/arch/arm/Kconfig @@ -217,6 +217,14 @@ config STATIC_SHM help This option enables statically shared memory on a dom0less system. +config STATIC_EVTCHN + bool "Static event channel support on a dom0less system" + depends on DOM0LESS_BOOT + default y + help + This option enables establishing static event channel communication + between domains on a dom0less system (domU-domU as well as domU-dom0). + endmenu menu "ARM errata workaround via the alternative framework" diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile index 809772417c..33c677672f 100644 --- a/xen/arch/arm/Makefile +++ b/xen/arch/arm/Makefile @@ -51,6 +51,7 @@ obj-y += setup.o obj-y += shutdown.o obj-y += smp.o obj-y += smpboot.o +obj-$(CONFIG_STATIC_EVTCHN) += static-evtchn.init.o obj-$(CONFIG_STATIC_MEMORY) += static-memory.init.o obj-$(CONFIG_STATIC_SHM) += static-shmem.init.o obj-y += sysctl.o diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c index df66fb88d8..613b2885ce 100644 --- a/xen/arch/arm/domain_build.c +++ b/xen/arch/arm/domain_build.c @@ -38,8 +38,6 @@ #include #include -#define STATIC_EVTCHN_NODE_SIZE_CELLS 2 - static unsigned int __initdata opt_dom0_max_vcpus; integer_param("dom0_max_vcpus", opt_dom0_max_vcpus); @@ -1919,150 +1917,6 @@ void __init evtchn_allocate(struct domain *d) d->arch.hvm.params[HVM_PARAM_CALLBACK_IRQ] = val; } -static int __init get_evtchn_dt_property(const struct dt_device_node *np, - uint32_t *port, uint32_t *phandle) -{ - const __be32 *prop = NULL; - uint32_t len; - - prop = dt_get_property(np, "xen,evtchn", &len); - if ( !prop ) - { - printk(XENLOG_ERR "xen,evtchn property should not be empty.\n"); - return -EINVAL; - } - - if ( !len || len < dt_cells_to_size(STATIC_EVTCHN_NODE_SIZE_CELLS) ) - { - printk(XENLOG_ERR "xen,evtchn property value is not valid.\n"); - return -EINVAL; - } - - *port = dt_next_cell(1, &prop); - *phandle = dt_next_cell(1, &prop); - - return 0; -} - -static int __init alloc_domain_evtchn(struct dt_device_node *node) -{ - int rc; - uint32_t domU1_port, domU2_port, remote_phandle; - struct dt_device_node *remote_node; - const struct dt_device_node *p1_node, *p2_node; - struct evtchn_alloc_unbound alloc_unbound; - struct evtchn_bind_interdomain bind_interdomain; - struct domain *d1 = NULL, *d2 = NULL; - - if ( !dt_device_is_compatible(node, "xen,evtchn-v1") ) - return 0; - - /* - * Event channel is already created while parsing the other side of - * evtchn node. - */ - if ( dt_device_static_evtchn_created(node) ) - return 0; - - rc = get_evtchn_dt_property(node, &domU1_port, &remote_phandle); - if ( rc ) - return rc; - - remote_node = dt_find_node_by_phandle(remote_phandle); - if ( !remote_node ) - { - printk(XENLOG_ERR - "evtchn: could not find remote evtchn phandle\n"); - return -EINVAL; - } - - rc = get_evtchn_dt_property(remote_node, &domU2_port, &remote_phandle); - if ( rc ) - return rc; - - if ( node->phandle != remote_phandle ) - { - printk(XENLOG_ERR "xen,evtchn property is not setup correctly.\n"); - return -EINVAL; - } - - p1_node = dt_get_parent(node); - if ( !p1_node ) - { - printk(XENLOG_ERR "evtchn: evtchn parent node is NULL\n" ); - return -EINVAL; - } - - p2_node = dt_get_parent(remote_node); - if ( !p2_node ) - { - printk(XENLOG_ERR "evtchn: remote parent node is NULL\n" ); - return -EINVAL; - } - - d1 = get_domain_by_id(p1_node->used_by); - d2 = get_domain_by_id(p2_node->used_by); - - if ( !d1 || !d2 ) - { - printk(XENLOG_ERR "evtchn: could not find domains\n" ); - return -EINVAL; - } - - alloc_unbound.dom = d1->domain_id; - alloc_unbound.remote_dom = d2->domain_id; - - rc = evtchn_alloc_unbound(&alloc_unbound, domU1_port); - if ( rc < 0 ) - { - printk(XENLOG_ERR - "evtchn_alloc_unbound() failure (Error %d) \n", rc); - return rc; - } - - bind_interdomain.remote_dom = d1->domain_id; - bind_interdomain.remote_port = domU1_port; - - rc = evtchn_bind_interdomain(&bind_interdomain, d2, domU2_port); - if ( rc < 0 ) - { - printk(XENLOG_ERR - "evtchn_bind_interdomain() failure (Error %d) \n", rc); - return rc; - } - - dt_device_set_static_evtchn_created(node); - dt_device_set_static_evtchn_created(remote_node); - - return 0; -} - -void __init alloc_static_evtchn(void) -{ - struct dt_device_node *node, *evtchn_node; - struct dt_device_node *chosen = dt_find_node_by_path("/chosen"); - - BUG_ON(chosen == NULL); - - if ( hardware_domain ) - dt_device_set_used_by(chosen, hardware_domain->domain_id); - - dt_for_each_child_node(chosen, node) - { - if ( hardware_domain ) - { - if ( alloc_domain_evtchn(node) != 0 ) - panic("Could not set up domains evtchn\n"); - } - - dt_for_each_child_node(node, evtchn_node) - { - if ( alloc_domain_evtchn(evtchn_node) != 0 ) - panic("Could not set up domains evtchn\n"); - } - } -} - static void __init find_gnttab_region(struct domain *d, struct kernel_info *kinfo) { diff --git a/xen/arch/arm/include/asm/setup.h b/xen/arch/arm/include/asm/setup.h index bda3c07b87..d15a88d2e0 100644 --- a/xen/arch/arm/include/asm/setup.h +++ b/xen/arch/arm/include/asm/setup.h @@ -136,7 +136,6 @@ void acpi_create_efi_mmap_table(struct domain *d, int acpi_make_efi_nodes(void *fdt, struct membank tbl_add[]); void create_dom0(void); -void alloc_static_evtchn(void); void discard_initial_modules(void); void fw_unreserved_regions(paddr_t s, paddr_t e, diff --git a/xen/arch/arm/include/asm/static-evtchn.h b/xen/arch/arm/include/asm/static-evtchn.h new file mode 100644 index 0000000000..f964522f6a --- /dev/null +++ b/xen/arch/arm/include/asm/static-evtchn.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#ifndef __ASM_STATIC_EVTCHN_H_ +#define __ASM_STATIC_EVTCHN_H_ + +#ifdef CONFIG_STATIC_EVTCHN + +void alloc_static_evtchn(void); + +#else /* !CONFIG_STATIC_EVTCHN */ + +static inline void alloc_static_evtchn(void) {}; + +#endif /* CONFIG_STATIC_EVTCHN */ + +#endif /* __ASM_STATIC_EVTCHN_H_ */ + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c index d07ea044db..59dd9bb25a 100644 --- a/xen/arch/arm/setup.c +++ b/xen/arch/arm/setup.c @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include diff --git a/xen/arch/arm/static-evtchn.c b/xen/arch/arm/static-evtchn.c new file mode 100644 index 0000000000..49db08d5c6 --- /dev/null +++ b/xen/arch/arm/static-evtchn.c @@ -0,0 +1,161 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ + +#include + +#include + +#define STATIC_EVTCHN_NODE_SIZE_CELLS 2 + +static int __init get_evtchn_dt_property(const struct dt_device_node *np, + uint32_t *port, uint32_t *phandle) +{ + const __be32 *prop = NULL; + uint32_t len; + + prop = dt_get_property(np, "xen,evtchn", &len); + if ( !prop ) + { + printk(XENLOG_ERR "xen,evtchn property should not be empty.\n"); + return -EINVAL; + } + + if ( !len || len < dt_cells_to_size(STATIC_EVTCHN_NODE_SIZE_CELLS) ) + { + printk(XENLOG_ERR "xen,evtchn property value is not valid.\n"); + return -EINVAL; + } + + *port = dt_next_cell(1, &prop); + *phandle = dt_next_cell(1, &prop); + + return 0; +} + +static int __init alloc_domain_evtchn(struct dt_device_node *node) +{ + int rc; + uint32_t domU1_port, domU2_port, remote_phandle; + struct dt_device_node *remote_node; + const struct dt_device_node *p1_node, *p2_node; + struct evtchn_alloc_unbound alloc_unbound; + struct evtchn_bind_interdomain bind_interdomain; + struct domain *d1 = NULL, *d2 = NULL; + + if ( !dt_device_is_compatible(node, "xen,evtchn-v1") ) + return 0; + + /* + * Event channel is already created while parsing the other side of + * evtchn node. + */ + if ( dt_device_static_evtchn_created(node) ) + return 0; + + rc = get_evtchn_dt_property(node, &domU1_port, &remote_phandle); + if ( rc ) + return rc; + + remote_node = dt_find_node_by_phandle(remote_phandle); + if ( !remote_node ) + { + printk(XENLOG_ERR + "evtchn: could not find remote evtchn phandle\n"); + return -EINVAL; + } + + rc = get_evtchn_dt_property(remote_node, &domU2_port, &remote_phandle); + if ( rc ) + return rc; + + if ( node->phandle != remote_phandle ) + { + printk(XENLOG_ERR "xen,evtchn property is not setup correctly.\n"); + return -EINVAL; + } + + p1_node = dt_get_parent(node); + if ( !p1_node ) + { + printk(XENLOG_ERR "evtchn: evtchn parent node is NULL\n" ); + return -EINVAL; + } + + p2_node = dt_get_parent(remote_node); + if ( !p2_node ) + { + printk(XENLOG_ERR "evtchn: remote parent node is NULL\n" ); + return -EINVAL; + } + + d1 = get_domain_by_id(p1_node->used_by); + d2 = get_domain_by_id(p2_node->used_by); + + if ( !d1 || !d2 ) + { + printk(XENLOG_ERR "evtchn: could not find domains\n" ); + return -EINVAL; + } + + alloc_unbound.dom = d1->domain_id; + alloc_unbound.remote_dom = d2->domain_id; + + rc = evtchn_alloc_unbound(&alloc_unbound, domU1_port); + if ( rc < 0 ) + { + printk(XENLOG_ERR + "evtchn_alloc_unbound() failure (Error %d) \n", rc); + return rc; + } + + bind_interdomain.remote_dom = d1->domain_id; + bind_interdomain.remote_port = domU1_port; + + rc = evtchn_bind_interdomain(&bind_interdomain, d2, domU2_port); + if ( rc < 0 ) + { + printk(XENLOG_ERR + "evtchn_bind_interdomain() failure (Error %d) \n", rc); + return rc; + } + + dt_device_set_static_evtchn_created(node); + dt_device_set_static_evtchn_created(remote_node); + + return 0; +} + +void __init alloc_static_evtchn(void) +{ + struct dt_device_node *node, *evtchn_node; + struct dt_device_node *chosen = dt_find_node_by_path("/chosen"); + + BUG_ON(chosen == NULL); + + if ( hardware_domain ) + dt_device_set_used_by(chosen, hardware_domain->domain_id); + + dt_for_each_child_node(chosen, node) + { + if ( hardware_domain ) + { + if ( alloc_domain_evtchn(node) != 0 ) + panic("Could not set up domains evtchn\n"); + } + + dt_for_each_child_node(node, evtchn_node) + { + if ( alloc_domain_evtchn(evtchn_node) != 0 ) + panic("Could not set up domains evtchn\n"); + } + } +} + +/* + * Local variables: + * mode: C + * c-file-style: "BSD" + * c-basic-offset: 4 + * tab-width: 4 + * indent-tabs-mode: nil + * End: + */ diff --git a/xen/include/xen/device_tree.h b/xen/include/xen/device_tree.h index 3ae7b45429..94a836cb4e 100644 --- a/xen/include/xen/device_tree.h +++ b/xen/include/xen/device_tree.h @@ -94,8 +94,10 @@ struct dt_device_node { /* IOMMU specific fields */ bool is_protected; +#ifdef CONFIG_STATIC_EVTCHN /* HACK: Remove this if there is a need of space */ bool static_evtchn_created; +#endif /* * The main purpose of this list is to link the structure in the list @@ -366,6 +368,7 @@ static inline bool dt_property_name_is_equal(const struct dt_property *pp, return !dt_prop_cmp(pp->name, name); } +#ifdef CONFIG_STATIC_EVTCHN static inline void dt_device_set_static_evtchn_created(struct dt_device_node *device) { @@ -377,6 +380,7 @@ dt_device_static_evtchn_created(const struct dt_device_node *device) { return device->static_evtchn_created; } +#endif /* CONFIG_STATIC_EVTCHN */ /** * dt_find_compatible_node - Find a node based on type and one of the