xen-devel.lists.xenproject.org archive mirror
 help / color / mirror / Atom feed
From: Boqun Feng <boqun.feng@intel.com>
To: xen-devel@lists.xen.org
Cc: "Kevin Tian" <kevin.tian@intel.com>,
	"Stefano Stabellini" <sstabellini@kernel.org>,
	"Wei Liu" <wei.liu2@citrix.com>,
	"Jun Nakajima" <jun.nakajima@intel.com>,
	"George Dunlap" <George.Dunlap@eu.citrix.com>,
	"Andrew Cooper" <andrew.cooper3@citrix.com>,
	"Ian Jackson" <ian.jackson@eu.citrix.com>,
	"Marek Marczykowski-Górecki" <marmarek@invisiblethingslab.com>,
	"Tim Deegan" <tim@xen.org>,
	kai.huang@linux.intel.com, "Julien Grall" <julien.grall@arm.com>,
	"Jan Beulich" <jbeulich@suse.com>,
	"David Scott" <dave@recoil.org>,
	"Boqun Feng" <boqun.feng@intel.com>
Subject: [PATCH v2 11/17] xen: vmx: handle SGX related MSRs
Date: Mon,  4 Dec 2017 08:15:22 +0800	[thread overview]
Message-ID: <20171204001528.1342-12-boqun.feng@intel.com> (raw)
In-Reply-To: <20171204001528.1342-1-boqun.feng@intel.com>

From: Kai Huang <kai.huang@linux.intel.com>

This patch handles IA32_FEATURE_CONTROL and IA32_SGXLEPUBKEYHASHn MSRs.

For IA32_FEATURE_CONTROL, if SGX is exposed to domain, then SGX_ENABLE
bit is always set. The SGX_LE_WR bit is default to be 0, unless 1) the
SGX launch control is exposed to domain and 2) the XL parameter 'lewr'
is true(the handling of this parameter is in a later patch, so for this
patch, SGX_LE_WR bit is always 0).  Write to IA32_FEATURE_CONTROL will
fault.

For IA32_SGXLEPUBKEYHASHn, vcpu's virtual ia32_sgxlepubkeyhash[0-3] are
added in 'sgx' field of 'struct msr_vcpu_policy'.

During vcpu is initialized, virtual ia32_sgxlepubkeyhash are also
initialized. The default values would be the physical values of the
physical machines. Later on, we may reset those values with the content
of the XL parameter 'lehash'. Besides if 'lewr' is true and no 'lehash'
is provided, we will reset those values with Intel's default value, as
for physical machines, those MSRs will have Intel's default value.

For IA32_SGXLEPUBKEYHASHn MSR read from guest, if SGX launch control is
not exposed to domain, guest is not allowed to read either, otherwise
vcpu's virtual MSR value is returned.

For IA32_SGXLEPUBKEYHASHn MSR write from guest, we allow guest to write
if only 'lewr' is set(so for this patch, writes will fault).

To make EINIT run successfully in guest, vcpu's virtual
IA32_SGXLEPUBKEYHASHn will be update to physical MSRs when vcpu is
scheduled in. Moreover, we cache the recent IA32_SGXLEPUBKEYHASHn in a
percpu variable, so that we won't need to update with wrmsr if the value
not changed.

Signed-off-by: Kai Huang <kai.huang@linux.intel.com>
Signed-off-by: Boqun Feng <boqun.feng@intel.com>
---
 xen/arch/x86/domctl.c            |  28 ++++++++-
 xen/arch/x86/hvm/vmx/vmx.c       |  19 ++++++
 xen/arch/x86/msr.c               |   6 +-
 xen/arch/x86/sgx.c               | 123 +++++++++++++++++++++++++++++++++++++++
 xen/include/asm-x86/cpufeature.h |   3 +
 xen/include/asm-x86/msr-index.h  |   5 ++
 xen/include/asm-x86/msr.h        |   5 ++
 xen/include/asm-x86/sgx.h        |   9 +++
 8 files changed, 196 insertions(+), 2 deletions(-)

diff --git a/xen/arch/x86/domctl.c b/xen/arch/x86/domctl.c
index 0ee9fb6458ec..eb5d4b346313 100644
--- a/xen/arch/x86/domctl.c
+++ b/xen/arch/x86/domctl.c
@@ -1352,13 +1352,16 @@ long arch_do_domctl(
 
         ret = -EINVAL;
         if ( (v == curr) || /* no vcpu_pause() */
-             !is_pv_domain(d) )
+             (!is_pv_domain(d) && !d->arch.cpuid->feat.sgx_lc) )
             break;
 
         /* Count maximum number of optional msrs. */
         if ( boot_cpu_has(X86_FEATURE_DBEXT) )
             nr_msrs += 4;
 
+        if ( d->arch.cpuid->feat.sgx_lc )
+            nr_msrs += 5;
+
         if ( domctl->cmd == XEN_DOMCTL_get_vcpu_msrs )
         {
             ret = 0; copyback = true;
@@ -1447,6 +1450,29 @@ long arch_do_domctl(
                     msr.index -= MSR_AMD64_DR1_ADDRESS_MASK - 1;
                     v->arch.pv_vcpu.dr_mask[msr.index] = msr.value;
                     continue;
+                case MSR_IA32_FEATURE_CONTROL:
+                    if ( msr.value & IA32_FEATURE_CONTROL_SGX_LE_WR )
+                    {
+                        if ( d->arch.cpuid->feat.sgx_lc && sgx_lewr())
+                        {
+                            v->arch.msr->sgx.lewr = true;
+                            continue;
+                        }
+                        else /* Try to set LE_WR while not supported */
+                            break;
+                    }
+		    continue;
+                case MSR_IA32_SGXLEPUBKEYHASH0 ... MSR_IA32_SGXLEPUBKEYHASH3:
+                    if ( d->arch.cpuid->feat.sgx_lc && sgx_lewr() )
+                    {
+                        sgx_set_vcpu_sgxlepubkeyhash(v,
+                                msr.index - MSR_IA32_SGXLEPUBKEYHASH0,
+                                msr.value);
+                        continue;
+                    }
+                    else
+                        break;
+		    continue;
                 }
                 break;
             }
diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c
index 92fb85b13a0c..ce1c95f69062 100644
--- a/xen/arch/x86/hvm/vmx/vmx.c
+++ b/xen/arch/x86/hvm/vmx/vmx.c
@@ -1049,6 +1049,9 @@ static void vmx_ctxt_switch_to(struct vcpu *v)
 
     if ( v->domain->arch.hvm_domain.pi_ops.switch_to )
         v->domain->arch.hvm_domain.pi_ops.switch_to(v);
+
+    if ( v->domain->arch.cpuid->feat.sgx_lc && sgx_lewr() )
+        sgx_ctxt_switch_to(v);
 }
 
 
@@ -2892,6 +2895,8 @@ static int is_last_branch_msr(u32 ecx)
 static int vmx_msr_read_intercept(unsigned int msr, uint64_t *msr_content)
 {
     const struct vcpu *curr = current;
+    const struct msr_vcpu_policy *vp = curr->arch.msr;
+    const struct domain *d = current->domain;
 
     HVM_DBG_LOG(DBG_LEVEL_MSR, "ecx=%#x", msr);
 
@@ -2915,11 +2920,19 @@ static int vmx_msr_read_intercept(unsigned int msr, uint64_t *msr_content)
             *msr_content |= IA32_FEATURE_CONTROL_LMCE_ON;
         if ( nestedhvm_enabled(curr->domain) )
             *msr_content |= IA32_FEATURE_CONTROL_ENABLE_VMXON_OUTSIDE_SMX;
+        if ( d->arch.cpuid->feat.sgx )
+            *msr_content |= IA32_FEATURE_CONTROL_SGX_ENABLE;
+        if ( vp->sgx.lewr )
+            *msr_content |= IA32_FEATURE_CONTROL_SGX_LE_WR;
         break;
     case MSR_IA32_VMX_BASIC...MSR_IA32_VMX_VMFUNC:
         if ( !nvmx_msr_read_intercept(msr, msr_content) )
             goto gp_fault;
         break;
+    case MSR_IA32_SGXLEPUBKEYHASH0 ... MSR_IA32_SGXLEPUBKEYHASH3:
+        if ( !sgx_msr_read_intercept(current, msr, msr_content) )
+            goto gp_fault;
+        break;
     case MSR_IA32_MISC_ENABLE:
         rdmsrl(MSR_IA32_MISC_ENABLE, *msr_content);
         /* Debug Trace Store is not supported. */
@@ -3146,6 +3159,12 @@ static int vmx_msr_write_intercept(unsigned int msr, uint64_t msr_content)
     case MSR_IA32_VMX_BASIC ... MSR_IA32_VMX_VMFUNC:
         /* None of these MSRs are writeable. */
         goto gp_fault;
+        break;
+
+    case MSR_IA32_SGXLEPUBKEYHASH0...MSR_IA32_SGXLEPUBKEYHASH3:
+        if ( !sgx_msr_write_intercept(current, msr, msr_content) )
+            goto gp_fault;
+        break;
 
     case MSR_P6_PERFCTR(0)...MSR_P6_PERFCTR(7):
     case MSR_P6_EVNTSEL(0)...MSR_P6_EVNTSEL(7):
diff --git a/xen/arch/x86/msr.c b/xen/arch/x86/msr.c
index baba44f43d05..95cb41b4d825 100644
--- a/xen/arch/x86/msr.c
+++ b/xen/arch/x86/msr.c
@@ -23,6 +23,7 @@
 #include <xen/lib.h>
 #include <xen/sched.h>
 #include <asm/msr.h>
+#include <asm/sgx.h>
 
 struct msr_domain_policy __read_mostly hvm_max_msr_domain_policy,
                          __read_mostly  pv_max_msr_domain_policy;
@@ -112,6 +113,8 @@ int init_vcpu_msr_policy(struct vcpu *v)
     if ( is_control_domain(d) )
         vp->misc_features_enables.available = false;
 
+    sgx_msr_vcpu_init(v, vp);
+
     v->arch.msr = vp;
 
     return 0;
@@ -119,8 +122,9 @@ int init_vcpu_msr_policy(struct vcpu *v)
 
 int guest_rdmsr(const struct vcpu *v, uint32_t msr, uint64_t *val)
 {
-    const struct msr_domain_policy *dp = v->domain->arch.msr;
     const struct msr_vcpu_policy *vp = v->arch.msr;
+    const struct domain *d = v->domain;
+    const struct msr_domain_policy *dp = d->arch.msr;
 
     switch ( msr )
     {
diff --git a/xen/arch/x86/sgx.c b/xen/arch/x86/sgx.c
index 0c898c3086cb..d103eb243e7a 100644
--- a/xen/arch/x86/sgx.c
+++ b/xen/arch/x86/sgx.c
@@ -27,12 +27,15 @@
 #include <asm/sgx.h>
 #include <xen/sched.h>
 #include <asm/p2m.h>
+#include <xen/percpu.h>
 
 struct sgx_cpuinfo __read_mostly boot_sgx_cpudata;
 
 static bool __read_mostly opt_sgx_enabled = false;
 boolean_param("sgx", opt_sgx_enabled);
 
+DEFINE_PER_CPU(uint64_t[4], cpu_ia32_sgxlepubkeyhash);
+
 #define total_epc_npages (boot_sgx_cpudata.epc_size >> PAGE_SHIFT)
 #define epc_base_mfn (boot_sgx_cpudata.epc_base >> PAGE_SHIFT)
 #define epc_base_maddr (boot_sgx_cpudata.epc_base)
@@ -378,6 +381,126 @@ int domain_destroy_epc(struct domain *d)
     return domain_reset_epc(d, true);
 }
 
+/* Digest of Intel signing key. MSR's default value after reset. */
+#define SGX_INTEL_DEFAULT_LEPUBKEYHASH0 0xa6053e051270b7ac
+#define SGX_INTEL_DEFAULT_LEPUBKEYHASH1 0x6cfbe8ba8b3b413d
+#define SGX_INTEL_DEFAULT_LEPUBKEYHASH2 0xc4916d99f2b3735d
+#define SGX_INTEL_DEFAULT_LEPUBKEYHASH3 0xd4f8c05909f9bb3b
+
+void sgx_set_vcpu_sgxlepubkeyhash(struct vcpu *v, int idx, uint64_t val)
+{
+    BUG_ON(idx < 0 || idx > 3);
+
+    v->arch.msr->sgx.ia32_sgxlepubkeyhash[idx] = val;
+}
+
+void sgx_msr_vcpu_init(struct vcpu *v, struct msr_vcpu_policy *vp)
+{
+    const struct domain *d = v->domain;
+
+    /* lewr is default false */
+    vp->sgx.lewr = false;
+
+    if ( d->arch.cpuid->feat.sgx_lc )
+    {
+        if ( sgx_lewr() )
+        {
+            vp->sgx.ia32_sgxlepubkeyhash[0] = SGX_INTEL_DEFAULT_LEPUBKEYHASH0;
+            vp->sgx.ia32_sgxlepubkeyhash[1] = SGX_INTEL_DEFAULT_LEPUBKEYHASH1;
+            vp->sgx.ia32_sgxlepubkeyhash[2] = SGX_INTEL_DEFAULT_LEPUBKEYHASH2;
+            vp->sgx.ia32_sgxlepubkeyhash[3] = SGX_INTEL_DEFAULT_LEPUBKEYHASH3;
+        }
+        else
+        {
+            rdmsrl(MSR_IA32_SGXLEPUBKEYHASH0, vp->sgx.ia32_sgxlepubkeyhash[0]);
+            rdmsrl(MSR_IA32_SGXLEPUBKEYHASH1, vp->sgx.ia32_sgxlepubkeyhash[1]);
+            rdmsrl(MSR_IA32_SGXLEPUBKEYHASH2, vp->sgx.ia32_sgxlepubkeyhash[2]);
+            rdmsrl(MSR_IA32_SGXLEPUBKEYHASH3, vp->sgx.ia32_sgxlepubkeyhash[3]);
+        }
+    }
+}
+
+#define sgx_try_to_write_msr(vp, i)                                     \
+do                                                                      \
+{                                                                       \
+    if ((vp)->sgx.ia32_sgxlepubkeyhash[i] !=                            \
+            this_cpu(cpu_ia32_sgxlepubkeyhash[i]))                      \
+    {                                                                   \
+        wrmsrl(MSR_IA32_SGXLEPUBKEYHASH##i,                             \
+               (vp)->sgx.ia32_sgxlepubkeyhash[i]);                      \
+        this_cpu(cpu_ia32_sgxlepubkeyhash[i]) =                         \
+                    (vp)->sgx.ia32_sgxlepubkeyhash[i];                  \
+    }                                                                   \
+} while (0)
+
+void sgx_ctxt_switch_to(struct vcpu *v)
+{
+    struct msr_vcpu_policy *vp = v->arch.msr;
+
+    sgx_try_to_write_msr(vp, 0);
+    sgx_try_to_write_msr(vp, 1);
+    sgx_try_to_write_msr(vp, 2);
+    sgx_try_to_write_msr(vp, 3);
+}
+
+int sgx_msr_read_intercept(struct vcpu *v, unsigned int msr, u64 *msr_content)
+{
+    const struct msr_vcpu_policy *vp = v->arch.msr;
+    const struct domain *d = v->domain;
+    u64 data;
+    int r = 1;
+
+    if ( !d->arch.cpuid->feat.sgx_lc )
+        return 0;
+
+    switch ( msr )
+    {
+    case MSR_IA32_SGXLEPUBKEYHASH0 ... MSR_IA32_SGXLEPUBKEYHASH3:
+        data = vp->sgx.ia32_sgxlepubkeyhash[msr - MSR_IA32_SGXLEPUBKEYHASH0];
+        *msr_content = data;
+
+        break;
+    default:
+        r = 0;
+        break;
+    }
+
+    return r;
+}
+
+int sgx_msr_write_intercept(struct vcpu *v, unsigned int msr, u64 msr_content)
+{
+    struct msr_vcpu_policy *vp = v->arch.msr;
+    const struct domain *d = v->domain;
+    int r = 1;
+
+    /*
+     * SDM 35.1 Model-Specific Registers, table 35-2.
+     *
+     * IA32_SGXLEPUBKEYHASH[0..3]:
+     *
+     * - If CPUID.0x7.0:ECX[30] = 1, FEATURE_CONTROL[17] is available.
+     * - Write permitted if CPUID.0x12.0:EAX[0] = 1 &&
+     *      FEATURE_CONTROL[17] = 1 && FEATURE_CONTROL[0] = 1.
+     */
+    if ( !d->arch.cpuid->feat.sgx_lc || !vp->sgx.lewr )
+        return 0;
+
+    switch ( msr )
+    {
+    case MSR_IA32_SGXLEPUBKEYHASH0...MSR_IA32_SGXLEPUBKEYHASH3:
+        vp->sgx.ia32_sgxlepubkeyhash[msr - MSR_IA32_SGXLEPUBKEYHASH0] =
+            msr_content;
+
+        break;
+    default:
+        r = 0;
+        break;
+    }
+
+    return r;
+}
+
 static void __detect_sgx(struct sgx_cpuinfo *sgxinfo)
 {
     u32 eax, ebx, ecx, edx;
diff --git a/xen/include/asm-x86/cpufeature.h b/xen/include/asm-x86/cpufeature.h
index 9793f8c1c586..f15deb535871 100644
--- a/xen/include/asm-x86/cpufeature.h
+++ b/xen/include/asm-x86/cpufeature.h
@@ -98,6 +98,9 @@
 #define cpu_has_smap            boot_cpu_has(X86_FEATURE_SMAP)
 #define cpu_has_sha             boot_cpu_has(X86_FEATURE_SHA)
 
+/* CPUID level 0x00000007:0.ecx */
+#define cpu_has_sgx_lc          boot_cpu_has(X86_FEATURE_SGX_LC)
+
 /* CPUID level 0x80000007.edx */
 #define cpu_has_itsc            boot_cpu_has(X86_FEATURE_ITSC)
 
diff --git a/xen/include/asm-x86/msr-index.h b/xen/include/asm-x86/msr-index.h
index 63e11931cd09..004e0fb249d5 100644
--- a/xen/include/asm-x86/msr-index.h
+++ b/xen/include/asm-x86/msr-index.h
@@ -300,6 +300,11 @@
 #define IA32_FEATURE_CONTROL_LMCE_ON                  0x100000
 #define IA32_FEATURE_CONTROL_SGX_LE_WR                0x20000
 
+#define MSR_IA32_SGXLEPUBKEYHASH0   0x0000008c
+#define MSR_IA32_SGXLEPUBKEYHASH1   0x0000008d
+#define MSR_IA32_SGXLEPUBKEYHASH2   0x0000008e
+#define MSR_IA32_SGXLEPUBKEYHASH3   0x0000008f
+
 #define MSR_IA32_TSC_ADJUST		0x0000003b
 
 #define MSR_IA32_APICBASE		0x0000001b
diff --git a/xen/include/asm-x86/msr.h b/xen/include/asm-x86/msr.h
index 751fa25a3694..e255a28f7fec 100644
--- a/xen/include/asm-x86/msr.h
+++ b/xen/include/asm-x86/msr.h
@@ -220,6 +220,11 @@ struct msr_vcpu_policy
         bool available; /* This MSR is non-architectural */
         bool cpuid_faulting;
     } misc_features_enables;
+
+    struct {
+        bool lewr;
+        uint64_t ia32_sgxlepubkeyhash[4];
+    } sgx;
 };
 
 void init_guest_msr_policy(void);
diff --git a/xen/include/asm-x86/sgx.h b/xen/include/asm-x86/sgx.h
index 855e7e638743..97ca5dd5b1ef 100644
--- a/xen/include/asm-x86/sgx.h
+++ b/xen/include/asm-x86/sgx.h
@@ -24,6 +24,7 @@
 #include <xen/types.h>
 #include <xen/init.h>
 #include <asm/processor.h>
+#include <asm/msr.h>
 #include <public/hvm/params.h>   /* HVM_PARAM_SGX */
 
 #define SGX_CPUID 0x12
@@ -59,6 +60,8 @@ void detect_sgx(struct sgx_cpuinfo *sgxinfo);
 void disable_sgx(void);
 #define sgx_lewr() (boot_sgx_cpudata.lewr)
 
+DECLARE_PER_CPU(uint64_t[4], cpu_ia32_sgxlepubkeyhash);
+
 struct page_info *alloc_epc_page(void);
 void free_epc_page(struct page_info *epg);
 
@@ -74,4 +77,10 @@ int domain_populate_epc(struct domain *d, unsigned long epc_base_pfn,
 int domain_reset_epc(struct domain *d, bool free_epc);
 int domain_destroy_epc(struct domain *d);
 
+void sgx_set_vcpu_sgxlepubkeyhash(struct vcpu *v, int idx, uint64_t val);
+void sgx_ctxt_switch_to(struct vcpu *v);
+void sgx_msr_vcpu_init(struct vcpu *v, struct msr_vcpu_policy *vp);
+int sgx_msr_read_intercept(struct vcpu *v, unsigned int msr, u64 *msr_content);
+int sgx_msr_write_intercept(struct vcpu *v, unsigned int msr, u64 msr_content);
+
 #endif  /* __ASM_X86_SGX_H__ */
-- 
2.15.0


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

  parent reply	other threads:[~2017-12-04  0:15 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-12-04  0:15 [RFC PATCH v2 00/17] RFC: SGX Virtualization design and draft patches Boqun Feng
2017-12-04  0:15 ` [PATCH v2 01/17] xen: x86: expose SGX to HVM domain in CPU featureset Boqun Feng
2017-12-04 11:13   ` Julien Grall
2017-12-04 13:10     ` Boqun Feng
2017-12-04 14:13       ` Jan Beulich
2017-12-05  0:22         ` Boqun Feng
2017-12-04  0:15 ` [PATCH v2 02/17] xen: x86: add early stage SGX feature detection Boqun Feng
2017-12-04  0:15 ` [PATCH v2 03/17] xen: vmx: detect ENCLS VMEXIT Boqun Feng
2017-12-04  0:15 ` [PATCH v2 04/17] xen: x86/mm: introduce ioremap_wb() Boqun Feng
2017-12-04  0:15 ` [PATCH v2 05/17] xen: p2m: new 'p2m_epc' type for EPC mapping Boqun Feng
2017-12-04  0:15 ` [PATCH v2 06/17] xen: mm: introduce non-scrubbable pages Boqun Feng
2017-12-04  0:15 ` [PATCH v2 07/17] xen: mm: manage EPC pages in Xen heaps Boqun Feng
2017-12-04  0:15 ` [PATCH v2 08/17] xen: x86/mm: add SGX EPC management Boqun Feng
2017-12-04  0:15 ` [PATCH v2 09/17] xen: x86: add functions to populate and destroy EPC for domain Boqun Feng
2017-12-04  0:15 ` [PATCH v2 10/17] xen: x86: add SGX cpuid handling support Boqun Feng
2017-12-04  0:15 ` Boqun Feng [this message]
2017-12-04  0:15 ` [PATCH v2 12/17] xen: vmx: handle ENCLS VMEXIT Boqun Feng
2017-12-04  0:15 ` [PATCH v2 13/17] xen: vmx: handle VMEXIT from SGX enclave Boqun Feng
2017-12-04  0:15 ` [PATCH v2 14/17] xen: x86: reset EPC when guest got suspended Boqun Feng
2017-12-04  0:15 ` [PATCH v2 15/17] xen: tools: add new 'sgx' parameter support Boqun Feng
2017-12-04  0:15 ` [PATCH v2 16/17] xen: tools: add SGX to applying CPUID policy Boqun Feng
2017-12-04  0:15 ` [PATCH v2 17/17] xen: tools: add SGX to applying MSR policy Boqun Feng
2017-12-25  5:01 ` [RFC PATCH v2 00/17] RFC: SGX Virtualization design and draft patches Boqun Feng

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=20171204001528.1342-12-boqun.feng@intel.com \
    --to=boqun.feng@intel.com \
    --cc=George.Dunlap@eu.citrix.com \
    --cc=andrew.cooper3@citrix.com \
    --cc=dave@recoil.org \
    --cc=ian.jackson@eu.citrix.com \
    --cc=jbeulich@suse.com \
    --cc=julien.grall@arm.com \
    --cc=jun.nakajima@intel.com \
    --cc=kai.huang@linux.intel.com \
    --cc=kevin.tian@intel.com \
    --cc=marmarek@invisiblethingslab.com \
    --cc=sstabellini@kernel.org \
    --cc=tim@xen.org \
    --cc=wei.liu2@citrix.com \
    --cc=xen-devel@lists.xen.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).