Xen-Devel Archive on lore.kernel.org
 help / color / Atom feed
From: Stefano Stabellini <sstabellini@kernel.org>
To: Volodymyr Babchuk <Volodymyr_Babchuk@epam.com>
Cc: Stefano Stabellini <sstabellini@kernel.org>, Wei Liu <wl@xen.org>,
	Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>,
	George Dunlap <George.Dunlap@eu.citrix.com>,
	Andrew Cooper <andrew.cooper3@citrix.com>,
	Ian Jackson <ian.jackson@eu.citrix.com>, Tim Deegan <tim@xen.org>,
	"tee-dev@lists.linaro.org" <tee-dev@lists.linaro.org>,
	Julien Grall <julien.grall@arm.com>,
	"xen-devel@lists.xenproject.org" <xen-devel@lists.xenproject.org>
Subject: Re: [Xen-devel] [PATCH v6 01/10] xen/arm: add generic TEE mediator framework
Date: Mon, 17 Jun 2019 09:11:14 -0700 (PDT)
Message-ID: <alpine.DEB.2.21.1906170911040.2072@sstabellini-ThinkPad-T480s> (raw)
In-Reply-To: <20190611184541.7281-2-volodymyr_babchuk@epam.com>

On Tue, 11 Jun 2019, Volodymyr Babchuk wrote:
> This patch adds basic framework for TEE mediators. Guests can't talk
> to TEE directly, we need some entity that will intercept request
> and decide what to do with them. "TEE mediator" is a such entity.
> 
> This is how it works: user can build XEN with multiple TEE mediators
> (see the next patches, where OP-TEE mediator is introduced).
> TEE mediator register self with REGISTER_TEE_MEDIATOR() macro in the
> same way, as device drivers use DT_DEVICE_START()/DT_DEVICE_END()
> macros.
> 
> At run-time, during initialization, framework calls probe() function
> for each available mediator driver to find which TEE is installed
> on the platform. Then generic vSMC handler will call selected mediator
> when it intercept SMC/HVC that belongs to TEE OS or TEE application.
> 
> Signed-off-by: Volodymyr Babchuk <volodymyr_babchuk@epam.com>
> Reviewed-by: Julien Grall <julien.grall@arm.com>

Acked-by: Stefano Stabellini <sstabellini@kernel.org>


> ---
> Changes from v5:
>   - Fixed bug, when XEN won't boot with CONFIG_TEE=n
>   - Fixed coding style
>   - Added __read_mostly attribute to *cur_mediator variable
> 
> Changes from v4:
>   - Added tee_get_type() function, which returns id of currently
>     available TEE
>   - Removed "dom0_tee_enabled" command line option. Dom0 now always
>     uses currently available TEE.
>   - Added TEE type sanity check in arch_sanitise_domain_config()
>   - tee_domain_init() now internally checks if requested TEE type
>     corresponds to available TEE
>   - removed tee_domain_destroy() function because it is not used
>     by anyone
> 
> Changes from v3:
> 
>   - tee_enable() renamed to tee_domain_init()
>   - Added tee_relinquish_resources() function along with
>     changes to domain_relinquish_resources()
>   - Added command-line parameter dom0_tee_enabled, which controls
>     if tee is enabled for Dom0. It is disabled by default
>   - Instead of boolean tee state (enabled/disabled) I introduced
>     enumeration with two values: none or native. It is possible
>     to add other types of tee in the future
> 
> Changes from v2:
>   - Removed empty tee/Kconfig file
> 
>  Changes from v1:
>   - Removed tee_remove() function
>   - CONFIG_TEE depends on EXPERT
>   - tee_domain_created() converted to tee_enable()
>   - tee_init() is called using initcall() mechanism
>   - tee_handle_smc() renamed to tee_handle_call()
> 
>  Changes from "RFC" version:
>   - renamed CONFIG_ARM_TEE to CONFIG_TEE
>   - changed discovery mechanism: instead of UUID mathing, TEE-specific
>      probing is used
> ---
>  MAINTAINERS                   |   6 ++
>  xen/arch/arm/Kconfig          |   7 +++
>  xen/arch/arm/Makefile         |   1 +
>  xen/arch/arm/domain.c         |  18 ++++++
>  xen/arch/arm/setup.c          |   2 +
>  xen/arch/arm/tee/Makefile     |   1 +
>  xen/arch/arm/tee/tee.c        |  98 +++++++++++++++++++++++++++++
>  xen/arch/arm/vsmc.c           |   5 ++
>  xen/arch/arm/xen.lds.S        |   7 +++
>  xen/include/asm-arm/domain.h  |   1 +
>  xen/include/asm-arm/tee/tee.h | 112 ++++++++++++++++++++++++++++++++++
>  xen/include/public/arch-arm.h |   5 ++
>  12 files changed, 263 insertions(+)
>  create mode 100644 xen/arch/arm/tee/Makefile
>  create mode 100644 xen/arch/arm/tee/tee.c
>  create mode 100644 xen/include/asm-arm/tee/tee.h
> 
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 6fbdc2bdcb..ab32e7f409 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -381,6 +381,12 @@ F:	config/Stubdom.mk.in
>  F:	m4/stubdom.m4
>  F:	stubdom/
>  
> +TEE MEDIATORS
> +M:	Volodymyr Babchuk <volodymyr_babchuk@epam.com>
> +S:	Supported
> +F:	xen/arch/arm/tee/
> +F:	xen/include/asm-arm/tee
> +
>  TOOLSTACK
>  M:	Ian Jackson <ian.jackson@eu.citrix.com>
>  M:	Wei Liu <wl@xen.org>
> diff --git a/xen/arch/arm/Kconfig b/xen/arch/arm/Kconfig
> index 585b57f023..caaf377a33 100644
> --- a/xen/arch/arm/Kconfig
> +++ b/xen/arch/arm/Kconfig
> @@ -106,6 +106,13 @@ config HARDEN_BRANCH_PREDICTOR
>  
>  	  If unsure, say Y.
>  
> +config TEE
> +	bool "Enable TEE mediators support" if EXPERT = "y"
> +	default n
> +	help
> +	  This option enables generic TEE mediators support. It allows guests
> +	  to access real TEE via one of TEE mediators implemented in XEN.
> +
>  endmenu
>  
>  menu "ARM errata workaround via the alternative framework"
> diff --git a/xen/arch/arm/Makefile b/xen/arch/arm/Makefile
> index cb902cb6fe..5c2aa34557 100644
> --- a/xen/arch/arm/Makefile
> +++ b/xen/arch/arm/Makefile
> @@ -5,6 +5,7 @@ subdir-$(CONFIG_ACPI) += acpi
>  ifneq ($(CONFIG_NO_PLAT),y)
>  subdir-y += platforms
>  endif
> +subdir-$(CONFIG_TEE) += tee
>  
>  obj-$(CONFIG_HAS_ALTERNATIVE) += alternative.o
>  obj-y += bootfdt.init.o
> diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c
> index ad1b106bd7..d27a137f7a 100644
> --- a/xen/arch/arm/domain.c
> +++ b/xen/arch/arm/domain.c
> @@ -32,6 +32,7 @@
>  #include <asm/platform.h>
>  #include <asm/procinfo.h>
>  #include <asm/regs.h>
> +#include <asm/tee/tee.h>
>  #include <asm/vfp.h>
>  #include <asm/vgic.h>
>  #include <asm/vtimer.h>
> @@ -647,6 +648,12 @@ int arch_sanitise_domain_config(struct xen_domctl_createdomain *config)
>          return -EINVAL;
>      }
>  
> +    if ( config->arch.tee_type != XEN_DOMCTL_CONFIG_TEE_NONE )
> +    {
> +        dprintk(XENLOG_INFO, "Unsupported TEE type\n");
> +        return -EINVAL;
> +    }
> +
>      return 0;
>  }
>  
> @@ -704,6 +711,9 @@ int arch_domain_create(struct domain *d,
>      if ( (rc = domain_vtimer_init(d, &config->arch)) != 0 )
>          goto fail;
>  
> +    if ( (rc = tee_domain_init(d, config->arch.tee_type)) != 0 )
> +        goto fail;
> +
>      update_domain_wallclock_time(d);
>  
>      /*
> @@ -948,6 +958,14 @@ int domain_relinquish_resources(struct domain *d)
>           */
>          domain_vpl011_deinit(d);
>  
> +        d->arch.relmem = RELMEM_tee;
> +        /* Fallthrough */
> +
> +    case RELMEM_tee:
> +        ret = tee_relinquish_resources(d);
> +        if (ret )
> +            return ret;
> +
>          d->arch.relmem = RELMEM_xen;
>          /* Fallthrough */
>  
> diff --git a/xen/arch/arm/setup.c b/xen/arch/arm/setup.c
> index 5af49c7a08..1643f91f1c 100644
> --- a/xen/arch/arm/setup.c
> +++ b/xen/arch/arm/setup.c
> @@ -49,6 +49,7 @@
>  #include <asm/platform.h>
>  #include <asm/procinfo.h>
>  #include <asm/setup.h>
> +#include <asm/tee/tee.h>
>  #include <xsm/xsm.h>
>  #include <asm/acpi.h>
>  
> @@ -894,6 +895,7 @@ void __init start_xen(unsigned long boot_phys_offset,
>      dom0_cfg.arch.nr_spis = min(gic_number_lines(), (unsigned int) 992) - 32;
>      if ( gic_number_lines() > 992 )
>          printk(XENLOG_WARNING "Maximum number of vGIC IRQs exceeded.\n");
> +    dom0_cfg.arch.tee_type = tee_get_type();
>      dom0_cfg.max_vcpus = dom0_max_vcpus();
>  
>      dom0 = domain_create(0, &dom0_cfg, true);
> diff --git a/xen/arch/arm/tee/Makefile b/xen/arch/arm/tee/Makefile
> new file mode 100644
> index 0000000000..c54d4796ff
> --- /dev/null
> +++ b/xen/arch/arm/tee/Makefile
> @@ -0,0 +1 @@
> +obj-y += tee.o
> diff --git a/xen/arch/arm/tee/tee.c b/xen/arch/arm/tee/tee.c
> new file mode 100644
> index 0000000000..3964a8a5cd
> --- /dev/null
> +++ b/xen/arch/arm/tee/tee.c
> @@ -0,0 +1,98 @@
> +/*
> + * xen/arch/arm/tee/tee.c
> + *
> + * Generic part of TEE mediator subsystem
> + *
> + * Volodymyr Babchuk <volodymyr_babchuk@epam.com>
> + * Copyright (c) 2018-2019 EPAM Systems.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms 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.
> + */
> +
> +#include <xen/errno.h>
> +#include <xen/init.h>
> +#include <xen/types.h>
> +
> +#include <asm/tee/tee.h>
> +
> +extern const struct tee_mediator_desc _steemediator[], _eteemediator[];
> +static const struct tee_mediator_desc __read_mostly *cur_mediator;
> +
> +/*
> + * TODO: Add function to alter Dom0 DTB, so we can properly describe
> + * present TEE.
> + */
> +
> +bool tee_handle_call(struct cpu_user_regs *regs)
> +{
> +    if ( unlikely(!cur_mediator) )
> +        return false;
> +
> +    return cur_mediator->ops->handle_call(regs);
> +}
> +
> +int tee_domain_init(struct domain *d, uint16_t tee_type)
> +{
> +    if ( tee_type == XEN_DOMCTL_CONFIG_TEE_NONE )
> +        return 0;
> +
> +    if ( !cur_mediator )
> +        return -ENODEV;
> +
> +    if ( cur_mediator->tee_type != tee_type )
> +        return -EINVAL;
> +
> +    return cur_mediator->ops->domain_init(d);
> +}
> +
> +int tee_relinquish_resources(struct domain *d)
> +{
> +    if ( !cur_mediator )
> +        return 0;
> +
> +    return cur_mediator->ops->relinquish_resources(d);
> +}
> +
> +uint16_t tee_get_type(void)
> +{
> +    if ( !cur_mediator )
> +        return XEN_DOMCTL_CONFIG_TEE_NONE;
> +
> +    return cur_mediator->tee_type;
> +}
> +
> +
> +static int __init tee_init(void)
> +{
> +    const struct tee_mediator_desc *desc;
> +
> +    for ( desc = _steemediator; desc != _eteemediator; desc++ )
> +    {
> +        if ( desc->ops->probe() )
> +        {
> +            printk(XENLOG_INFO "Using TEE mediator for %s\n", desc->name);
> +            cur_mediator = desc;
> +            return 0;
> +        }
> +    }
> +
> +    return 0;
> +}
> +
> +__initcall(tee_init);
> +
> +/*
> + * Local variables:
> + * mode: C
> + * c-file-style: "BSD"
> + * c-basic-offset: 4
> + * indent-tabs-mode: nil
> + * End:
> + */
> diff --git a/xen/arch/arm/vsmc.c b/xen/arch/arm/vsmc.c
> index c72b9a04ff..f8e350311d 100644
> --- a/xen/arch/arm/vsmc.c
> +++ b/xen/arch/arm/vsmc.c
> @@ -23,6 +23,7 @@
>  #include <asm/monitor.h>
>  #include <asm/regs.h>
>  #include <asm/smccc.h>
> +#include <asm/tee/tee.h>
>  #include <asm/traps.h>
>  #include <asm/vpsci.h>
>  #include <asm/platform.h>
> @@ -276,6 +277,10 @@ static bool vsmccc_handle_call(struct cpu_user_regs *regs)
>          case ARM_SMCCC_OWNER_SIP:
>              handled = platform_smc(regs);
>              break;
> +        case ARM_SMCCC_OWNER_TRUSTED_APP ... ARM_SMCCC_OWNER_TRUSTED_APP_END:
> +        case ARM_SMCCC_OWNER_TRUSTED_OS ... ARM_SMCCC_OWNER_TRUSTED_OS_END:
> +            handled = tee_handle_call(regs);
> +            break;
>          }
>      }
>  
> diff --git a/xen/arch/arm/xen.lds.S b/xen/arch/arm/xen.lds.S
> index 1e72906477..e664c4441a 100644
> --- a/xen/arch/arm/xen.lds.S
> +++ b/xen/arch/arm/xen.lds.S
> @@ -137,6 +137,13 @@ SECTIONS
>        _aedevice = .;
>    } :text
>  
> +  . = ALIGN(8);
> +  .teemediator.info : {
> +      _steemediator = .;
> +      *(.teemediator.info)
> +      _eteemediator = .;
> +  } :text
> +
>    . = ALIGN(PAGE_SIZE);             /* Init code and data */
>    __init_begin = .;
>    .init.text : {
> diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h
> index 312fec8932..0f15372098 100644
> --- a/xen/include/asm-arm/domain.h
> +++ b/xen/include/asm-arm/domain.h
> @@ -58,6 +58,7 @@ struct arch_domain
>      /* Continuable domain_relinquish_resources(). */
>      enum {
>          RELMEM_not_started,
> +        RELMEM_tee,
>          RELMEM_xen,
>          RELMEM_page,
>          RELMEM_mapping,
> diff --git a/xen/include/asm-arm/tee/tee.h b/xen/include/asm-arm/tee/tee.h
> new file mode 100644
> index 0000000000..f483986385
> --- /dev/null
> +++ b/xen/include/asm-arm/tee/tee.h
> @@ -0,0 +1,112 @@
> +/*
> + * xen/include/asm-arm/tee/tee.h
> + *
> + * Generic part of TEE mediator subsystem
> + *
> + * Volodymyr Babchuk <volodymyr_babchuk@epam.com>
> + * Copyright (c) 2018 EPAM Systems.
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License version 2 as
> + * published by the Free Software Foundation.
> + */
> +
> +#ifndef __ARCH_ARM_TEE_TEE_H__
> +#define __ARCH_ARM_TEE_TEE_H__
> +
> +#include <xen/lib.h>
> +#include <xen/types.h>
> +
> +#include <asm/regs.h>
> +
> +#ifdef CONFIG_TEE
> +
> +struct tee_mediator_ops {
> +    /*
> +     * Probe for TEE. Should return true if TEE found and
> +     * mediator is initialized.
> +     */
> +    bool (*probe)(void);
> +
> +    /*
> +     * Called during domain construction if toolstack requests to enable
> +     * TEE support so mediator can inform TEE about new
> +     * guest and create own structures for the new domain.
> +     */
> +    int (*domain_init)(struct domain *d);
> +
> +    /*
> +     * Called during domain destruction to relinquish resources used
> +     * by mediator itself. This function can return -ERESTART to indicate
> +     * that it does not finished work and should be called again.
> +     */
> +    int (*relinquish_resources)(struct domain *d);
> +
> +    /* Handle SMCCC call for current domain. */
> +    bool (*handle_call)(struct cpu_user_regs *regs);
> +};
> +
> +struct tee_mediator_desc {
> +    /* Printable name of the TEE. */
> +    const char *name;
> +
> +    /* Mediator callbacks as described above. */
> +    const struct tee_mediator_ops *ops;
> +
> +    /*
> +     * ID of TEE. Corresponds to xen_arch_domainconfig.tee_type.
> +     * Should be one of XEN_DOMCTL_CONFIG_TEE_xxx
> +     */
> +    uint16_t tee_type;
> +};
> +
> +bool tee_handle_call(struct cpu_user_regs *regs);
> +int tee_domain_init(struct domain *d, uint16_t tee_type);
> +int tee_relinquish_resources(struct domain *d);
> +uint16_t tee_get_type(void);
> +
> +#define REGISTER_TEE_MEDIATOR(_name, _namestr, _type, _ops)         \
> +static const struct tee_mediator_desc __tee_desc_##_name __used     \
> +__section(".teemediator.info") = {                                  \
> +    .name = _namestr,                                               \
> +    .ops = _ops,                                                    \
> +    .tee_type = _type                                               \
> +}
> +
> +#else
> +
> +static inline bool tee_handle_call(struct cpu_user_regs *regs)
> +{
> +    return false;
> +}
> +
> +static inline int tee_domain_init(struct domain *d, uint16_t tee_type)
> +{
> +    if ( likely(tee_type == XEN_DOMCTL_CONFIG_TEE_NONE) )
> +        return 0;
> +
> +    return -ENODEV;
> +}
> +
> +static inline int tee_relinquish_resources(struct domain *d)
> +{
> +    return 0;
> +}
> +
> +static inline uint16_t tee_get_type(void)
> +{
> +    return XEN_DOMCTL_CONFIG_TEE_NONE;
> +}
> +
> +#endif  /* CONFIG_TEE */
> +
> +#endif /* __ARCH_ARM_TEE_TEE_H__ */
> +
> +/*
> + * Local variables:
> + * mode: C
> + * c-file-style: "BSD"
> + * c-basic-offset: 4
> + * indent-tabs-mode: nil
> + * End:
> + */
> diff --git a/xen/include/public/arch-arm.h b/xen/include/public/arch-arm.h
> index eb424e8286..bb69c380ec 100644
> --- a/xen/include/public/arch-arm.h
> +++ b/xen/include/public/arch-arm.h
> @@ -304,10 +304,15 @@ DEFINE_XEN_GUEST_HANDLE(vcpu_guest_context_t);
>  #define XEN_DOMCTL_CONFIG_GIC_NATIVE    0
>  #define XEN_DOMCTL_CONFIG_GIC_V2        1
>  #define XEN_DOMCTL_CONFIG_GIC_V3        2
> +
> +#define XEN_DOMCTL_CONFIG_TEE_NONE      0
> +
>  struct xen_arch_domainconfig {
>      /* IN/OUT */
>      uint8_t gic_version;
>      /* IN */
> +    uint16_t tee_type;
> +    /* IN */
>      uint32_t nr_spis;
>      /*
>       * OUT
> -- 
> 2.21.0
> 

_______________________________________________
Xen-devel mailing list
Xen-devel@lists.xenproject.org
https://lists.xenproject.org/mailman/listinfo/xen-devel

  reply index

Thread overview: 30+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-06-11 18:46 [Xen-devel] [PATCH v6 00/10] TEE mediator (and OP-TEE) support in XEN Volodymyr Babchuk
2019-06-11 18:46 ` [Xen-devel] [PATCH v6 01/10] xen/arm: add generic TEE mediator framework Volodymyr Babchuk
2019-06-17 16:11   ` Stefano Stabellini [this message]
2019-06-11 18:46 ` [Xen-devel] [PATCH v6 02/10] xen/arm: optee: add OP-TEE header files Volodymyr Babchuk
2019-06-15 18:39   ` Julien Grall
2019-06-17 15:24     ` Julien Grall
2019-06-17 16:28       ` Stefano Stabellini
2019-06-17 16:34         ` Julien Grall
2019-06-17 17:28           ` Stefano Stabellini
2019-06-19  8:20             ` Lars Kurth
2019-06-19 10:26               ` Julien Grall
2019-06-11 18:46 ` [Xen-devel] [PATCH v6 03/10] xen/arm: optee: add OP-TEE mediator skeleton Volodymyr Babchuk
2019-06-19 11:01   ` Julien Grall
2019-06-19 11:03     ` Julien Grall
2019-06-19 15:44       ` Volodymyr Babchuk
2019-06-11 18:46 ` [Xen-devel] [PATCH v6 04/10] xen/arm: optee: add fast calls handling Volodymyr Babchuk
2019-06-11 18:46 ` [Xen-devel] [PATCH v6 05/10] xen/arm: optee: add std call handling Volodymyr Babchuk
2019-06-11 18:46 ` [Xen-devel] [PATCH v6 06/10] xen/arm: optee: add support for RPC SHM buffers Volodymyr Babchuk
2019-06-11 18:46 ` [Xen-devel] [PATCH v6 07/10] xen/arm: optee: add support for arbitrary shared memory Volodymyr Babchuk
2019-06-11 18:46 ` [Xen-devel] [PATCH v6 08/10] xen/arm: optee: add support for RPC commands Volodymyr Babchuk
2019-06-11 18:46 ` [Xen-devel] [PATCH v6 09/10] tools/arm: tee: add "tee" option for xl.cfg Volodymyr Babchuk
2019-06-15 19:10   ` Julien Grall
2019-06-18 11:19     ` Volodymyr Babchuk
2019-06-18 12:49       ` Julien Grall
2019-06-18 14:30         ` Volodymyr Babchuk
2019-06-18 15:19           ` Julien Grall
2019-06-18 15:23             ` Volodymyr Babchuk
2019-06-19 10:30               ` Julien Grall
2019-06-11 18:46 ` [Xen-devel] [PATCH v6 10/10] tools/arm: optee: create optee firmware node in DT if tee=optee Volodymyr Babchuk
2019-06-19 11:08 ` [Xen-devel] [PATCH v6 00/10] TEE mediator (and OP-TEE) support in XEN Julien Grall

Reply instructions:

You may reply publically to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=alpine.DEB.2.21.1906170911040.2072@sstabellini-ThinkPad-T480s \
    --to=sstabellini@kernel.org \
    --cc=George.Dunlap@eu.citrix.com \
    --cc=Volodymyr_Babchuk@epam.com \
    --cc=andrew.cooper3@citrix.com \
    --cc=ian.jackson@eu.citrix.com \
    --cc=julien.grall@arm.com \
    --cc=konrad.wilk@oracle.com \
    --cc=tee-dev@lists.linaro.org \
    --cc=tim@xen.org \
    --cc=wl@xen.org \
    --cc=xen-devel@lists.xenproject.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

Xen-Devel Archive on lore.kernel.org

Archives are clonable:
	git clone --mirror https://lore.kernel.org/xen-devel/0 xen-devel/git/0.git
	git clone --mirror https://lore.kernel.org/xen-devel/1 xen-devel/git/1.git

	# If you have public-inbox 1.1+ installed, you may
	# initialize and index your mirror using the following commands:
	public-inbox-init -V2 xen-devel xen-devel/ https://lore.kernel.org/xen-devel \
		xen-devel@lists.xenproject.org xen-devel@lists.xen.org xen-devel@archiver.kernel.org
	public-inbox-index xen-devel

Example config snippet for mirrors

Newsgroup available over NNTP:
	nntp://nntp.lore.kernel.org/org.xenproject.lists.xen-devel


AGPL code for this site: git clone https://public-inbox.org/ public-inbox