[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [PATCH v4 5/9] xen/arm: Add XEN_DOMCTL_dt_overlay and device attachment to domains



On Thu, 23 May 2024, Julien Grall wrote:
> Hi Henry,
> 
> On 23/05/2024 08:40, Henry Wang wrote:
> > In order to support the dynamic dtbo device assignment to a running
> > VM, the add/remove of the DT overlay and the attach/detach of the
> > device from the DT overlay should happen separately. Therefore,
> > repurpose the existing XEN_SYSCTL_dt_overlay to only add the DT
> > overlay to Xen device tree
> 
> I think it would be worth mentioning in the commit message why changing the
> sysctl behavior is fine. The feature is experimental and therefore breaking
> compatibility is ok.

Added


> > , instead of assigning the device to the
> > hardware domain at the same time. Add the XEN_DOMCTL_dt_overlay with
> > operations XEN_DOMCTL_DT_OVERLAY_ATTACH to do the device assignment
> > to the domain.
> > 
> > The hypervisor firstly checks the DT overlay passed from the toolstack
> > is valid. Then the device nodes are retrieved from the overlay tracker
> > based on the DT overlay. The attach of the device is implemented by
> > mapping the IRQ and IOMMU resources.
> 
> So, the expectation is the user will always want to attach all the devices in
> the overlay to a single domain. Is that correct?

Yes, also added to the commit message

> > 
> > Signed-off-by: Henry Wang <xin.wang2@xxxxxxx>
> > Signed-off-by: Vikram Garhwal <fnu.vikram@xxxxxxxxxx>
> > ---
> > v4:
> > - Split the original patch, only do the device attachment.
> > v3:
> > - Style fixes for arch-selection #ifdefs.
> > - Do not include public/domctl.h, only add a forward declaration of
> >    struct xen_domctl_dt_overlay.
> > - Extract the overlay track entry finding logic to a function, drop
> >    the unused variables.
> > - Use op code 1&2 for XEN_DOMCTL_DT_OVERLAY_{ATTACH,DETACH}.
> > v2:
> > - New patch.
> > ---
> >   xen/arch/arm/domctl.c        |   3 +
> >   xen/common/dt-overlay.c      | 199 ++++++++++++++++++++++++++---------
> >   xen/include/public/domctl.h  |  14 +++
> >   xen/include/public/sysctl.h  |  11 +-
> >   xen/include/xen/dt-overlay.h |   7 ++
> >   5 files changed, 176 insertions(+), 58 deletions(-)
> > 
> > diff --git a/xen/arch/arm/domctl.c b/xen/arch/arm/domctl.c
> > index ad56efb0f5..12a12ee781 100644
> > --- a/xen/arch/arm/domctl.c
> > +++ b/xen/arch/arm/domctl.c
> > @@ -5,6 +5,7 @@
> >    * Copyright (c) 2012, Citrix Systems
> >    */
> >   +#include <xen/dt-overlay.h>
> >   #include <xen/errno.h>
> >   #include <xen/guest_access.h>
> >   #include <xen/hypercall.h>
> > @@ -176,6 +177,8 @@ long arch_do_domctl(struct xen_domctl *domctl, struct
> > domain *d,
> >             return rc;
> >       }
> > +    case XEN_DOMCTL_dt_overlay:
> > +        return dt_overlay_domctl(d, &domctl->u.dt_overlay);
> >       default:
> >           return subarch_do_domctl(domctl, d, u_domctl);
> >       }
> > diff --git a/xen/common/dt-overlay.c b/xen/common/dt-overlay.c
> > index 9cece79067..1087f9b502 100644
> > --- a/xen/common/dt-overlay.c
> > +++ b/xen/common/dt-overlay.c
> > @@ -356,6 +356,42 @@ static int overlay_get_nodes_info(const void *fdto,
> > char **nodes_full_path)
> >       return 0;
> >   }
> >   +/* This function should be called with the overlay_lock taken */
> > +static struct overlay_track *
> > +find_track_entry_from_tracker(const void *overlay_fdt,
> > +                              uint32_t overlay_fdt_size)
> > +{
> > +    struct overlay_track *entry, *temp;
> > +    bool found_entry = false;
> > +
> > +    ASSERT(spin_is_locked(&overlay_lock));
> > +
> > +    /*
> > +     * First check if dtbo is correct i.e. it should one of the dtbo which
> > was
> > +     * used when dynamically adding the node.
> > +     * Limitation: Cases with same node names but different property are
> > not
> > +     * supported currently. We are relying on user to provide the same dtbo
> > +     * as it was used when adding the nodes.
> > +     */
> > +    list_for_each_entry_safe( entry, temp, &overlay_tracker, entry )
> > +    {
> > +        if ( memcmp(entry->overlay_fdt, overlay_fdt, overlay_fdt_size) == 0
> > )
> > +        {
> > +            found_entry = true;
> > +            break;
> > +        }
> > +    }
> > +
> > +    if ( !found_entry )
> > +    {
> > +        printk(XENLOG_ERR "Cannot find any matching tracker with input
> > dtbo."
> > +               " Operation is supported only for prior added dtbo.\n");
> > +        return NULL;
> > +    }
> > +
> > +    return entry;
> > +}
> > +
> >   /* Check if node itself can be removed and remove node from IOMMU. */
> >   static int remove_node_resources(struct dt_device_node *device_node)
> >   {
> > @@ -485,8 +521,7 @@ static long handle_remove_overlay_nodes(const void
> > *overlay_fdt,
> >                                           uint32_t overlay_fdt_size)
> >   {
> >       int rc;
> > -    struct overlay_track *entry, *temp, *track;
> > -    bool found_entry = false;
> > +    struct overlay_track *entry;
> >         rc = check_overlay_fdt(overlay_fdt, overlay_fdt_size);
> >       if ( rc )
> > @@ -494,29 +529,10 @@ static long handle_remove_overlay_nodes(const void
> > *overlay_fdt,
> >         spin_lock(&overlay_lock);
> >   -    /*
> > -     * First check if dtbo is correct i.e. it should one of the dtbo which
> > was
> > -     * used when dynamically adding the node.
> > -     * Limitation: Cases with same node names but different property are
> > not
> > -     * supported currently. We are relying on user to provide the same dtbo
> > -     * as it was used when adding the nodes.
> > -     */
> > -    list_for_each_entry_safe( entry, temp, &overlay_tracker, entry )
> > -    {
> > -        if ( memcmp(entry->overlay_fdt, overlay_fdt, overlay_fdt_size) == 0
> > )
> > -        {
> > -            track = entry;
> > -            found_entry = true;
> > -            break;
> > -        }
> > -    }
> > -
> > -    if ( !found_entry )
> > +    entry = find_track_entry_from_tracker(overlay_fdt, overlay_fdt_size);
> > +    if ( entry == NULL )
> >       {
> >           rc = -EINVAL;
> > -
> > -        printk(XENLOG_ERR "Cannot find any matching tracker with input
> > dtbo."
> > -               " Removing nodes is supported only for prior added
> > dtbo.\n");
> >           goto out;
> >         }
> > @@ -620,15 +636,7 @@ static long add_nodes(struct overlay_track *tr, char
> > **nodes_full_path)
> >               return -EFAULT;
> >           }
> >   -        rc = handle_device(hardware_domain, overlay_node,
> > p2m_mmio_direct_c,
> > -                           tr->iomem_ranges,
> > -                           tr->irq_ranges);
> >           write_unlock(&dt_host_lock);
> > -        if ( rc )
> > -        {
> > -            printk(XENLOG_ERR "Adding IRQ and IOMMU failed\n");
> > -            return rc;
> > -        }
> >             /* Keep overlay_node address in tracker. */
> >           tr->nodes_address[j] = (unsigned long)overlay_node;
> > @@ -638,9 +646,7 @@ static long add_nodes(struct overlay_track *tr, char
> > **nodes_full_path)
> >   }
> >   /*
> >    * Adds device tree nodes under target node.
> > - * We use tr->dt_host_new to unflatten the updated device_tree_flattened.
> > This
> > - * is done to avoid the removal of device_tree generation, iomem regions
> > mapping
> > - * to hardware domain done by handle_node().
> > + * We use tr->dt_host_new to unflatten the updated device_tree_flattened.
> >    */
> >   static long handle_add_overlay_nodes(void *overlay_fdt,
> >                                        uint32_t overlay_fdt_size)
> > @@ -774,20 +780,6 @@ static long handle_add_overlay_nodes(void *overlay_fdt,
> >           goto err;
> >       }
> >   -    tr->irq_ranges = rangeset_new(hardware_domain, "Overlays:
> > Interrupts", 0);
> > -    if (tr->irq_ranges == NULL)
> > -    {
> > -        printk(XENLOG_ERR "Creating IRQ rangeset failed");
> > -        goto err;
> > -    }
> > -
> > -    tr->iomem_ranges = rangeset_new(hardware_domain, "Overlay: I/O Memory",
> > 0);
> > -    if (tr->iomem_ranges == NULL)
> > -    {
> > -        printk(XENLOG_ERR "Creating IOMMU rangeset failed");
> > -        goto err;
> > -    }
> > -
> >       rc = add_nodes(tr, nodes_full_path);
> >       if ( rc )
> >       {
> > @@ -843,14 +835,83 @@ static long handle_add_overlay_nodes(void
> > *overlay_fdt,
> >       xfree(tr->nodes_address);
> >       xfree(tr->fdt);
> >   -    rangeset_destroy(tr->irq_ranges);
> > -    rangeset_destroy(tr->iomem_ranges);
> > -
> >       xfree(tr);
> >         return rc;
> >   }
> >   +static long handle_attach_overlay_nodes(struct domain *d,
> > +                                        const void *overlay_fdt,
> > +                                        uint32_t overlay_fdt_size)
> > +{
> > +    int rc;
> > +    unsigned int j;
> > +    struct overlay_track *entry;
> > +
> > +    rc = check_overlay_fdt(overlay_fdt, overlay_fdt_size);
> > +    if ( rc )
> > +        return rc;
> > +
> > +    spin_lock(&overlay_lock);
> > +
> > +    entry = find_track_entry_from_tracker(overlay_fdt, overlay_fdt_size);
> > +    if ( entry == NULL )
> > +    {
> > +        rc = -EINVAL;
> > +        goto out;
> > +    }
> > +
> > +    entry->irq_ranges = rangeset_new(d, "Overlays: Interrupts", 0);
> > +    if (entry->irq_ranges == NULL)
> > +    {
> > +        rc = -ENOMEM;
> > +        printk(XENLOG_ERR "Creating IRQ rangeset failed");
> > +        goto out;
> > +    }
> > +
> > +    entry->iomem_ranges = rangeset_new(d, "Overlay: I/O Memory", 0);
> > +    if (entry->iomem_ranges == NULL)
> > +    {
> > +        rc = -ENOMEM;
> > +        printk(XENLOG_ERR "Creating IOMMU rangeset failed");
> > +        goto out;
> > +    }
> > +
> > +    for ( j = 0; j < entry->num_nodes; j++ )
> > +    {
> > +        struct dt_device_node *overlay_node;
> > +
> > +        overlay_node = (struct dt_device_node *)entry->nodes_address[j];
> > +        if ( overlay_node == NULL )
> > +        {
> > +            rc = -EINVAL;
> > +            goto out;
> > +        }
> > +
> > +        write_lock(&dt_host_lock);
> > +        rc = handle_device(d, overlay_node, p2m_mmio_direct_c,
> > +                           entry->iomem_ranges, entry->irq_ranges);
> > +        write_unlock(&dt_host_lock);
> > +        if ( rc )
> > +        {
> > +            printk(XENLOG_ERR "Adding IRQ and IOMMU failed\n");
> > +            goto out;
> > +        }
> > +    }
> > +
> > +    spin_unlock(&overlay_lock);
> > +
> > +    return 0;
> > +
> > + out:
> > +    spin_unlock(&overlay_lock);
> > +
> > +    rangeset_destroy(entry->irq_ranges);
> > +    rangeset_destroy(entry->iomem_ranges);
> > +
> > +    return rc;
> > +}
> > +
> >   long dt_overlay_sysctl(struct xen_sysctl_dt_overlay *op)
> >   {
> >       long ret;
> > @@ -890,6 +951,42 @@ long dt_overlay_sysctl(struct xen_sysctl_dt_overlay
> > *op)
> >       return ret;
> >   }
> >   +long dt_overlay_domctl(struct domain *d, struct xen_domctl_dt_overlay
> > *op)
> > +{
> > +    long ret;
> > +    void *overlay_fdt;
> > +
> > +    if ( op->overlay_op != XEN_DOMCTL_DT_OVERLAY_ATTACH )
> > +        return -EOPNOTSUPP;
> > +
> > +    if ( op->overlay_fdt_size == 0 || op->overlay_fdt_size > KB(500) )
> 
> Let's avoid to hardocode KB(500) a second time (it alredy exists in the sysctl
> path).
> 
> But I would actually consider to allow up to 512KB because...

I left it as is because I wasn't sure what you wanted as a change. Did
you mean that you would like the check to be removed, or did you mean
that you would like an #define instead of writing KB(500)?

It is fine either way for me, or to keep it as is, please make the
desired change on commit.


> > +        return -EINVAL;
> > +
> > +    if ( op->pad[0] || op->pad[1] || op->pad[2] )
> > +        return -EINVAL;
> > +
> > +    overlay_fdt = xmalloc_bytes(op->overlay_fdt_size);
> 
> ... xmalloc_bytes() will be more efficient. If the size is not power of 2
> pages, it will free the leftover. Anyway, this could be a follow-up patch.

Leaving this as is for now


> > +
> > +    if ( overlay_fdt == NULL )
> > +        return -ENOMEM;
> > +
> > +    ret = copy_from_guest(overlay_fdt, op->overlay_fdt,
> > op->overlay_fdt_size);
> > +    if ( ret )
> > +    {
> > +        gprintk(XENLOG_ERR, "copy from guest failed\n");
> > +        xfree(overlay_fdt);
> > +
> > +        return -EFAULT;
> > +    }
> > +
> > +    if ( op->overlay_op == XEN_DOMCTL_DT_OVERLAY_ATTACH )
> > +        ret = handle_attach_overlay_nodes(d, overlay_fdt,
> > op->overlay_fdt_size);
> 
> I think you would return 0 if the operation is not supported. But I think we
> need to return -EOPNOTSUPP.

I made the change


> > +
> > +    xfree(overlay_fdt);
> > +
> > +    return ret;
> > +}
> > +
> >   /*
> >    * Local variables:
> >    * mode: C
> > diff --git a/xen/include/public/domctl.h b/xen/include/public/domctl.h
> > index a33f9ec32b..ac3c2a7c4c 100644
> > --- a/xen/include/public/domctl.h
> > +++ b/xen/include/public/domctl.h
> 
> If I am not mistkane, this is the first change in the domctl header for 4.19.
> So you want to bump XEN_DOMCTL_INTERFACE_VERSION.

Done


> > @@ -1190,6 +1190,16 @@ struct xen_domctl_vmtrace_op {
> >   typedef struct xen_domctl_vmtrace_op xen_domctl_vmtrace_op_t;
> >   DEFINE_XEN_GUEST_HANDLE(xen_domctl_vmtrace_op_t);
> >   +#if defined(__arm__) || defined(__aarch64__)
> > +struct xen_domctl_dt_overlay {
> > +    XEN_GUEST_HANDLE_64(const_void) overlay_fdt;  /* IN: overlay fdt. */
> > +    uint32_t overlay_fdt_size;              /* IN: Overlay dtb size. */
> > +#define XEN_DOMCTL_DT_OVERLAY_ATTACH                1
> 
> OOI, why not starting from 0?

I think it was to avoid the risk of confusing zero as uninitialized with
a real operation.


> > +    uint8_t overlay_op;                     /* IN: Attach. */
> > +    uint8_t pad[3];                         /* IN: Must be zero. */
> > +};
> > +#endif
> > +
> >   struct xen_domctl {
> >       uint32_t cmd;
> >   #define XEN_DOMCTL_createdomain                   1
> > @@ -1277,6 +1287,7 @@ struct xen_domctl {
> >   #define XEN_DOMCTL_vmtrace_op                    84
> >   #define XEN_DOMCTL_get_paging_mempool_size       85
> >   #define XEN_DOMCTL_set_paging_mempool_size       86
> > +#define XEN_DOMCTL_dt_overlay                    87
> >   #define XEN_DOMCTL_gdbsx_guestmemio            1000
> >   #define XEN_DOMCTL_gdbsx_pausevcpu             1001
> >   #define XEN_DOMCTL_gdbsx_unpausevcpu           1002
> > @@ -1339,6 +1350,9 @@ struct xen_domctl {
> >           struct xen_domctl_vuart_op          vuart_op;
> >           struct xen_domctl_vmtrace_op        vmtrace_op;
> >           struct xen_domctl_paging_mempool    paging_mempool;
> > +#if defined(__arm__) || defined(__aarch64__)
> > +        struct xen_domctl_dt_overlay        dt_overlay;
> > +#endif
> >           uint8_t                             pad[128];
> >       } u;
> >   };
> > diff --git a/xen/include/public/sysctl.h b/xen/include/public/sysctl.h
> > index febaa4b16a..3a6e7d48f0 100644
> > --- a/xen/include/public/sysctl.h
> > +++ b/xen/include/public/sysctl.h
> > @@ -1184,14 +1184,11 @@ typedef struct xen_sysctl_cpu_policy
> > xen_sysctl_cpu_policy_t;
> >   DEFINE_XEN_GUEST_HANDLE(xen_sysctl_cpu_policy_t);
> >   #endif
> >   -#if defined(__arm__) || defined (__aarch64__)
> > +#if defined(__arm__) || defined(__aarch64__)
> 
> This seems like unrelated change. Maybe mention in the commit message that you
> are fixing the coding style?

Done


> >   /*
> >    * XEN_SYSCTL_dt_overlay
> > - * Performs addition/removal of device tree nodes under parent node using
> > dtbo.
> > - * This does in three steps:
> > - *  - Adds/Removes the nodes from dt_host.
> > - *  - Adds/Removes IRQ permission for the nodes.
> > - *  - Adds/Removes MMIO accesses.
> > + * Performs addition/removal of device tree nodes under parent node using
> > dtbo
> > + * from dt_host.
> >    */
> >   struct xen_sysctl_dt_overlay {
> >       XEN_GUEST_HANDLE_64(const_void) overlay_fdt;  /* IN: overlay fdt. */
> > @@ -1265,7 +1262,7 @@ struct xen_sysctl {
> >           struct xen_sysctl_cpu_policy        cpu_policy;
> >   #endif
> >   -#if defined(__arm__) || defined (__aarch64__)
> > +#if defined(__arm__) || defined(__aarch64__)
> >           struct xen_sysctl_dt_overlay        dt_overlay;
> >   #endif
> >           uint8_t                             pad[128];
> > diff --git a/xen/include/xen/dt-overlay.h b/xen/include/xen/dt-overlay.h
> > index c0567741ee..7f0f3741b5 100644
> > --- a/xen/include/xen/dt-overlay.h
> > +++ b/xen/include/xen/dt-overlay.h
> > @@ -39,15 +39,22 @@ struct overlay_track {
> >   };
> >     struct xen_sysctl_dt_overlay;
> > +struct xen_domctl_dt_overlay;
> >     #ifdef CONFIG_OVERLAY_DTB
> >   long dt_overlay_sysctl(struct xen_sysctl_dt_overlay *op);
> > +long dt_overlay_domctl(struct domain *d, struct xen_domctl_dt_overlay *op);
> >   #else
> >   #include <xen/errno.h>
> >   static inline long dt_overlay_sysctl(struct xen_sysctl_dt_overlay *op)
> >   {
> >       return -EOPNOTSUPP;
> >   }
> 
> NIT: Newline here please.

Done

> 
> > +static inline long dt_overlay_domctl(struct domain *d,
> > +                                     struct xen_domctl_dt_overlay *op)
> > +{
> > +    return -EOPNOTSUPP;
> > +}
> >   #endif
> >     #endif /* __XEN_DT_OVERLAY_H__ */
> 
> Cheers,
> 
> -- 
> Julien Grall
> 



 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.