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

Re: [XEN][RFC PATCH v3 10/14] xen/arm: Implement device tree node removal functionalities


  • To: Vikram Garhwal <fnu.vikram@xxxxxxxxxx>
  • From: Luca Fancellu <Luca.Fancellu@xxxxxxx>
  • Date: Tue, 15 Mar 2022 10:10:40 +0000
  • Accept-language: en-GB, en-US
  • Arc-authentication-results: i=1; mx.microsoft.com 1; spf=pass smtp.mailfrom=arm.com; dmarc=pass action=none header.from=arm.com; dkim=pass header.d=arm.com; arc=none
  • Arc-message-signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-AntiSpam-MessageData-ChunkCount:X-MS-Exchange-AntiSpam-MessageData-0:X-MS-Exchange-AntiSpam-MessageData-1; bh=0Xd9tJPmVHqwTMr8HrUReVlY39b81yZ3QyHJIENAIsg=; b=nM9wWA8CVfvYTfsOndxCAGoaHPIt/qH8kF7hhu0upS83fs0hglGjLsCZR4oK3nPt5MJtNqPby8J1wiKup1G/nSLDTqDZHAOoQmWUA8a1WO2AsQRxOAdog5MPXlnk0Oi1d3rzrEQILAPIBDdW878NMOmJUF0QspGOsZwIvSAOSAuMS7jBVY9CdxbvsYX+bSlRx7ZEgVZDbMRaFVTSCmNWnSflXptNhIIZM3IQG8kwhhtjSgrXi1EjN3Q6rEArFP7f8MXoNAjLgBubiJxYP/43xI5Q4QVmCKvGAqP4BIQWrz7SxLQGcmoJ3dFhFjlryt9qS3d+lPruT0NmDcY/T2SNWA==
  • Arc-seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=MTd2Aa8YBLyFGeTeY5uSjv+21EuROhfF120Zlz6i94yVT7Y2s1gPgvllKAH2zViFPhrMek7mUucpDQmryaskLs2OdRig+uIdRdSm3vJzuDL2OE//EYdSRDPeyFrORZ4BADVSd+ERPPRUjPuv+0Wn56Q8XJhisXnFVL9eCQnfznXU/qjG7CnUDEl131de+Brj7qqOqgvuzhFM3QSg6qM36XHWvexZPvFZO6z4gBc1No5NnAd7dPkej9qefi7lqzjnh5oSWKu21Fs8GJL+eaoHoYHufenRe+G1fPrJRgGCQpJRu6c5jKiYQ7eRINOMqtGLaq69ErhQpE2WlfLVwqhayQ==
  • Authentication-results-original: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=arm.com;
  • Cc: Xen-devel <xen-devel@xxxxxxxxxxxxxxxxxxxx>, Stefano Stabellini <sstabellini@xxxxxxxxxx>, "julien@xxxxxxx" <julien@xxxxxxx>, Bertrand Marquis <Bertrand.Marquis@xxxxxxx>, "volodymyr_babchuk@xxxxxxxx" <volodymyr_babchuk@xxxxxxxx>, Andrew Cooper <andrew.cooper3@xxxxxxxxxx>, George Dunlap <george.dunlap@xxxxxxxxxx>, Jan Beulich <jbeulich@xxxxxxxx>, Wei Liu <wl@xxxxxxx>
  • Delivery-date: Tue, 15 Mar 2022 10:11:06 +0000
  • List-id: Xen developer discussion <xen-devel.lists.xenproject.org>
  • Nodisclaimer: true
  • Original-authentication-results: dkim=none (message not signed) header.d=none;dmarc=none action=none header.from=arm.com;
  • Thread-index: AQHYMyWCd0PyEjstNUKgDSNIsR/0BKzAQ40A
  • Thread-topic: [XEN][RFC PATCH v3 10/14] xen/arm: Implement device tree node removal functionalities

> 
> diff --git a/xen/common/Makefile b/xen/common/Makefile
> index dc8d3a13f5..2eb5734f8e 100644
> --- a/xen/common/Makefile
> +++ b/xen/common/Makefile
> @@ -54,6 +54,7 @@ obj-y += wait.o
> obj-bin-y += warning.init.o
> obj-$(CONFIG_XENOPROF) += xenoprof.o
> obj-y += xmalloc_tlsf.o
> +obj-$(CONFIG_OVERLAY_DTB) += dt_overlay.o

I think the entries are in alphabetical order, this should be added after += 
domain.o

> +/*
> + * overlay_get_nodes_info will get the all node's full name with path. This 
> is
> + * useful when checking node for duplication i.e. dtbo tries to add nodes 
> which
> + * already exists in device tree.
> + */
> +static int overlay_get_nodes_info(const void *fdto, char ***nodes_full_path,
> +                                  unsigned int num_overlay_nodes)
> +{
> +    int fragment;
> +    unsigned int node_num = 0;
> +
> +    *nodes_full_path = xmalloc_bytes(num_overlay_nodes * sizeof(char *));

Here you can use xzalloc_bytes and...

> +
> +    if ( *nodes_full_path == NULL )
> +        return -ENOMEM;
> +    memset(*nodes_full_path, 0x0, num_overlay_nodes * sizeof(char *));

Get rid of this memset

> +
> +/* Remove nodes from dt_host. */
> +static int remove_nodes(char **full_dt_node_path, int **nodes_irq,
> +                        int *node_num_irq, unsigned int num_nodes)
> +{
> +    struct domain *d = hardware_domain;
> +    int rc = 0;
> +    struct dt_device_node *overlay_node;
> +    unsigned int naddr;
> +    unsigned int i, j, nirq;
> +    u64 addr, size;
> +    domid_t domid = 0;
> +
> +    for ( j = 0; j < num_nodes; j++ )
> +    {
> +        dt_dprintk("Finding node %s in the dt_host\n", full_dt_node_path[j]);
> +
> +        overlay_node = dt_find_node_by_path(full_dt_node_path[j]);
> +
> +        if ( overlay_node == NULL )
> +        {
> +            printk(XENLOG_ERR "Device %s is not present in the tree. 
> Removing nodes failed\n",
> +                   full_dt_node_path[j]);
> +            return -EINVAL;
> +        }
> +
> +        domid = dt_device_used_by(overlay_node);
> +
> +        dt_dprintk("Checking if node %s is used by any domain\n",
> +                   full_dt_node_path[j]);
> +
> +        /* Remove the node iff it's assigned to domain 0 or domain io. */
> +        if ( domid != 0 && domid != DOMID_IO )
> +        {
> +            printk(XENLOG_ERR "Device %s as it is being used by domain %d. 
> Removing nodes failed\n",
> +                   full_dt_node_path[j], domid);
> +            return -EINVAL;
> +        }
> +
> +        dt_dprintk("Removing node: %s\n", full_dt_node_path[j]);
> +
> +        nirq = node_num_irq[j];
> +
> +        /* Remove IRQ permission */
> +        for ( i = 0; i < nirq; i++ )
> +        {
> +            rc = nodes_irq[j][i];
> +            /*
> +             * TODO: We don't handle shared IRQs for now. So, it is assumed 
> that
> +             * the IRQs was not shared with another domain.
> +             */
> +            rc = irq_deny_access(d, rc);
> +            if ( rc )
> +            {
> +                printk(XENLOG_ERR "unable to revoke access for irq %u for 
> %s\n",
> +                       i, dt_node_full_name(overlay_node));
> +                return rc;
> +            }
> +        }
> +
> +        rc = iommu_remove_dt_device(overlay_node);
> +        if ( rc != 0 && rc != -ENXIO )
> +            return rc;
> +
> +        naddr = dt_number_of_address(overlay_node);
> +
> +        /* Remove mmio access. */
> +        for ( i = 0; i < naddr; i++ )
> +        {
> +            rc = dt_device_get_address(overlay_node, i, &addr, &size);
> +            if ( rc )
> +            {
> +                printk(XENLOG_ERR "Unable to retrieve address %u for %s\n",
> +                       i, dt_node_full_name(overlay_node));
> +                return rc;
> +            }
> +
> +            rc = iomem_deny_access(d, paddr_to_pfn(addr),
> +                                   paddr_to_pfn(PAGE_ALIGN(addr + size - 
> 1)));
> +            if ( rc )
> +            {
> +                printk(XENLOG_ERR "Unable to remove dom%d access to"
> +                        " 0x%"PRIx64" - 0x%"PRIx64"\n",
> +                        d->domain_id,
> +                        addr & PAGE_MASK, PAGE_ALIGN(addr + size) - 1);

NIT: here in each line under XENLOG_ERR, there is an extra space, these lines
Could be aligned to XENLOG_ERR, just for code style purpose.

> +                return rc;
> +            }
> +        }
> +
> +        rc = dt_overlay_remove_node(overlay_node);
> +        if ( rc )
> +            return rc;
> +    }
> +
> +    return rc;
> +}
> +
> 
> +long dt_sysctl(struct xen_sysctl *op)
> +{
> +    long ret = 0;
> +    void *overlay_fdt;
> +    char **nodes_full_path = NULL;
> +    unsigned int num_overlay_nodes = 0;
> +
> +    if ( op->u.dt_overlay.overlay_fdt_size <= 0 )
> +        return -EINVAL;
> +
> +    overlay_fdt = xmalloc_bytes(op->u.dt_overlay.overlay_fdt_size);
> +
> +    if ( overlay_fdt == NULL )
> +        return -ENOMEM;
> +
> +    ret = copy_from_guest(overlay_fdt, op->u.dt_overlay.overlay_fdt,
> +                         op->u.dt_overlay.overlay_fdt_size);
> +    if ( ret )
> +    {
> +        gprintk(XENLOG_ERR, "copy from guest failed\n");
> +        xfree(overlay_fdt);
> +
> +        return -EFAULT;
> +    }
> +
> +    switch ( op->u.dt_overlay.overlay_op )
> +    {
> +    case XEN_SYSCTL_DT_OVERLAY_REMOVE:
> +        ret = check_overlay_fdt(overlay_fdt,
> +                                op->u.dt_overlay.overlay_fdt_size);
> +        if ( ret )
> +        {
> +            ret = -EFAULT;
> +            break;
> +        }
> +
> +        num_overlay_nodes = overlay_node_count(overlay_fdt);
> +        if ( num_overlay_nodes == 0 )
> +        {
> +            ret = -ENOMEM;
> +            break;
> +        }
> +
> +        ret = overlay_get_nodes_info(overlay_fdt, &nodes_full_path,
> +                                     num_overlay_nodes);
> +        if ( ret )
> +             break;
> +
> +        ret = handle_remove_overlay_nodes(nodes_full_path,
> +                                          num_overlay_nodes);
> +        break;
> +
> +    default:
> +        break;
> +    }
> +
> +    if ( nodes_full_path != NULL )
> +    {
> +        int I;

unsigned int

> +        for ( i = 0; i < num_overlay_nodes && nodes_full_path[i] != NULL; 
> i++ )
> +        {
> +            xfree(nodes_full_path[i]);
> +        }
> +        xfree(nodes_full_path);
> +    }
> +
> +    return ret;
> +}
> diff --git a/xen/common/sysctl.c b/xen/common/sysctl.c
> index fc4a0b31d6..d685c07159 100644
> --- a/xen/common/sysctl.c
> +++ b/xen/common/sysctl.c
> @@ -29,6 +29,10 @@
> #include <xen/livepatch.h>
> #include <xen/coverage.h>
> 
> +#ifdef CONFIG_OVERLAY_DTB
> +#include <xen/dt_overlay.h>
> +#endif

Maybe this header can be included anyway, removing ifdefs, and...

> +
> long cf_check do_sysctl(XEN_GUEST_HANDLE_PARAM(xen_sysctl_t) u_sysctl)
> {
>     long ret = 0;
> @@ -482,6 +486,12 @@ long cf_check 
> do_sysctl(XEN_GUEST_HANDLE_PARAM(xen_sysctl_t) u_sysctl)
>             copyback = 1;
>         break;
> 
> +#ifdef CONFIG_OVERLAY_DTB
> +    case XEN_SYSCTL_overlay:
> +        ret = dt_sysctl(op);
> +        break;
> +#endif

Also here you can remove ifdefs and use the header to switch between the real 
implementation
or a static inline returning error if CONFIG_OVERLAY_DTB is not enabled, take a 
look in
livepatch_op(struct xen_sysctl_livepatch_op *op).

dt_sysctl can take struct xen_sysctl_dt_overlay* as input.

> +
>     default:
>         ret = arch_do_sysctl(op, u_sysctl);
>         copyback = 0;
> diff --git a/xen/include/public/sysctl.h b/xen/include/public/sysctl.h
> index 55252e97f2..e256aeb7c6 100644
> --- a/xen/include/public/sysctl.h
> +++ b/xen/include/public/sysctl.h
> @@ -1069,6 +1069,22 @@ typedef struct xen_sysctl_cpu_policy 
> xen_sysctl_cpu_policy_t;
> DEFINE_XEN_GUEST_HANDLE(xen_sysctl_cpu_policy_t);
> #endif
> 
> +#define XEN_SYSCTL_DT_OVERLAY_REMOVE                2
> +
> +/*
> + * 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.
> + */
> +struct xen_sysctl_dt_overlay {
> +    XEN_GUEST_HANDLE_64(void) overlay_fdt;
> +    uint32_t overlay_fdt_size;  /* Overlay dtb size. */
> +    uint8_t overlay_op; /* Add or remove. */
> +};
> +
> struct xen_sysctl {
>     uint32_t cmd;
> #define XEN_SYSCTL_readconsole                    1
> @@ -1099,6 +1115,7 @@ struct xen_sysctl {
> #define XEN_SYSCTL_livepatch_op                  27
> /* #define XEN_SYSCTL_set_parameter              28 */
> #define XEN_SYSCTL_get_cpu_policy                29
> +#define XEN_SYSCTL_dt_overlay                    30
>     uint32_t interface_version; /* XEN_SYSCTL_INTERFACE_VERSION */
>     union {
>         struct xen_sysctl_readconsole       readconsole;
> @@ -1129,6 +1146,7 @@ struct xen_sysctl {
> #if defined(__i386__) || defined(__x86_64__)
>         struct xen_sysctl_cpu_policy        cpu_policy;
> #endif
> +        struct xen_sysctl_dt_overlay        dt_overlay;

Here I would need an opinion from someone more experienced, but I think when a 
change
is made in this structure, XEN_SYSCTL_INTERFACE_VERSION should be bumped?

>         uint8_t                             pad[128];
>     } u;
> };
> diff --git a/xen/include/xen/dt_overlay.h b/xen/include/xen/dt_overlay.h
> new file mode 100644
> index 0000000000..525818b77c
> --- /dev/null
> +++ b/xen/include/xen/dt_overlay.h
> @@ -0,0 +1,47 @@
> +/*
> + * xen/common/dt_overlay.c

Typo: dt_overlay.h

> + *
> + * Device tree overlay suppoert in Xen.

Typo: support

> + *
> + * Copyright (c) 2021 Xilinx Inc.
> + * Written by Vikram Garhwal <fnu.vikram@xxxxxxxxxx>
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms and conditions of the GNU General Public
> + * License, version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> + * GNU General Public License for more details.
> + */
> +#ifndef __XEN_DT_SYSCTL_H__
> +#define __XEN_DT_SYSCTL_H__
> +
> +#include <xen/list.h>
> +#include <xen/libfdt/libfdt.h>
> +#include <xen/device_tree.h>
> +#include <public/sysctl.h>

In case you decide to pass struct xen_sysctl_dt_overlay to dt_sysctl, you can 
remove
#include <public/sysctl.h> and use a forward declaration to struct 
xen_sysctl_dt_overlay
instead.

> +
> +/*
> + * overlay_node_track describes information about added nodes through dtbo.
> + * @entry: List pointer.
> + * @dt_host_new: Pointer to the updated dt_host_new unflattened 'updated 
> fdt'.
> + * @fdt: Stores the fdt.
> + * @nodes_fullname: Stores the full name of nodes.
> + * @nodes_irq: Stores the IRQ added from overlay dtb.
> + * @node_num_irq: Stores num of IRQ for each node in overlay dtb.
> + * @num_nodes: Stores total number of nodes in overlay dtb.
> + */
> +struct overlay_track {
> +    struct list_head entry;
> +    struct dt_device_node *dt_host_new;
> +    void *fdt;
> +    char **nodes_fullname;
> +    int **nodes_irq;
> +    int *node_num_irq;
> +    unsigned int num_nodes;
> +};
> +
> +long dt_sysctl(struct xen_sysctl *op);
> +#endif
> 




 


Rackspace

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