[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [PATCH v3 6/7] xen/arm: introduce xen-evtchn dom0less property
On Thu, 1 Sep 2022, Julien Grall wrote: > On 01/09/2022 10:13, Rahul Singh wrote: > > Introduce a new sub-node under /chosen node to establish static event > > channel communication between domains on dom0less systems. > > > > An event channel will be created beforehand to allow the domains to > > send notifications to each other. > > > > Signed-off-by: Rahul Singh <rahul.singh@xxxxxxx> > > --- > > Changes in v3: > > - use device-tree used_by to find the domain id of the evtchn node. > > - add new static_evtchn_create variable in struct dt_device_node to > > hold the information if evtchn is already created. > > - fix minor comments > > Changes in v2: > > - no change > > --- > > docs/misc/arm/device-tree/booting.txt | 64 ++++++++++++- > > xen/arch/arm/domain_build.c | 128 ++++++++++++++++++++++++++ > > xen/arch/arm/include/asm/setup.h | 1 + > > xen/arch/arm/setup.c | 2 + > > xen/include/xen/device_tree.h | 13 +++ > > 5 files changed, 207 insertions(+), 1 deletion(-) > > > > diff --git a/docs/misc/arm/device-tree/booting.txt > > b/docs/misc/arm/device-tree/booting.txt > > index 98253414b8..edef98e6d1 100644 > > --- a/docs/misc/arm/device-tree/booting.txt > > +++ b/docs/misc/arm/device-tree/booting.txt > > @@ -212,7 +212,7 @@ with the following properties: > > enable only selected interfaces. > > Under the "xen,domain" compatible node, one or more sub-nodes are > > present > > -for the DomU kernel and ramdisk. > > +for the DomU kernel, ramdisk and static event channel. > > The kernel sub-node has the following properties: > > @@ -254,11 +254,44 @@ The ramdisk sub-node has the following properties: > > property because it will be created by the UEFI stub on boot. > > This option is needed only when UEFI boot is used. > > +The static event channel sub-node has the following properties: > > + > > +- compatible > > + > > + "xen,evtchn" > > + > > +- xen,evtchn > > + > > + The property is tuples of two numbers > > + (local-evtchn link-to-foreign-evtchn) where: > > + > > + local-evtchn is an integer value that will be used to allocate local > > port > > + for a domain to send and receive event notifications to/from the remote > > + domain. Maximum supported value is 2^17 for FIFO ABI and 4096 for 2L > > ABI. > > + It is recommended to use low event channel IDs. > > + > > + link-to-foreign-evtchn is a single phandle to a remote evtchn to which > > + local-evtchn will be connected. > > Example > > ======= > > chosen { > > + > > + module@0 { > > + compatible = "multiboot,kernel", "multiboot,module"; > > + xen,uefi-binary = "..."; > > + bootargs = "..."; > > + > > + }; > > NIT: Describing this node in the example seems unnecessary. > > > + > > + /* one sub-node per local event channel */ > > + ec1: evtchn@1 { > > + compatible = "xen,evtchn-v1"; > > + /* local-evtchn link-to-foreign-evtchn */ > > + xen,evtchn = <0xa &ec2>; > > + }; > > + > > Here you provide an example for dom0. But the position where you describe the > binding suggests this binding only exists for domUs. > > Either we duplicate the binding or we re-order the documentation to have > common binding in a single place. My preference would be the latter. > > > domU1 { > > compatible = "xen,domain"; > > #address-cells = <0x2>; > > @@ -277,6 +310,23 @@ chosen { > > compatible = "multiboot,ramdisk", "multiboot,module"; > > reg = <0x0 0x4b000000 0xffffff>; > > }; > > + > > + /* one sub-node per local event channel */ > > + ec2: evtchn@2 { > > + compatible = "xen,evtchn-v1"; > > + /* local-evtchn link-to-foreign-evtchn */ > > + xen,evtchn = <0xa &ec1>; > > + }; > > + > > + ec3: evtchn@3 { > > + compatible = "xen,evtchn-v1"; > > + xen,evtchn = <0xb &ec5>; > > + }; > > + > > + ec4: evtchn@4 { > > + compatible = "xen,evtchn-v1"; > > + xen,evtchn = <0xc &ec6>; > > + }; > > }; > > domU2 { > > @@ -296,6 +346,18 @@ chosen { > > compatible = "multiboot,ramdisk", "multiboot,module"; > > reg = <0x0 0x4d000000 0xffffff>; > > }; > > + > > + /* one sub-node per local event channel */ > > + ec5: evtchn@5 { > > + compatible = "xen,evtchn-v1"; > > + /* local-evtchn link-to-foreign-evtchn */ > > + xen,evtchn = <0xb &ec3>; > > + }; > > + > > + ec6: evtchn@6 { > > + compatible = "xen,evtchn-v1"; > > + xen,evtchn = <0xd &ec4>; > > + }; > > }; > > }; > > diff --git a/xen/arch/arm/domain_build.c b/xen/arch/arm/domain_build.c > > index 707e247f6a..4b24261825 100644 > > --- a/xen/arch/arm/domain_build.c > > +++ b/xen/arch/arm/domain_build.c > > @@ -33,6 +33,8 @@ > > #include <xen/grant_table.h> > > #include <xen/serial.h> > > +#define STATIC_EVTCHN_NODE_SIZE_CELLS 2 > > + > > static unsigned int __initdata opt_dom0_max_vcpus; > > integer_param("dom0_max_vcpus", opt_dom0_max_vcpus); > > @@ -3052,6 +3054,131 @@ 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; > > + struct evtchn_alloc_unbound alloc_unbound; > > + struct evtchn_bind_interdomain bind_interdomain; > > + struct domain *d1 = NULL, *d2 = NULL; > > + > > + if ( dt_device_static_evtchn_created(node) ) > > I think this deserve a comment explain why the node would be created. I.e it > would happen if the other side was created first. I will comment about > dt_device_static_evtchn_created() futher down. > > > + 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; > > + } > > + > > + d1 = get_domain_by_id(dt_get_parent(node)->used_by); > > + d2 = get_domain_by_id(dt_get_parent(remote_node)->used_by); > > I think dt_get_parent() could return NULL (i.e. for the root). So I think you > want to check that at least remote_node() has a parent. For convenience, this > check could be done in > > > + > > + 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 process_static_evtchn_node(struct dt_device_node *node) > > This is missing a prototype. So I guess this wants to be static? > > That said, I think it would make more sense to fold > process_static_evtchn_node() in alloc_domain_evtchn() or > alloc_static-evtchn(). > > > +{ > > + if ( dt_device_is_compatible(node, "xen,evtchn-v1") ) > > + { > > + if ( alloc_domain_evtchn(node) != 0 ) > > + panic("Could not set up domains evtchn\n"); > > + } > > +} > > + > > +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 ) > > + process_static_evtchn_node(node); > > + > > + dt_for_each_child_node(node, evtchn_node) > > + process_static_evtchn_node(evtchn_node); > > + } > > +} > > + > > static void __init find_gnttab_region(struct domain *d, > > struct kernel_info *kinfo) > > { > > @@ -3364,6 +3491,7 @@ void __init create_domUs(void) > > panic("Error creating domain %s\n", dt_node_name(node)); > > d->is_console = true; > > + dt_device_set_used_by(node, d->domain_id); > > if ( construct_domU(d, node) != 0 ) > > panic("Could not set up domain %s\n", dt_node_name(node)); > > diff --git a/xen/arch/arm/include/asm/setup.h > > b/xen/arch/arm/include/asm/setup.h > > index 5815ccf8c5..5ee28b270f 100644 > > --- a/xen/arch/arm/include/asm/setup.h > > +++ b/xen/arch/arm/include/asm/setup.h > > @@ -106,6 +106,7 @@ int acpi_make_efi_nodes(void *fdt, struct membank > > tbl_add[]); > > void create_domUs(void); > > 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/setup.c b/xen/arch/arm/setup.c > > index 6e0398f3f6..cf15d359d2 100644 > > --- a/xen/arch/arm/setup.c > > +++ b/xen/arch/arm/setup.c > > @@ -1077,6 +1077,8 @@ void __init start_xen(unsigned long boot_phys_offset, > > if ( acpi_disabled ) > > create_domUs(); > > + alloc_static_evtchn(); > > + > > /* > > * This needs to be called **before** heap_init_late() so modules > > * will be scrubbed (unless suppressed). > > diff --git a/xen/include/xen/device_tree.h b/xen/include/xen/device_tree.h > > index 430a1ef445..5579c875d2 100644 > > --- a/xen/include/xen/device_tree.h > > +++ b/xen/include/xen/device_tree.h > > @@ -82,6 +82,7 @@ struct dt_device_node { > > dt_phandle phandle; > > char *full_name; > > domid_t used_by; /* By default it's used by dom0 */ > > + bool_t static_evtchn_created; > > I can see why you want to add the boolean in dt_device_node. However, I > dislike this approach because this feels an abuse of dt_device_node and the > field is only used at boot. > > So this seems to be a bit of a waste to include it in the structure (even if > we are re-using padding today). > > I don't have a solution that is has trivial as this approach. However, at > minimum we should document this is a HACK and should be remove if we need > space in the structure. I would move static_evtchn_created just above (or below) "bool is_protected". It would still re-use the padding and it would be closer to another more similar field of the struct. The only other option that I can think of would be to use port_is_valid, instead of static_evtchn_created, to check that the port has already been allocated, but we wouldn't be able to tell if it is a static evtchn or simply unavailable for other reasons and it would require more device tree parsing.
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |