xen-devel.lists.xenproject.org archive mirror
 help / color / mirror / Atom feed
From: Julien Grall <julien.grall@arm.com>
To: Bhupinder Thakur <bhupinder.thakur@linaro.org>,
	xen-devel@lists.xenproject.org
Cc: nd@arm.com, Stefano Stabellini <sstabellini@kernel.org>
Subject: Re: [PATCH 01/11] xen/arm: vpl011: Add pl011 uart emulation in Xen
Date: Sun, 5 Mar 2017 12:12:06 +0000	[thread overview]
Message-ID: <0f555eb4-c131-0469-44b6-ffa67e2d8537@arm.com> (raw)
In-Reply-To: <1487676368-22356-2-git-send-email-bhupinder.thakur@linaro.org>

Hi Bhupinder,

On 21/02/17 11:25, Bhupinder Thakur wrote:
> diff --git a/xen/arch/arm/vpl011.c b/xen/arch/arm/vpl011.c
> new file mode 100644
> index 0000000..88ba968
> --- /dev/null
> +++ b/xen/arch/arm/vpl011.c

[...]

> +static int vpl011_mmio_write(struct vcpu *v, mmio_info_t *info, register_t r, void *priv)

See my comment on the vpl011_mmio_read about the structure of the function.

> +{
> +    unsigned char ch = r;
> +
> +    switch (info->gpa - GUEST_PL011_BASE)
> +    {
> +        case VPL011_UARTCR_OFFSET:

This register is not required in the SBSA UART.

> +            v->domain->arch.vpl011.control = r;
> +            break;
> +        case VPL011_UARTDR_OFFSET:
> +            vpl011_write_data(v->domain, ch);

The implicit casting of register_t to ch is a bit confusing. Also I 
would prefer to use uint8_t as it reflects the size of the field.

Lastly, what if vpl011_write_data is returning an error?

> +            break;
> +        case VPL011_UARTIMSC_OFFSET:
> +            v->domain->arch.vpl011.intr_mask = r;

You need to sanitize the value written and make sure reserved field and 
Write As Ones register and handle correctly (see the spec).

> +            if ( (v->domain->arch.vpl011.raw_intr_status & v->domain->arch.vpl011.intr_mask) )

This line and the line below are over 80 columns. Also the code in 
general would benefits if you define a local variable to point to 
v->domain->arch.vpl011.

> +                vgic_vcpu_inject_spi(v->domain, (int)v->domain->arch.hvm_domain.params[HVM_PARAM_VPL011_VIRQ]);

I don't think we need an HVM_PARAM for the pl011 SPI. We cannot hardcode 
this in the guest layout (see include/public/arch-arm.h).

> +            break;
> +        case VPL011_UARTICR_OFFSET:
> +            /*
> +             * clear all bits which are set in the input
> +             */
> +            v->domain->arch.vpl011.raw_intr_status &= ~r;
> +            if ( (v->domain->arch.vpl011.raw_intr_status & v->domain->arch.vpl011.intr_mask) )
> +            {

{ } are not necessary.

> +                vgic_vcpu_inject_spi(v->domain, (int)v->domain->arch.hvm_domain.params[HVM_PARAM_VPL011_VIRQ]);
> +            }

The if is exactly the same as the on in IMSC. This is the call of an 
helper to check the interrupt state and inject one if necessary.

> +            break;
> +        case VPL011_UARTRSR_OFFSET: // nothing to clear

The coding style for single line comment in Xen is /* ... */

Also, I think we may want to handle Overrun error as the ring may be full.

> +            break;
> +        case VPL011_UARTFR_OFFSET: // these are all RO registers
> +        case VPL011_UARTRIS_OFFSET:
> +        case VPL011_UARTMIS_OFFSET:
> +        case VPL011_UARTDMACR_OFFSET:

Please have a look at the vGICv2/vGICv3 emulation see how we implemented 
write ignore register.

> +            break;
> +        default:
> +            printk ("vpl011_mmio_write: switch case not handled %d\n", (int)(info->gpa - GUEST_PL011_BASE));

See my comment about the prinkt in the read emulation.

> +            break;
> +    }
> +
> +    return VPL011_EMUL_OK;
> +}
> +
> +static const struct mmio_handler_ops vpl011_mmio_handler = {
> +    .read = vpl011_mmio_read,
> +    .write = vpl011_mmio_write,
> +};
> +
> +
> +

Only newline is sufficient. This was mention by Konrad and I will try to 
avoid repeating his comments.

> +int vpl011_map_guest_page(struct domain *d)
> +{
> +    int rc=0;
> +
> +    /*
> +     * map the guest PFN to Xen address space
> +     */
> +    rc = prepare_ring_for_helper(d,
> +                                 d->arch.hvm_domain.params[HVM_PARAM_VPL011_CONSOLE_PFN],
> +                                 &d->arch.vpl011.ring_page,
> +                                 (void **)&d->arch.vpl011.ring_buf);

Why do you need the cast?

Also I cannot find any code in this series which destroy the ring. 
Please have a helper called vpl011_unmap_guest_page to do this job and 
call when the domain is destroyed.

> +    if ( rc < 0 )
> +    {
> +        printk("Failed to map vpl011 guest PFN\n");
> +    }
> +
> +    return rc;
> +}
> +
> +static int vpl011_data_avail(struct domain *d)
> +{
> +    int rc=0;
> +    unsigned long flags;
> +
> +    struct console_interface *intf=(struct console_interface *)d->arch.vpl011.ring_buf;
> +
> +    VPL011_LOCK(d, flags);
> +
> +    /*`
> +     * check IN ring buffer
> +     */
> +    if ( !VPL011_IN_RING_EMPTY(intf) )
> +    {
> +        /*
> +         * clear the RX FIFO empty flag as the ring is not empty
> +         */
> +        d->arch.vpl011.flag &= ~(VPL011_UARTFR_RXFE);
> +
> +        /*
> +         * if the buffer is full then set the RX FIFO FULL flag
> +         */
> +        if ( VPL011_IN_RING_FULL(intf) )
> +            d->arch.vpl011.flag |= (VPL011_UARTFR_RXFF);
> +
> +        /*
> +         * set the RX interrupt status
> +         */
> +        d->arch.vpl011.raw_intr_status |= (VPL011_UARTRIS_RXRIS);
> +    }
> +
> +    /*
> +     * check OUT ring buffer
> +     */
> +    if ( !VPL011_OUT_RING_FULL(intf) )
> +    {
> +        /*
> +         * if the buffer is not full then clear the TX FIFO full flag
> +         */
> +        d->arch.vpl011.flag &= ~(VPL011_UARTFR_TXFF);
> +
> +        /*
> +         * set the TX interrupt status
> +         */
> +        d->arch.vpl011.raw_intr_status |= (VPL011_UARTRIS_TXRIS);
> +
> +        if ( VPL011_OUT_RING_EMPTY(intf) )
> +        {
> +            /*
> +             * clear the uart busy flag and set the TX FIFO empty flag
> +             */
> +            d->arch.vpl011.flag &= ~(VPL011_UARTFR_BUSY);
> +            d->arch.vpl011.flag |= (VPL011_UARTFR_TXFE);
> +        }
> +    }
> +
> +    VPL011_UNLOCK(d, flags);
> +
> +    /*
> +     * send an interrupt if it is not masked
> +     */
> +    if ( (d->arch.vpl011.raw_intr_status & d->arch.vpl011.intr_mask) )
> +        vgic_vcpu_inject_spi(d, (int)d->arch.hvm_domain.params[HVM_PARAM_VPL011_VIRQ]);

See my comment above about having an helper for this code.

> +
> +    if ( !VPL011_OUT_RING_EMPTY(intf) )
> +    {
> +        /*
> +         * raise an interrupt to dom0

The backend console does not necessarily live in DOM0. Anyway, Konrad 
requested to drop the comment and I am happy with that.

> +         */
> +        rc = raw_evtchn_send(d,
> +                    d->arch.hvm_domain.params[HVM_PARAM_VPL011_CONSOLE_EVTCHN], NULL);

You are using a function that is been defined in a later patch (i.w #3). 
All the patch should be able to compile without applying upcoming patch 
to allow bisection.

Ideally, Xen should still be functional for every patch. But it is a 
best effort.

> +
> +        if ( rc < 0 )
> +            printk("Failed to send vpl011 interrupt to dom0\n");
> +    }
> +
> +    return rc;
> +}
> +
> +int vpl011_read_data(struct domain *d, unsigned char *data)

This function does not seem to be used outside of this file. So why do 
you export it?

> +{
> +    int rc=0;
> +    unsigned long flags;
> +    struct console_interface *intf=(struct console_interface *)d->arch.vpl011.ring_buf;
> +
> +    *data = 0;
> +
> +    VPL011_LOCK(d, flags);
> +
> +    /*
> +     * if there is data in the ring buffer then copy it to the output buffer
> +     */
> +    if ( !VPL011_IN_RING_EMPTY(intf) )
> +    {
> +        *data = intf->in[MASK_VPL011CONS_IDX(intf->in_cons++, intf->in)];
> +    }
> +
> +    /*
> +     * if the ring buffer is empty then set the RX FIFO empty flag
> +     */
> +    if ( VPL011_IN_RING_EMPTY(intf) )
> +    {
> +        d->arch.vpl011.flag |= (VPL011_UARTFR_RXFE);
> +        d->arch.vpl011.raw_intr_status &= ~(VPL011_UARTRIS_RXRIS);
> +    }
> +
> +    /*
> +     * clear the RX FIFO full flag
> +     */
> +    d->arch.vpl011.flag &= ~(VPL011_UARTFR_RXFF);
> +
> +    VPL011_UNLOCK(d, flags);
> +
> +    return rc;
> +}
> +
> +int vpl011_write_data(struct domain *d, unsigned char data)

Same has for vpl011_read_data.

> +{
> +    int rc=0;
> +    unsigned long flags;
> +    struct console_interface *intf=(struct console_interface *)d->arch.vpl011.ring_buf;
> +
> +    VPL011_LOCK(d, flags);
> +
> +    /*
> +     * if there is space in the ring buffer then write the data
> +     */
> +    if ( !VPL011_OUT_RING_FULL(intf) )
> +    {
> +        intf->out[MASK_VPL011CONS_IDX(intf->out_prod++, intf->out)] = data;
> +        smp_wmb();
> +    }
> +
> +    /*
> +     * if there is no space in the ring buffer then set the
> +     * TX FIFO FULL flag
> +     */
> +    if ( VPL011_OUT_RING_FULL(intf) )
> +    {
> +        d->arch.vpl011.flag |= (VPL011_UARTFR_TXFF);
> +        d->arch.vpl011.raw_intr_status &= ~(VPL011_UARTRIS_TXRIS);
> +    }
> +
> +    /*
> +     * set the uart busy status
> +     */
> +    d->arch.vpl011.flag |= (VPL011_UARTFR_BUSY);
> +
> +    /*
> +     * clear the TX FIFO empty flag
> +     */
> +    d->arch.vpl011.flag &= ~(VPL011_UARTFR_TXFE);
> +
> +    VPL011_UNLOCK(d, flags);
> +
> +    /*
> +     * raise an event to dom0 only if it is the first character in the buffer
> +     */
> +    if ( VPL011_RING_DEPTH(intf, out) == 1 )
> +    {
> +        rc = raw_evtchn_send(d,
> +                d->arch.hvm_domain.params[HVM_PARAM_VPL011_CONSOLE_EVTCHN], NULL);
> +
> +        if ( rc < 0 )
> +            printk("Failed to send vpl011 interrupt to dom0\n");
> +    }
> +
> +    return rc;
> +}
> +
> +static void vpl011_notification(struct vcpu *v, unsigned int port)
> +{
> +    vpl011_data_avail(v->domain);

vpl011_data_avail is returning an error but you don't check. What is the 
point of it then?

> +}
> +
> +int domain_vpl011_init(struct domain *d)

I was expected a destroy function to clean-up the vpl011 emulation.

> +{
> +    int rc=0;
> +
> +    /*
> +     * register xen event channel
> +     */
> +    rc = alloc_unbound_xen_event_channel(d, 0, current->domain->domain_id,
> +                                                        vpl011_notification);

This line looks wrong to me. The console backend may not live in the 
same domain as the toolstack.

> +    if (rc < 0)
> +    {
> +        printk ("Failed to allocate vpl011 event channel\n");
> +        return rc;
> +    }
> +    d->arch.hvm_domain.params[HVM_PARAM_VPL011_CONSOLE_EVTCHN] = rc;
> +
> +    /*
> +     * allocate an SPI VIRQ for the guest
> +     */
> +    d->arch.hvm_domain.params[HVM_PARAM_VPL011_VIRQ] = vgic_allocate_spi(d);

It makes little sense to hardcode the MMIO region and not the SPI. Also, 
I would rather avoid to introduce new HVM_PARAM when not necessary. So 
hardcoding the value looks more sensible to me.

> +
> +    /*
> +     * register mmio handler
> +     */
> +    register_mmio_handler (d, &vpl011_mmio_handler, GUEST_PL011_BASE, GUEST_PL011_SIZE, NULL);

Coding style. No space between the function name and (.

> +
> +    /*
> +     * initialize the lock
> +     */
> +    spin_lock_init(&d->arch.vpl011.lock);
> +
> +    /*
> +     * clear the flag, control and interrupt status registers
> +     */
> +    d->arch.vpl011.control = 0;
> +    d->arch.vpl011.flag = 0;
> +    d->arch.vpl011.intr_mask = 0;
> +    d->arch.vpl011.intr_clear = 0;
> +    d->arch.vpl011.raw_intr_status = 0;
> +    d->arch.vpl011.masked_intr_status = 0;


The domain structure is already zeroed. So no need to 0 it again.

> +
> +    return 0;
> +}

Missing e-macs magic here.

> diff --git a/xen/arch/arm/vpl011.h b/xen/arch/arm/vpl011.h
> new file mode 100644
> index 0000000..f2c577f
> --- /dev/null
> +++ b/xen/arch/arm/vpl011.h

Header should live in include.

[...]

> +#ifndef _VPL011_H_
> +
> +#define _VPL011_H_
> +
> +/*
> + * register offsets
> + */

We already define the PL011 register in include/asm-arm/pl011-uart.h. 
Please re-use them rather than re-inventing the wheel.

> +#define VPL011_UARTDR_OFFSET    0x0 // data register (RW)
> +#define VPL011_UARTRSR_OFFSET   0x4 // receive status and error clear register (RW)
> +#define VPL011_UARTFR_OFFSET    0x18 // flag register (RO)
> +#define VPL011_UARTRIS_OFFSET   0x3c // raw interrupt status register (RO)
> +#define VPL011_UARTMIS_OFFSET   0x40 // masked interrupt status register (RO)
> +#define VPL011_UARTIMSC_OFFSET  0x38 // interrupt mask set/clear register (RW)
> +#define VPL011_UARTICR_OFFSET   0x44 // interrupt clear register (WO)
> +#define VPL011_UARTCR_OFFSET    0x30 // uart control register
> +#define VPL011_UARTDMACR_OFFSET 0x48 // uart dma control register


[...]

> +#define MASK_VPL011CONS_IDX(idx, ring) ((idx) & (sizeof(ring)-1))
> +struct console_interface {
> +    char in[1024];
> +    char out[2048];
> +    uint32_t in_cons, in_prod;
> +    uint32_t out_cons, out_prod;
> +};
> +#endif

The communication between Xen and the console backend is based on the PV 
console ring. It would be easier to re-use it rather than recreating one.

> diff --git a/xen/common/Kconfig b/xen/common/Kconfig
> index f2ecbc4..7e2feac 100644
> --- a/xen/common/Kconfig
> +++ b/xen/common/Kconfig
> @@ -237,4 +237,10 @@ config FAST_SYMBOL_LOOKUP
>  	  The only user of this is Live patching.
>
>  	  If unsure, say Y.
> +
> +config VPL011_CONSOLE
> +	bool "Emulated pl011 console support"
> +	default y
> +	---help---
> +	  Allows a guest to use pl011 UART as a console
>  endmenu

This should go in arch/arm/Kconfig

> diff --git a/xen/include/asm-arm/domain.h b/xen/include/asm-arm/domain.h
> index 2d6fbb1..ff2403a 100644
> --- a/xen/include/asm-arm/domain.h
> +++ b/xen/include/asm-arm/domain.h
> @@ -40,6 +40,7 @@ struct vtimer {
>          uint64_t cval;
>  };
>
> +

Spurious line.

>  struct arch_domain
>  {
>  #ifdef CONFIG_ARM_64
> @@ -131,6 +132,20 @@ struct arch_domain
>      struct {
>          uint8_t privileged_call_enabled : 1;
>      } monitor;
> +
> +#ifdef CONFIG_VPL011_CONSOLE
> +    struct vpl011 {
> +        void *ring_buf;
> +        struct page_info *ring_page;
> +        uint32_t    flag;               /* flag register */
> +        uint32_t    control;            /* control register */
> +        uint32_t    intr_mask;          /* interrupt mask register*/
> +        uint32_t    intr_clear;         /* interrupt clear register */
> +        uint32_t    raw_intr_status;    /* raw interrupt status register */
> +        uint32_t    masked_intr_status; /* masked interrupt register */
> +        spinlock_t  lock;
> +    } vpl011;
> +#endif

I think the structure should be defined in vpl011.h.

>  }  __cacheline_aligned;
>
>  struct arch_vcpu
> diff --git a/xen/include/public/arch-arm.h b/xen/include/public/arch-arm.h
> index bd974fb..1d4548f 100644
> --- a/xen/include/public/arch-arm.h
> +++ b/xen/include/public/arch-arm.h
> @@ -410,6 +410,10 @@ typedef uint64_t xen_callback_t;
>  #define GUEST_ACPI_BASE 0x20000000ULL
>  #define GUEST_ACPI_SIZE 0x02000000ULL
>
> +/* PL011 mappings */
> +#define GUEST_PL011_BASE    0x22000000ULL
> +#define GUEST_PL011_SIZE    0x00001000ULL
> +
>  /*
>   * 16MB == 4096 pages reserved for guest to use as a region to map its
>   * grant table in.
> @@ -420,6 +424,7 @@ typedef uint64_t xen_callback_t;
>  #define GUEST_MAGIC_BASE  xen_mk_ullong(0x39000000)
>  #define GUEST_MAGIC_SIZE  xen_mk_ullong(0x01000000)
>
> +

Spurious line.

>  #define GUEST_RAM_BANKS   2
>
>  #define GUEST_RAM0_BASE   xen_mk_ullong(0x40000000) /* 3GB of low RAM @ 1GB */
>

Cheers,

-- 
Julien Grall

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

  parent reply	other threads:[~2017-03-05 12:12 UTC|newest]

Thread overview: 82+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-02-21 11:25 [PATCH 00/11] pl011 emulation support in Xen Bhupinder Thakur
2017-02-21 11:25 ` [PATCH 01/11] xen/arm: vpl011: Add pl011 uart emulation " Bhupinder Thakur
2017-02-26 21:37   ` Julien Grall
2017-03-03 19:19     ` Julien Grall
2017-03-21 13:27     ` Bhupinder Thakur
2017-03-21 19:38       ` Julien Grall
2017-03-23  9:44         ` Bhupinder Thakur
2017-03-23 13:51           ` Julien Grall
2017-03-03 19:59   ` Konrad Rzeszutek Wilk
2017-03-05  1:04     ` Julien Grall
2017-03-06 14:22       ` Konrad Rzeszutek Wilk
2017-03-05  1:15     ` Julien Grall
2017-03-05 11:59     ` Julien Grall
2017-03-22  5:50     ` Bhupinder Thakur
2017-03-05 12:12   ` Julien Grall [this message]
2017-03-23  9:14     ` Bhupinder Thakur
2017-03-23 14:16       ` Julien Grall
2017-03-24 10:39         ` Bhupinder Thakur
2017-02-21 11:25 ` [PATCH 02/11] xen/arm: vpl011: Add new hvm params in Xen for ring buffer/event setup Bhupinder Thakur
2017-03-03 20:02   ` Konrad Rzeszutek Wilk
2017-03-24  6:58     ` Bhupinder Thakur
2017-03-05 12:35   ` Julien Grall
2017-03-06  8:06     ` Jan Beulich
2017-03-06 11:42       ` Julien Grall
2017-03-06 12:41         ` Jan Beulich
2017-03-06 13:21           ` Julien Grall
2017-03-06 13:48             ` Jan Beulich
2017-03-08 14:45               ` Julien Grall
2017-03-08 15:21                 ` Jan Beulich
2017-03-08 18:22                   ` Stefano Stabellini
2017-04-11 14:38                     ` Bhupinder Thakur
2017-04-11 22:07                       ` Stefano Stabellini
2017-04-14  7:12                         ` Bhupinder Thakur
2017-04-19 18:43                           ` Stefano Stabellini
2017-03-06 14:48             ` George Dunlap
2017-03-08 13:52               ` Julien Grall
2017-03-24  7:31     ` Bhupinder Thakur
2017-02-21 11:26 ` [PATCH 03/11] xen/arm: vpl011: Refactor evtchn_send in Xen to allow sending events from a xen bound channel Bhupinder Thakur
2017-03-03 21:13   ` Konrad Rzeszutek Wilk
2017-03-06 10:16     ` Bhupinder Thakur
2017-03-06 10:35       ` Jan Beulich
2017-03-05 12:39   ` Julien Grall
2017-03-06  8:15     ` Jan Beulich
2017-03-06 10:44       ` Bhupinder Thakur
2017-03-06 10:54         ` Jan Beulich
2017-03-06 11:12           ` Bhupinder Thakur
2017-03-28  9:43             ` Bhupinder Thakur
2017-02-21 11:26 ` [PATCH 04/11] xen/arm: vpl011: Enable vpl011 emulation for a domain in Xen Bhupinder Thakur
2017-03-03 21:47   ` Konrad Rzeszutek Wilk
2017-03-05 12:46   ` Julien Grall
2017-03-06  8:27     ` Jan Beulich
2017-02-21 11:26 ` [PATCH 05/11] xen/arm: vpl011: Initialize nr_spis in vgic_init in Xen to atleast 1 Bhupinder Thakur
2017-03-03 20:49   ` Konrad Rzeszutek Wilk
2017-03-05 12:51   ` Julien Grall
2017-03-16  6:50     ` Bhupinder Thakur
2017-03-16  8:24       ` Julien Grall
2017-03-16 10:31         ` Bhupinder Thakur
2017-03-16 13:24           ` Julien Grall
2017-03-20 16:29             ` Bhupinder Thakur
2017-02-21 11:26 ` [PATCH 06/11] xen/arm: vpl011: Add a new pl011 uart node in the guest DT in the toolstack Bhupinder Thakur
2017-03-03 20:15   ` Konrad Rzeszutek Wilk
2017-03-03 21:03   ` Konrad Rzeszutek Wilk
2017-03-05 12:59     ` Julien Grall
2017-03-05 13:04   ` Julien Grall
2017-03-14 13:00     ` Wei Liu
2017-02-21 11:26 ` [PATCH 07/11] xen/arm: vpl011: Add two new vpl011 parameters to xenstore Bhupinder Thakur
2017-03-03 20:58   ` Konrad Rzeszutek Wilk
2017-03-28  7:49     ` Bhupinder Thakur
2017-02-21 11:26 ` [PATCH 08/11] xen/arm: vpl011: Allocate a new PFN in the toolstack and pass to Xen using a hvm call Bhupinder Thakur
2017-03-03 20:51   ` Konrad Rzeszutek Wilk
2017-03-05 13:07     ` Julien Grall
2017-02-21 11:26 ` [PATCH 09/11] xen/arm: vpl011: Modify domain_create_ring in xenconsole to map the ring buffer and event channel Bhupinder Thakur
2017-03-03 21:46   ` Konrad Rzeszutek Wilk
2017-02-21 11:26 ` [PATCH 10/11] xen/arm: vpl011: Modify handle_ring_read and buffer_append to read/append vpl011 data Bhupinder Thakur
2017-03-03 21:06   ` Konrad Rzeszutek Wilk
2017-02-21 11:26 ` [PATCH 11/11] xen/arm: vpl011: Modify handle_tty_read in xenconsole to redirect user data to vpl011 IN ring buffer Bhupinder Thakur
2017-03-03 21:17   ` Konrad Rzeszutek Wilk
2017-03-03 20:23 ` [PATCH 00/11] pl011 emulation support in Xen Konrad Rzeszutek Wilk
2017-03-03 21:15   ` Konrad Rzeszutek Wilk
2017-03-14  7:44   ` Bhupinder Thakur
2017-03-05 11:46 ` Julien Grall
2017-03-14  7:47   ` Bhupinder Thakur

Reply instructions:

You may reply publicly 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=0f555eb4-c131-0469-44b6-ffa67e2d8537@arm.com \
    --to=julien.grall@arm.com \
    --cc=bhupinder.thakur@linaro.org \
    --cc=nd@arm.com \
    --cc=sstabellini@kernel.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
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).