xen-devel.lists.xenproject.org archive mirror
 help / color / mirror / Atom feed
From: Julien Grall <julien.grall@arm.com>
To: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com>,
	xen-devel@lists.xenproject.org, konrad@kernel.org,
	ross.lagerwall@citrix.com
Cc: Andrew Cooper <andrew.cooper3@citrix.com>, sstabellini@kernel.org
Subject: Re: [PATCH v1 6/9] livepatch: Initial ARM64 support.
Date: Wed, 17 Aug 2016 19:22:54 +0100	[thread overview]
Message-ID: <c544f4fc-3a6d-bca5-e374-061a2cf37ddd@arm.com> (raw)
In-Reply-To: <1471216074-3007-7-git-send-email-konrad.wilk@oracle.com>

Hi Konrad,

On 15/08/16 00:07, Konrad Rzeszutek Wilk wrote:

[...]

> diff --git a/xen/arch/arm/arm64/livepatch.c b/xen/arch/arm/arm64/livepatch.c
> new file mode 100644
> index 0000000..e348942
> --- /dev/null
> +++ b/xen/arch/arm/arm64/livepatch.c
> @@ -0,0 +1,247 @@
> +/*
> + *  Copyright (c) 2016 Oracle and/or its affiliates. All rights reserved.
> + */
> +
> +#include "../livepatch.h"
> +#include <xen/bitops.h>
> +#include <xen/errno.h>
> +#include <xen/lib.h>
> +#include <xen/livepatch_elf.h>
> +#include <xen/livepatch.h>
> +#include <xen/mm.h>
> +#include <xen/vmap.h>
> +
> +#include <asm/bitops.h>
> +#include <asm/byteorder.h>
> +#include <asm/insn.h>
> +
> +void arch_livepatch_apply_jmp(struct livepatch_func *func)
> +{
> +    uint32_t insn;
> +    uint32_t *old_ptr;
> +    uint32_t *new_ptr;
> +
> +    BUILD_BUG_ON(PATCH_INSN_SIZE > sizeof(func->opaque));
> +    BUILD_BUG_ON(PATCH_INSN_SIZE != sizeof(insn));
> +
> +    ASSERT(vmap_of_xen_text);
> +
> +    /* Save old one. */
> +    old_ptr = func->old_addr;
> +    memcpy(func->opaque, old_ptr, PATCH_INSN_SIZE);
> +
> +    if ( func->new_size )
> +        insn = aarch64_insn_gen_branch_imm((unsigned long)func->old_addr,
> +                                           (unsigned long)func->new_addr,
> +                                           AARCH64_INSN_BRANCH_NOLINK);

The function aarch64_insn_gen_branch_imm will fail to create the branch 
if the difference between old_addr and new_addr is greater than 128MB.

In this case, the function will return AARCH64_BREAK_FAULT which will 
crash Xen when the instruction is executed.

I cannot find any sanity check in the hypervisor code. So are we 
trusting the payload?

> +    else
> +        insn = aarch64_insn_gen_nop();
> +
> +    new_ptr = func->old_addr - (void *)_start + vmap_of_xen_text;
> +
> +    /* PATCH! */
> +    *(new_ptr) = cpu_to_le32(insn);
> +
> +    clean_and_invalidate_dcache_va_range(new_ptr, sizeof(*new_ptr));
> +}
> +
> +void arch_livepatch_revert_jmp(const struct livepatch_func *func)
> +{
> +    uint32_t *new_ptr;
> +    uint32_t insn;
> +
> +    memcpy(&insn, func->opaque, PATCH_INSN_SIZE);
> +
> +    new_ptr = (uint32_t *)func->old_addr - (u32 *)_start + vmap_of_xen_text;
> +
> +    /* PATCH! */
> +    *(new_ptr) = cpu_to_le32(insn);
> +
> +    clean_and_invalidate_dcache_va_range(new_ptr, sizeof(*new_ptr));
> +}
> +
> +int arch_livepatch_verify_elf(const struct livepatch_elf *elf)
> +{
> +    const Elf_Ehdr *hdr = elf->hdr;
> +
> +    if ( hdr->e_machine != EM_AARCH64 ||
> +         hdr->e_ident[EI_CLASS] != ELFCLASS64 )
> +    {
> +        dprintk(XENLOG_ERR, LIVEPATCH "%s: Unsupported ELF Machine type!\n",
> +                elf->name);
> +        return -EOPNOTSUPP;
> +    }
> +
> +    return 0;
> +}
> +

[...]

> diff --git a/xen/arch/arm/domain.c b/xen/arch/arm/domain.c
> index 20bb2ba..607ee59 100644
> --- a/xen/arch/arm/domain.c
> +++ b/xen/arch/arm/domain.c
> @@ -13,6 +13,7 @@
>  #include <xen/hypercall.h>
>  #include <xen/init.h>
>  #include <xen/lib.h>
> +#include <xen/livepatch.h>
>  #include <xen/sched.h>
>  #include <xen/softirq.h>
>  #include <xen/wait.h>
> @@ -55,6 +56,11 @@ void idle_loop(void)
>
>          do_tasklet();
>          do_softirq();
> +        /*
> +         * We MUST be last (or before dsb, wfi). Otherwise after we get the
> +         * softirq we would execute dsb,wfi (and sleep) and not patch.
> +         */
> +        check_for_livepatch_work();
>      }
>  }
>
> diff --git a/xen/arch/arm/livepatch.c b/xen/arch/arm/livepatch.c
> index 3093554..19f6033 100644
> --- a/xen/arch/arm/livepatch.c
> +++ b/xen/arch/arm/livepatch.c
> @@ -1,56 +1,93 @@
>  /*
>   *  Copyright (C) 2016 Citrix Systems R&D Ltd.
>   */
> +

Spurious change?

> +#include "livepatch.h"
>  #include <xen/errno.h>
>  #include <xen/init.h>
>  #include <xen/lib.h>
>  #include <xen/livepatch_elf.h>
>  #include <xen/livepatch.h>
> +#include <xen/vmap.h>
> +
> +#include <asm/mm.h>
>
> -/* On ARM32,64 instructions are always 4 bytes long. */
> -#define PATCH_INSN_SIZE 4

Rather than moving again PATCH_INSN_SIZE in this patch. Can you directly 
move it in patch [1]?

> +void *vmap_of_xen_text;
>
>  int arch_verify_insn_length(unsigned long len)
>  {
>      return len != PATCH_INSN_SIZE;
>  }
>
> -void arch_livepatch_quiesce(void)
> +int arch_livepatch_quiesce(void)

It would have been nice to move the prototype change out of this patch 
to keep it "straight forward".

>  {
> +    mfn_t text_mfn;
> +    unsigned int text_order;
> +
> +    if ( vmap_of_xen_text )
> +        return -EINVAL;
> +
> +    text_mfn = _mfn(virt_to_mfn(_stext));
> +    text_order = get_order_from_bytes(_end - _start);

It is a bit odd that you use _stext before and the _start. But I won't 
complain as I did the same in alternatives.c :/.

However, I think it should be enough to remap _stext -> _etext. I had to 
map all the Xen binary for the alternatives because we may patch the 
init text.

I forgot to mention it in the code, so I will send a patch to update it.

> +
> +    /*
> +     * The text section is read-only. So re-map Xen to be able to patch
> +     * the code.
> +     */
> +    vmap_of_xen_text = __vmap(&text_mfn, 1 << text_order, 1, 1, PAGE_HYPERVISOR,
> +                              VMAP_DEFAULT);
> +
> +    if ( !vmap_of_xen_text )
> +    {
> +        printk(XENLOG_ERR LIVEPATCH "Failed to setup vmap of hypervisor! (order=%u)\n",
> +               text_order);
> +        return -ENOMEM;
> +    }
> +    return 0;
>  }
>
>  void arch_livepatch_revive(void)
>  {
> +    /*
> +     * Nuke the instruction cache. It has been cleaned before in

I guess you want to replace "It" by "Data cache" otherwise it does not 
make much sense.

> +     * arch_livepatch_apply_jmp.

What about the payload? It may contain instructions, so we need to 
ensure that all the data reached the memory.

> +     */
> +    invalidate_icache();
> +
> +    if ( vmap_of_xen_text )
> +        vunmap(vmap_of_xen_text);
> +
> +    vmap_of_xen_text = NULL;
> +
> +    /*
> +     * Need to flush the branch predicator for ARMv7 as it may be

s/predicator/predictor/

> +     * architecturally visible to the software (see B2.2.4 in ARM DDI 0406C.b).
> +     */
> +    flush_xen_text_tlb_local();

I am a bit confused. In your comment you mention the branch but flush 
the TLBs. The two are not related.

However, I would prefer the branch predictor to be flushed directly in 
invalidate_icache by calling BPIALLIS. This is because flushing the 
cache means that you likely want to flush the branch predictor too.

>  }
>
>  int arch_livepatch_verify_func(const struct livepatch_func *func)
>  {
> -    return -ENOSYS;
> -}
> -
> -void arch_livepatch_apply_jmp(struct livepatch_func *func)
> -{
> -}
> +    if ( func->old_size < PATCH_INSN_SIZE )
> +        return -EINVAL;
>
> -void arch_livepatch_revert_jmp(const struct livepatch_func *func)
> -{
> +    return 0;
>  }
>
>  void arch_livepatch_post_action(void)
>  {
> +    /* arch_livepatch_revive has nuked the instruction cache. */
>  }
>
>  void arch_livepatch_mask(void)
>  {
> +    /* Mask System Error (SError) */
> +    local_abort_disable();
>  }
>
>  void arch_livepatch_unmask(void)
>  {
> -}
> -
> -int arch_livepatch_verify_elf(const struct livepatch_elf *elf)
> -{
> -    return -ENOSYS;
> +    local_abort_enable();
>  }
>
>  int arch_livepatch_perform_rel(struct livepatch_elf *elf,
> @@ -60,20 +97,34 @@ int arch_livepatch_perform_rel(struct livepatch_elf *elf,
>      return -ENOSYS;
>  }
>
> -int arch_livepatch_perform_rela(struct livepatch_elf *elf,
> -                                const struct livepatch_elf_sec *base,
> -                                const struct livepatch_elf_sec *rela)
> -{
> -    return -ENOSYS;
> -}
> -
>  int arch_livepatch_secure(const void *va, unsigned int pages, enum va_type type)
>  {
> -    return -ENOSYS;
> +    unsigned long start = (unsigned long)va;
> +    unsigned int flags;
> +
> +    ASSERT(va);
> +    ASSERT(pages);
> +
> +    if ( type == LIVEPATCH_VA_RX )
> +        flags = PTE_RO; /* R set, NX clear */
> +    else if ( type == LIVEPATCH_VA_RW )
> +        flags = PTE_NX; /* R clear, NX set */
> +    else
> +        flags = PTE_NX | PTE_RO; /* R set, NX set */

va_type is an enum. So I would prefer to see a switch. So we can catch 
more easily any addition of a new member.

> +
> +    modify_xen_mappings(start, start + pages * PAGE_SIZE, flags);
> +
> +    return 0;
>  }
>
>  void __init arch_livepatch_init(void)
>  {
> +    void *start, *end;
> +
> +    start = (void *)LIVEPATCH_VMAP;
> +    end = start + MB(2);

Could you define the in config.h? So in the future we can rework more 
easily the memory layout.

> +
> +    vm_init_type(VMAP_XEN, start, end);
>  }
>
>  /*
> diff --git a/xen/arch/arm/livepatch.h b/xen/arch/arm/livepatch.h
> new file mode 100644
> index 0000000..8c8d625
> --- /dev/null
> +++ b/xen/arch/arm/livepatch.h

I am not sure why this header is living in arch/arm/ and not 
include/asm-arm/

> @@ -0,0 +1,28 @@
> +/*
> + * Copyright (c) 2016 Oracle and/or its affiliates. All rights reserved.
> + *
> + */
> +
> +#ifndef __XEN_ARM_LIVEPATCH_H__
> +#define __XEN_ARM_LIVEPATCH_H__
> +
> +/* On ARM32,64 instructions are always 4 bytes long. */
> +#define PATCH_INSN_SIZE 4
> +
> +/*
> + * The va of the hypervisor .text region. We need this as the
> + * normal va are write protected.
> + */
> +extern void *vmap_of_xen_text;
> +
> +#endif /* __XEN_ARM_LIVEPATCH_H__ */
> +
> +/*
> + * Local variables:
> + * mode: C
> + * c-file-style: "BSD"
> + * c-basic-offset: 4
> + * tab-width: 4
> + * indent-tabs-mode: nil
> + * End:
> + */
> diff --git a/xen/arch/x86/livepatch.c b/xen/arch/x86/livepatch.c
> index 06c67bc..e3f3f37 100644
> --- a/xen/arch/x86/livepatch.c
> +++ b/xen/arch/x86/livepatch.c
> @@ -15,10 +15,12 @@
>
>  #define PATCH_INSN_SIZE 5
>
> -void arch_livepatch_quiesce(void)
> +int arch_livepatch_quiesce(void)
>  {
>      /* Disable WP to allow changes to read-only pages. */
>      write_cr0(read_cr0() & ~X86_CR0_WP);
> +
> +    return 0;
>  }
>
>  void arch_livepatch_revive(void)
> diff --git a/xen/common/Kconfig b/xen/common/Kconfig
> index 51afa24..2fc76b6 100644
> --- a/xen/common/Kconfig
> +++ b/xen/common/Kconfig
> @@ -222,7 +222,7 @@ endmenu
>  config LIVEPATCH
>  	bool "Live patching support (TECH PREVIEW)"
>  	default n
> -	depends on X86 && HAS_BUILD_ID = "y"
> +	depends on (X86 || ARM_64) && HAS_BUILD_ID = "y"
>  	---help---
>  	  Allows a running Xen hypervisor to be dynamically patched using
>  	  binary patches without rebooting. This is primarily used to binarily
> diff --git a/xen/common/livepatch.c b/xen/common/livepatch.c
> index 9c45270..af9443d 100644
> --- a/xen/common/livepatch.c
> +++ b/xen/common/livepatch.c
> @@ -682,7 +682,7 @@ static int prepare_payload(struct payload *payload,
>                                    sizeof(*region->frame[i].bugs);
>      }
>
> -#ifndef CONFIG_ARM
> +#ifndef CONFIG_ARM_32

I would prefer if you use CONFIG_ALTERNATIVE rather than CONFIG_ARM_32.

>      sec = livepatch_elf_sec_by_name(elf, ".altinstructions");
>      if ( sec )
>      {
> @@ -711,9 +711,15 @@ static int prepare_payload(struct payload *payload,
>                  return -EINVAL;
>              }
>          }
> +#ifndef CONFIG_ARM
>          apply_alternatives_nocheck(start, end);
> +#else
> +        apply_alternatives(start, sec->sec->sh_size);
> +#endif
>      }
> +#endif
>
> +#ifndef CONFIG_ARM
>      sec = livepatch_elf_sec_by_name(elf, ".ex_table");
>      if ( sec )
>      {

Any reason to not move .ex_table in an x86 specific file? Or maybe we 
should define a new config option HAVE_ARCH_EX_TABLE to avoid 
architecture specific check in the common code.

> @@ -1083,12 +1089,17 @@ static int livepatch_list(xen_sysctl_livepatch_list_t *list)
>  static int apply_payload(struct payload *data)
>  {
>      unsigned int i;
> +    int rc;
>
>      printk(XENLOG_INFO LIVEPATCH "%s: Applying %u functions\n",
>              data->name, data->nfuncs);
>
> -    arch_livepatch_quiesce();
> -
> +    rc = arch_livepatch_quiesce();
> +    if ( rc )
> +    {
> +        printk(XENLOG_ERR LIVEPATCH "%s: unable to quiesce!\n", data->name);
> +        return rc;
> +    }
>      /*
>       * Since we are running with IRQs disabled and the hooks may call common
>       * code - which expects the spinlocks to run with IRQs enabled - we temporarly
> @@ -1119,10 +1130,16 @@ static int apply_payload(struct payload *data)
>  static int revert_payload(struct payload *data)
>  {
>      unsigned int i;
> +    int rc;
>
>      printk(XENLOG_INFO LIVEPATCH "%s: Reverting\n", data->name);
>
> -    arch_livepatch_quiesce();
> +    rc = arch_livepatch_quiesce();
> +    if ( rc )
> +    {
> +        printk(XENLOG_ERR LIVEPATCH "%s: unable to quiesce!\n", data->name);
> +        return rc;
> +    }
>
>      for ( i = 0; i < data->nfuncs; i++ )
>          arch_livepatch_revert_jmp(&data->funcs[i]);
> diff --git a/xen/include/asm-arm/config.h b/xen/include/asm-arm/config.h
> index a96f845..8d876f6 100644
> --- a/xen/include/asm-arm/config.h
> +++ b/xen/include/asm-arm/config.h
> @@ -80,9 +80,10 @@
>   *   4M -   6M   Fixmap: special-purpose 4K mapping slots
>   *   6M -   8M   Early boot mapping of FDT
>   *   8M -  10M   Early relocation address (used when relocating Xen)
> + *               and later for livepatch vmap (if compiled in)
>   *
>   * ARM32 layout:
> - *   0  -   8M   <COMMON>
> + *   0  -  10M   <COMMON>

May I ask to have this change and ...

>   *
>   *  32M - 128M   Frametable: 24 bytes per page for 16GB of RAM
>   * 256M -   1G   VMAP: ioremap and early_ioremap use this virtual address
> @@ -93,7 +94,7 @@
>   *
>   * ARM64 layout:
>   * 0x0000000000000000 - 0x0000007fffffffff (512GB, L0 slot [0])
> - *   0  -   8M   <COMMON>
> + *   0  -  10M   <COMMON>

this change in a separate patch to keep this patch livepatch only?

>   *
>   *   1G -   2G   VMAP: ioremap and early_ioremap
>   *
> @@ -113,6 +114,9 @@
>  #define FIXMAP_ADDR(n)        (_AT(vaddr_t,0x00400000) + (n) * PAGE_SIZE)
>  #define BOOT_FDT_VIRT_START    _AT(vaddr_t,0x00600000)
>  #define BOOT_RELOC_VIRT_START  _AT(vaddr_t,0x00800000)
> +#ifdef CONFIG_LIVEPATCH
> +#define LIVEPATCH_VMAP         _AT(vaddr_t,0x00800000)
> +#endif
>
>  #define HYPERVISOR_VIRT_START  XEN_VIRT_START
>
> diff --git a/xen/include/asm-arm/current.h b/xen/include/asm-arm/current.h
> index 65c0cdf..f4fcfd6 100644
> --- a/xen/include/asm-arm/current.h
> +++ b/xen/include/asm-arm/current.h
> @@ -33,8 +33,15 @@ static inline struct cpu_info *get_cpu_info(void)
>
>  #define guest_cpu_user_regs() (&get_cpu_info()->guest_cpu_user_regs)
>
> +#ifdef CONFIG_LIVEPATCH
> +#define switch_stack_and_jump(stack, fn)                                \
> +    asm volatile ("mov sp,%0;"                                          \
> +                  "bl check_for_livepatch_work;"                        \
> +                  "b " STR(fn) : : "r" (stack) : "memory" )
> +#else
>  #define switch_stack_and_jump(stack, fn)                                \
>      asm volatile ("mov sp,%0; b " STR(fn) : : "r" (stack) : "memory" )
> +#endif

I have commented on the previous version about switch_stack_and_jump a 
while after you send this series. So I will spare you new comments here :).

>  #define reset_stack_and_jump(fn) switch_stack_and_jump(get_cpu_info(), fn)
>

[...]

> diff --git a/xen/include/xen/livepatch.h b/xen/include/xen/livepatch.h
> index 2e64686..6f30c0d 100644
> --- a/xen/include/xen/livepatch.h
> +++ b/xen/include/xen/livepatch.h
> @@ -72,7 +72,7 @@ int arch_livepatch_verify_func(const struct livepatch_func *func);
>   * These functions are called around the critical region patching live code,
>   * for an architecture to take make appropratie global state adjustments.
>   */
> -void arch_livepatch_quiesce(void);
> +int arch_livepatch_quiesce(void);
>  void arch_livepatch_revive(void);
>
>  void arch_livepatch_apply_jmp(struct livepatch_func *func);
>

[1] 
https://lists.xenproject.org/archives/html/xen-devel/2016-08/msg01832.html

-- 
Julien Grall

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

  parent reply	other threads:[~2016-08-17 18:23 UTC|newest]

Thread overview: 47+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-08-14 23:07 [PATCH v1] Livepatch ARM 64 implementation Konrad Rzeszutek Wilk
2016-08-14 23:07 ` [PATCH v1 1/9] livepatch: Bubble up sanity checks on Elf relocs Konrad Rzeszutek Wilk
2016-08-17 11:56   ` Jan Beulich
2016-08-14 23:07 ` [PATCH v1 2/9] x86/arm: Make 'make debug' work properly Konrad Rzeszutek Wilk
2016-08-17 12:00   ` Jan Beulich
2016-08-22 17:05     ` Konrad Rzeszutek Wilk
2016-08-14 23:07 ` [PATCH v1 3/9] x86/arm64: Move the ALT_[ORIG|REPL]_PTR macros to header files Konrad Rzeszutek Wilk
2016-08-17 12:15   ` Jan Beulich
2016-08-17 16:26   ` Julien Grall
2016-08-14 23:07 ` [PATCH v1 4/9] arm/mm: Introduce modify_xen_mappings Konrad Rzeszutek Wilk
2016-08-17 16:54   ` Julien Grall
2016-08-14 23:07 ` [PATCH v1 5/9] arm64/insn: introduce aarch64_insn_gen_{nop|branch_imm}() helper functions Konrad Rzeszutek Wilk
2016-08-14 23:07 ` [PATCH v1 6/9] livepatch: Initial ARM64 support Konrad Rzeszutek Wilk
2016-08-15  8:21   ` Jan Beulich
2016-08-15 14:09     ` Konrad Rzeszutek Wilk
2016-08-15 14:23       ` Jan Beulich
2016-08-15 14:57         ` Julien Grall
2016-08-15 15:17           ` Konrad Rzeszutek Wilk
2016-08-15 15:25             ` Julien Grall
2016-08-15 15:27               ` Andrew Cooper
2016-08-17  2:45                 ` Konrad Rzeszutek Wilk
2016-08-17  9:02                   ` Andrew Cooper
2016-08-15 15:17   ` Julien Grall
2016-08-17  1:50     ` Konrad Rzeszutek Wilk
2016-08-17 19:44       ` Julien Grall
2016-08-17 17:12     ` Julien Grall
2016-08-17 18:22   ` Julien Grall [this message]
2016-08-17 18:57     ` Konrad Rzeszutek Wilk
2016-08-17 19:50       ` Julien Grall
2016-08-22 19:22       ` Konrad Rzeszutek Wilk
2016-08-24  2:14     ` Konrad Rzeszutek Wilk
2016-08-25 13:54       ` Julien Grall
2016-08-14 23:07 ` [PATCH v1 7/9] livepatch: ARM64: Ignore mapping symbols: $[a, d, x, p] Konrad Rzeszutek Wilk
2016-08-17 12:21   ` Jan Beulich
2016-08-22 17:14     ` Konrad Rzeszutek Wilk
2016-08-14 23:07 ` [PATCH v1 8/9] livepatch: Move test-cases to common Konrad Rzeszutek Wilk
2016-08-17 12:24   ` Jan Beulich
2016-08-14 23:07 ` [PATCH v1 9/9] livepatch: tests: Make them compile under ARM64 Konrad Rzeszutek Wilk
2016-08-17 18:29   ` Julien Grall
2016-08-17 19:00     ` Konrad Rzeszutek Wilk
2016-08-17 19:57       ` Julien Grall
2016-08-17 20:08         ` Andrew Cooper
2016-08-18 10:38           ` Jan Beulich
2016-08-22 17:41         ` Konrad Rzeszutek Wilk
2016-08-22 19:59       ` Konrad Rzeszutek Wilk
2016-08-15 14:52 ` [PATCH v1] Livepatch ARM 64 implementation Julien Grall
2016-08-15 15:49   ` Konrad Rzeszutek Wilk

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=c544f4fc-3a6d-bca5-e374-061a2cf37ddd@arm.com \
    --to=julien.grall@arm.com \
    --cc=andrew.cooper3@citrix.com \
    --cc=konrad.wilk@oracle.com \
    --cc=konrad@kernel.org \
    --cc=ross.lagerwall@citrix.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).