diff mbox

[03/15] xen: x86: add early stage SGX feature detection

Message ID c3fe7a4996cd1fc44e71da62ae72b54df1488cb7.1499586046.git.kai.huang@linux.intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

Kai Huang July 9, 2017, 8:09 a.m. UTC
This patch adds early stage SGX feature detection via SGX CPUID 0x12. Function
detect_sgx is added to detect SGX info on each CPU (called from vmx_cpu_up).
SDM says SGX info returned by CPUID is per-thread, and we cannot assume all
threads will return the same SGX info, so we have to detect SGX for each CPU.
For simplicity, currently SGX is only supported when all CPUs reports the same
SGX info.

SDM also says it's possible to have multiple EPC sections but this is only for
multiple-socket server, which we don't support now (there are other things
need to be done, ex, NUMA EPC, scheduling, etc, as well), so currently only
one EPC is supported.

Dedicated files sgx.c and sgx.h are added (under vmx directory as SGX is Intel
specific) for bulk of above SGX detection code detection code, and for further
SGX code as well.

Signed-off-by: Kai Huang <kai.huang@linux.intel.com>
---
 xen/arch/x86/hvm/vmx/Makefile     |   1 +
 xen/arch/x86/hvm/vmx/sgx.c        | 208 ++++++++++++++++++++++++++++++++++++++
 xen/arch/x86/hvm/vmx/vmcs.c       |   4 +
 xen/include/asm-x86/cpufeature.h  |   1 +
 xen/include/asm-x86/hvm/vmx/sgx.h |  45 +++++++++
 5 files changed, 259 insertions(+)
 create mode 100644 xen/arch/x86/hvm/vmx/sgx.c
 create mode 100644 xen/include/asm-x86/hvm/vmx/sgx.h

Comments

Andrew Cooper July 19, 2017, 2:23 p.m. UTC | #1
On 09/07/17 09:09, Kai Huang wrote:
> This patch adds early stage SGX feature detection via SGX CPUID 0x12. Function
> detect_sgx is added to detect SGX info on each CPU (called from vmx_cpu_up).
> SDM says SGX info returned by CPUID is per-thread, and we cannot assume all
> threads will return the same SGX info, so we have to detect SGX for each CPU.
> For simplicity, currently SGX is only supported when all CPUs reports the same
> SGX info.
>
> SDM also says it's possible to have multiple EPC sections but this is only for
> multiple-socket server, which we don't support now (there are other things
> need to be done, ex, NUMA EPC, scheduling, etc, as well), so currently only
> one EPC is supported.
>
> Dedicated files sgx.c and sgx.h are added (under vmx directory as SGX is Intel
> specific) for bulk of above SGX detection code detection code, and for further
> SGX code as well.
>
> Signed-off-by: Kai Huang <kai.huang@linux.intel.com>

I am not sure putting this under hvm/ is a sensible move.  Almost
everything in this patch is currently common, and I can forsee us
wanting to introduce PV support, so it would be good to introduce this
in a guest-neutral location to begin with.

> ---
>  xen/arch/x86/hvm/vmx/Makefile     |   1 +
>  xen/arch/x86/hvm/vmx/sgx.c        | 208 ++++++++++++++++++++++++++++++++++++++
>  xen/arch/x86/hvm/vmx/vmcs.c       |   4 +
>  xen/include/asm-x86/cpufeature.h  |   1 +
>  xen/include/asm-x86/hvm/vmx/sgx.h |  45 +++++++++
>  5 files changed, 259 insertions(+)
>  create mode 100644 xen/arch/x86/hvm/vmx/sgx.c
>  create mode 100644 xen/include/asm-x86/hvm/vmx/sgx.h
>
> diff --git a/xen/arch/x86/hvm/vmx/Makefile b/xen/arch/x86/hvm/vmx/Makefile
> index 04a29ce59d..f6bcf0d143 100644
> --- a/xen/arch/x86/hvm/vmx/Makefile
> +++ b/xen/arch/x86/hvm/vmx/Makefile
> @@ -4,3 +4,4 @@ obj-y += realmode.o
>  obj-y += vmcs.o
>  obj-y += vmx.o
>  obj-y += vvmx.o
> +obj-y += sgx.o
> diff --git a/xen/arch/x86/hvm/vmx/sgx.c b/xen/arch/x86/hvm/vmx/sgx.c
> new file mode 100644
> index 0000000000..6b41469371
> --- /dev/null
> +++ b/xen/arch/x86/hvm/vmx/sgx.c

This file looks like it should be arch/x86/sgx.c, given its current content.

> @@ -0,0 +1,208 @@
> +/*
> + * Intel Software Guard Extensions support

Please include a GPLv2 header.

> + *
> + * Author: Kai Huang <kai.huang@linux.intel.com>
> + */
> +
> +#include <asm/cpufeature.h>
> +#include <asm/msr-index.h>
> +#include <asm/msr.h>
> +#include <asm/hvm/vmx/sgx.h>
> +#include <asm/hvm/vmx/vmcs.h>
> +
> +static struct sgx_cpuinfo __read_mostly sgx_cpudata[NR_CPUS];
> +static struct sgx_cpuinfo __read_mostly boot_sgx_cpudata;

I don't think any of this is necessary.  The description says that all
EPCs across the server will be reported in CPUID subleaves, and our
implementation gives up if the data are non-identical across CPUs.

Therefore, we only need to keep one copy of the data, and check check
APs against the master copy.


Let me see about splitting up a few bits of the existing CPUID
infrastructure, so we can use the host cpuid policy more effectively for
Xen related things.

~Andrew
Kai Huang July 21, 2017, 9:17 a.m. UTC | #2
On 7/20/2017 2:23 AM, Andrew Cooper wrote:
> On 09/07/17 09:09, Kai Huang wrote:
>> This patch adds early stage SGX feature detection via SGX CPUID 0x12. Function
>> detect_sgx is added to detect SGX info on each CPU (called from vmx_cpu_up).
>> SDM says SGX info returned by CPUID is per-thread, and we cannot assume all
>> threads will return the same SGX info, so we have to detect SGX for each CPU.
>> For simplicity, currently SGX is only supported when all CPUs reports the same
>> SGX info.
>>
>> SDM also says it's possible to have multiple EPC sections but this is only for
>> multiple-socket server, which we don't support now (there are other things
>> need to be done, ex, NUMA EPC, scheduling, etc, as well), so currently only
>> one EPC is supported.
>>
>> Dedicated files sgx.c and sgx.h are added (under vmx directory as SGX is Intel
>> specific) for bulk of above SGX detection code detection code, and for further
>> SGX code as well.
>>
>> Signed-off-by: Kai Huang <kai.huang@linux.intel.com>
> 
> I am not sure putting this under hvm/ is a sensible move.  Almost
> everything in this patch is currently common, and I can forsee us
> wanting to introduce PV support, so it would be good to introduce this
> in a guest-neutral location to begin with.
> 
>> ---
>>   xen/arch/x86/hvm/vmx/Makefile     |   1 +
>>   xen/arch/x86/hvm/vmx/sgx.c        | 208 ++++++++++++++++++++++++++++++++++++++
>>   xen/arch/x86/hvm/vmx/vmcs.c       |   4 +
>>   xen/include/asm-x86/cpufeature.h  |   1 +
>>   xen/include/asm-x86/hvm/vmx/sgx.h |  45 +++++++++
>>   5 files changed, 259 insertions(+)
>>   create mode 100644 xen/arch/x86/hvm/vmx/sgx.c
>>   create mode 100644 xen/include/asm-x86/hvm/vmx/sgx.h
>>
>> diff --git a/xen/arch/x86/hvm/vmx/Makefile b/xen/arch/x86/hvm/vmx/Makefile
>> index 04a29ce59d..f6bcf0d143 100644
>> --- a/xen/arch/x86/hvm/vmx/Makefile
>> +++ b/xen/arch/x86/hvm/vmx/Makefile
>> @@ -4,3 +4,4 @@ obj-y += realmode.o
>>   obj-y += vmcs.o
>>   obj-y += vmx.o
>>   obj-y += vvmx.o
>> +obj-y += sgx.o
>> diff --git a/xen/arch/x86/hvm/vmx/sgx.c b/xen/arch/x86/hvm/vmx/sgx.c
>> new file mode 100644
>> index 0000000000..6b41469371
>> --- /dev/null
>> +++ b/xen/arch/x86/hvm/vmx/sgx.c
> 
> This file looks like it should be arch/x86/sgx.c, given its current content.
> 
>> @@ -0,0 +1,208 @@
>> +/*
>> + * Intel Software Guard Extensions support
> 
> Please include a GPLv2 header.
> 
>> + *
>> + * Author: Kai Huang <kai.huang@linux.intel.com>
>> + */
>> +
>> +#include <asm/cpufeature.h>
>> +#include <asm/msr-index.h>
>> +#include <asm/msr.h>
>> +#include <asm/hvm/vmx/sgx.h>
>> +#include <asm/hvm/vmx/vmcs.h>
>> +
>> +static struct sgx_cpuinfo __read_mostly sgx_cpudata[NR_CPUS];
>> +static struct sgx_cpuinfo __read_mostly boot_sgx_cpudata;
> 
> I don't think any of this is necessary.  The description says that all
> EPCs across the server will be reported in CPUID subleaves, and our
> implementation gives up if the data are non-identical across CPUs.
> 
> Therefore, we only need to keep one copy of the data, and check check
> APs against the master copy.

Right. boot_sgx_cpudata is what we need. Currently detect_sgx is called 
from vmx_cpu_up. How about changing to calling it from identify_cpu, and 
something like below ?

	if ( c == &boot_cpu_data )
		detect_sgx(&boot_sgx_cpudata);
	else {
		struct sgx_cpuinfo tmp;
		detect_sgx(&tmp);
		if ( memcmp(&boot_sgx_cpudata, &tmp, sizeof (tmp)) )
			//disable SGX
	}

Thanks,
-Kai
> 
> 
> Let me see about splitting up a few bits of the existing CPUID
> infrastructure, so we can use the host cpuid policy more effectively for
> Xen related things.
> 
> ~Andrew
> 
> _______________________________________________
> Xen-devel mailing list
> Xen-devel@lists.xen.org
> https://lists.xen.org/xen-devel
>
Kai Huang July 22, 2017, 1:06 a.m. UTC | #3
On 7/21/2017 9:17 PM, Huang, Kai wrote:
> 
> 
> On 7/20/2017 2:23 AM, Andrew Cooper wrote:
>> On 09/07/17 09:09, Kai Huang wrote:
>>> This patch adds early stage SGX feature detection via SGX CPUID 0x12. 
>>> Function
>>> detect_sgx is added to detect SGX info on each CPU (called from 
>>> vmx_cpu_up).
>>> SDM says SGX info returned by CPUID is per-thread, and we cannot 
>>> assume all
>>> threads will return the same SGX info, so we have to detect SGX for 
>>> each CPU.
>>> For simplicity, currently SGX is only supported when all CPUs reports 
>>> the same
>>> SGX info.
>>>
>>> SDM also says it's possible to have multiple EPC sections but this is 
>>> only for
>>> multiple-socket server, which we don't support now (there are other 
>>> things
>>> need to be done, ex, NUMA EPC, scheduling, etc, as well), so 
>>> currently only
>>> one EPC is supported.
>>>
>>> Dedicated files sgx.c and sgx.h are added (under vmx directory as SGX 
>>> is Intel
>>> specific) for bulk of above SGX detection code detection code, and 
>>> for further
>>> SGX code as well.
>>>
>>> Signed-off-by: Kai Huang <kai.huang@linux.intel.com>
>>
>> I am not sure putting this under hvm/ is a sensible move.  Almost
>> everything in this patch is currently common, and I can forsee us
>> wanting to introduce PV support, so it would be good to introduce this
>> in a guest-neutral location to begin with.

Sorry I forgot to response to this in my last reply. I looked at code 
again and yes I think we can make the code to common place. I will move 
current sgx.c to arch/x86/sgx.c. Thanks for comments.

>>
>>> ---
>>>   xen/arch/x86/hvm/vmx/Makefile     |   1 +
>>>   xen/arch/x86/hvm/vmx/sgx.c        | 208 
>>> ++++++++++++++++++++++++++++++++++++++
>>>   xen/arch/x86/hvm/vmx/vmcs.c       |   4 +
>>>   xen/include/asm-x86/cpufeature.h  |   1 +
>>>   xen/include/asm-x86/hvm/vmx/sgx.h |  45 +++++++++
>>>   5 files changed, 259 insertions(+)
>>>   create mode 100644 xen/arch/x86/hvm/vmx/sgx.c
>>>   create mode 100644 xen/include/asm-x86/hvm/vmx/sgx.h
>>>
>>> diff --git a/xen/arch/x86/hvm/vmx/Makefile 
>>> b/xen/arch/x86/hvm/vmx/Makefile
>>> index 04a29ce59d..f6bcf0d143 100644
>>> --- a/xen/arch/x86/hvm/vmx/Makefile
>>> +++ b/xen/arch/x86/hvm/vmx/Makefile
>>> @@ -4,3 +4,4 @@ obj-y += realmode.o
>>>   obj-y += vmcs.o
>>>   obj-y += vmx.o
>>>   obj-y += vvmx.o
>>> +obj-y += sgx.o
>>> diff --git a/xen/arch/x86/hvm/vmx/sgx.c b/xen/arch/x86/hvm/vmx/sgx.c
>>> new file mode 100644
>>> index 0000000000..6b41469371
>>> --- /dev/null
>>> +++ b/xen/arch/x86/hvm/vmx/sgx.c
>>
>> This file looks like it should be arch/x86/sgx.c, given its current 
>> content.

Will do.

>>
>>> @@ -0,0 +1,208 @@
>>> +/*
>>> + * Intel Software Guard Extensions support
>>
>> Please include a GPLv2 header.

Yes will do.

Thanks,
-Kai
>>
>>> + *
>>> + * Author: Kai Huang <kai.huang@linux.intel.com>
>>> + */
>>> +
>>> +#include <asm/cpufeature.h>
>>> +#include <asm/msr-index.h>
>>> +#include <asm/msr.h>
>>> +#include <asm/hvm/vmx/sgx.h>
>>> +#include <asm/hvm/vmx/vmcs.h>
>>> +
>>> +static struct sgx_cpuinfo __read_mostly sgx_cpudata[NR_CPUS];
>>> +static struct sgx_cpuinfo __read_mostly boot_sgx_cpudata;
>>
>> I don't think any of this is necessary.  The description says that all
>> EPCs across the server will be reported in CPUID subleaves, and our
>> implementation gives up if the data are non-identical across CPUs.
>>
>> Therefore, we only need to keep one copy of the data, and check check
>> APs against the master copy.
> 
> Right. boot_sgx_cpudata is what we need. Currently detect_sgx is called 
> from vmx_cpu_up. How about changing to calling it from identify_cpu, and 
> something like below ?
> 
>      if ( c == &boot_cpu_data )
>          detect_sgx(&boot_sgx_cpudata);
>      else {
>          struct sgx_cpuinfo tmp;
>          detect_sgx(&tmp);
>          if ( memcmp(&boot_sgx_cpudata, &tmp, sizeof (tmp)) )
>              //disable SGX
>      }
> 
> Thanks,
> -Kai
>>
>>
>> Let me see about splitting up a few bits of the existing CPUID
>> infrastructure, so we can use the host cpuid policy more effectively for
>> Xen related things.
>>
>> ~Andrew
>>
>> _______________________________________________
>> Xen-devel mailing list
>> Xen-devel@lists.xen.org
>> https://lists.xen.org/xen-devel
>>
> 
> _______________________________________________
> Xen-devel mailing list
> Xen-devel@lists.xen.org
> https://lists.xen.org/xen-devel
diff mbox

Patch

diff --git a/xen/arch/x86/hvm/vmx/Makefile b/xen/arch/x86/hvm/vmx/Makefile
index 04a29ce59d..f6bcf0d143 100644
--- a/xen/arch/x86/hvm/vmx/Makefile
+++ b/xen/arch/x86/hvm/vmx/Makefile
@@ -4,3 +4,4 @@  obj-y += realmode.o
 obj-y += vmcs.o
 obj-y += vmx.o
 obj-y += vvmx.o
+obj-y += sgx.o
diff --git a/xen/arch/x86/hvm/vmx/sgx.c b/xen/arch/x86/hvm/vmx/sgx.c
new file mode 100644
index 0000000000..6b41469371
--- /dev/null
+++ b/xen/arch/x86/hvm/vmx/sgx.c
@@ -0,0 +1,208 @@ 
+/*
+ * Intel Software Guard Extensions support
+ *
+ * Author: Kai Huang <kai.huang@linux.intel.com>
+ */
+
+#include <asm/cpufeature.h>
+#include <asm/msr-index.h>
+#include <asm/msr.h>
+#include <asm/hvm/vmx/sgx.h>
+#include <asm/hvm/vmx/vmcs.h>
+
+static struct sgx_cpuinfo __read_mostly sgx_cpudata[NR_CPUS];
+static struct sgx_cpuinfo __read_mostly boot_sgx_cpudata;
+
+static bool_t sgx_enabled_in_bios(void)
+{
+    uint64_t val, sgx_enabled = IA32_FEATURE_CONTROL_SGX_ENABLE |
+                                IA32_FEATURE_CONTROL_LOCK;
+
+    rdmsrl(MSR_IA32_FEATURE_CONTROL, val);
+
+    return (val & sgx_enabled) == sgx_enabled;
+}
+
+static void __detect_sgx(int cpu)
+{
+    struct sgx_cpuinfo *sgxinfo = &sgx_cpudata[cpu];
+    u32 eax, ebx, ecx, edx;
+
+    memset(sgxinfo, 0, sizeof(*sgxinfo));
+
+    /*
+     * In reality if SGX is not enabled in BIOS, SGX CPUID should report
+     * invalid SGX info, but we do the check anyway to make sure.
+     */
+    if ( !sgx_enabled_in_bios() )
+    {
+        printk("CPU%d: SGX disabled in BIOS.\n", cpu);
+        goto not_supported;
+    }
+
+    /*
+     * CPUID.0x12.0x0:
+     *
+     *  EAX [0]:    whether SGX1 is supported.
+     *      [1]:    whether SGX2 is supported.
+     *  EBX [31:0]: miscselect
+     *  ECX [31:0]: reserved
+     *  EDX [7:0]:  MaxEnclaveSize_Not64
+     *      [15:8]: MaxEnclaveSize_64
+     */
+    cpuid_count(SGX_CPUID, 0x0, &eax, &ebx, &ecx, &edx);
+    sgxinfo->cap = eax & (SGX_CAP_SGX1 | SGX_CAP_SGX2);
+    sgxinfo->miscselect = ebx;
+    sgxinfo->max_enclave_size32 = edx & 0xff;
+    sgxinfo->max_enclave_size64 = (edx & 0xff00) >> 8;
+
+    if ( !(eax & SGX_CAP_SGX1) )
+    {
+        /* We may reach here if BIOS doesn't enable SGX */
+        printk("CPU%d: CPUID.0x12.0x0 reports not SGX support.\n", cpu);
+        goto not_supported;
+    }
+
+    /*
+     * CPUID.0x12.0x1:
+     *
+     *  EAX [31:0]: bitmask of 1-setting of SECS.ATTRIBUTES[31:0]
+     *  EBX [31:0]: bitmask of 1-setting of SECS.ATTRIBUTES[63:32]
+     *  ECX [31:0]: bitmask of 1-setting of SECS.ATTRIBUTES[95:64]
+     *  EDX [31:0]: bitmask of 1-setting of SECS.ATTRIBUTES[127:96]
+     */
+    cpuid_count(SGX_CPUID, 0x1, &eax, &ebx, &ecx, &edx);
+    sgxinfo->secs_attr_bitmask[0] = eax;
+    sgxinfo->secs_attr_bitmask[1] = ebx;
+    sgxinfo->secs_attr_bitmask[2] = ecx;
+    sgxinfo->secs_attr_bitmask[3] = edx;
+
+    /*
+     * CPUID.0x12.0x2:
+     *
+     *  EAX [3:0]:      0000: this sub-leaf is invalid
+     *                  0001: this sub-leaf enumerates EPC resource
+     *      [11:4]:     reserved
+     *      [31:12]:    bits 31:12 of physical address of EPC base (when
+     *                  EAX[3:0] is 0001, which applies to following)
+     *  EBX [19:0]:     bits 51:32 of physical address of EPC base
+     *      [31:20]:    reserved
+     *  ECX [3:0]:      0000: EDX:ECX are 0
+     *                  0001: this is EPC section.
+     *      [11:4]:     reserved
+     *      [31:12]:    bits 31:12 of EPC size
+     *  EDX [19:0]:     bits 51:32 of EPC size
+     *      [31:20]:    reserved
+     *
+     *  TODO: So far assume there's only one EPC resource.
+     */
+    cpuid_count(SGX_CPUID, 0x2, &eax, &ebx, &ecx, &edx);
+    if ( !(eax & 0x1) || !(ecx & 0x1) )
+    {
+        /* We may reach here if BIOS doesn't enable SGX */
+        printk("CPU%d: CPUID.0x12.0x2 reports invalid EPC resource.\n", cpu);
+        goto not_supported;
+    }
+    sgxinfo->epc_base = (((u64)(ebx & 0xfffff)) << 32) | (eax & 0xfffff000);
+    sgxinfo->epc_size = (((u64)(edx & 0xfffff)) << 32) | (ecx & 0xfffff000);
+
+    return;
+
+not_supported:
+    memset(sgxinfo, 0, sizeof(*sgxinfo));
+}
+
+void detect_sgx(int cpu)
+{
+    /* Caller (vmx_cpu_up) has checked cpu_has_vmx_encls */
+    if ( !cpu_has_sgx || boot_cpu_data.cpuid_level < SGX_CPUID )
+    {
+        setup_clear_cpu_cap(X86_FEATURE_SGX);
+        return;
+    }
+
+    __detect_sgx(cpu);
+}
+
+static void __init disable_sgx(void)
+{
+    memset(&boot_sgx_cpudata, 0, sizeof (struct sgx_cpuinfo));
+    /*
+     * X86_FEATURE_SGX is cleared in boot_cpu_data so that cpu_has_sgx
+     * can be used anywhere to check whether SGX is supported by Xen.
+     *
+     * FIXME: also adjust boot_cpu_data.cpuid_level ?
+     */
+    setup_clear_cpu_cap(X86_FEATURE_SGX);
+}
+
+static void __init print_sgx_cpuinfo(struct sgx_cpuinfo *sgxinfo)
+{
+    printk("SGX: \n"
+           "\tCAP: %s,%s\n"
+           "\tEPC: [0x%"PRIx64", 0x%"PRIx64")\n",
+           boot_sgx_cpudata.cap & SGX_CAP_SGX1 ? "SGX1" : "",
+           boot_sgx_cpudata.cap & SGX_CAP_SGX2 ? "SGX2" : "",
+           boot_sgx_cpudata.epc_base,
+           boot_sgx_cpudata.epc_base + boot_sgx_cpudata.epc_size);
+}
+
+/*
+ * Check SGX CPUID info all for all CPUs, and only support SGX when all CPUs
+ * report the same SGX info. SDM (37.7.2 Intel SGX Resource Enumeration Leaves)
+ * says "software should not assume that if Intel SGX instructions are
+ * supported on one hardware thread, they are also supported elsewhere.".
+ * For simplicity, we only support SGX when all CPUs reports consistent SGX
+ * info.
+ *
+ * boot_sgx_cpudata is set to store the *common* SGX CPUID info.
+ */
+static bool_t __init check_sgx_consistency(void)
+{
+    int i;
+
+    for_each_online_cpu ( i )
+    {
+        struct sgx_cpuinfo *s = &sgx_cpudata[i];
+
+        if ( memcmp(&boot_sgx_cpudata, s, sizeof (*s)) )
+        {
+            printk("SGX inconsistency between CPU 0 and CPU %d. "
+                    "Disable SGX.\n", i);
+            memset(&boot_sgx_cpudata, 0,  sizeof (*s));
+            return false;
+        }
+    }
+
+    return true;
+}
+
+static int __init sgx_init(void)
+{
+    /* Assume CPU 0 is always online */
+    boot_sgx_cpudata = sgx_cpudata[0];
+
+    if ( !(boot_sgx_cpudata.cap & SGX_CAP_SGX1) )
+        goto not_supported;
+
+    if ( !check_sgx_consistency() )
+        goto not_supported;
+
+    print_sgx_cpuinfo(&boot_sgx_cpudata);
+
+    return 0;
+not_supported:
+    disable_sgx();
+    return -EINVAL;
+}
+__initcall(sgx_init);
+
+/*
+ * 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/hvm/vmx/vmcs.c b/xen/arch/x86/hvm/vmx/vmcs.c
index ae7e6f9321..518133bbfd 100644
--- a/xen/arch/x86/hvm/vmx/vmcs.c
+++ b/xen/arch/x86/hvm/vmx/vmcs.c
@@ -40,6 +40,7 @@ 
 #include <asm/shadow.h>
 #include <asm/tboot.h>
 #include <asm/apic.h>
+#include <asm/hvm/vmx/sgx.h>
 
 static bool_t __read_mostly opt_vpid_enabled = 1;
 boolean_param("vpid", opt_vpid_enabled);
@@ -696,6 +697,9 @@  int vmx_cpu_up(void)
 
     vmx_pi_per_cpu_init(cpu);
 
+    if ( cpu_has_vmx_encls )
+        detect_sgx(cpu);
+
     return 0;
 }
 
diff --git a/xen/include/asm-x86/cpufeature.h b/xen/include/asm-x86/cpufeature.h
index 84cc51d2bd..9793f8c1c5 100644
--- a/xen/include/asm-x86/cpufeature.h
+++ b/xen/include/asm-x86/cpufeature.h
@@ -85,6 +85,7 @@ 
 
 /* CPUID level 0x00000007:0.ebx */
 #define cpu_has_fsgsbase        boot_cpu_has(X86_FEATURE_FSGSBASE)
+#define cpu_has_sgx             boot_cpu_has(X86_FEATURE_SGX)
 #define cpu_has_bmi1            boot_cpu_has(X86_FEATURE_BMI1)
 #define cpu_has_hle             boot_cpu_has(X86_FEATURE_HLE)
 #define cpu_has_avx2            boot_cpu_has(X86_FEATURE_AVX2)
diff --git a/xen/include/asm-x86/hvm/vmx/sgx.h b/xen/include/asm-x86/hvm/vmx/sgx.h
new file mode 100644
index 0000000000..5414d8237e
--- /dev/null
+++ b/xen/include/asm-x86/hvm/vmx/sgx.h
@@ -0,0 +1,45 @@ 
+/*
+ * Intel Software Guard Extensions support
+ *
+ * Copyright (c) 2016, Intel Corporation.
+ *
+ * Author: Kai Huang <kai.huang@linux.intel.com>
+ */
+#ifndef __ASM_X86_HVM_VMX_SGX_H__
+#define __ASM_X86_HVM_VMX_SGX_H__
+
+#include <xen/config.h>
+#include <xen/types.h>
+#include <xen/init.h>
+#include <asm/processor.h>
+
+#define SGX_CPUID 0x12
+
+/*
+ * SGX info reported by SGX CPUID.
+ *
+ * TODO:
+ *
+ * SDM (37.7.2 Intel SGX Resource Enumeration Leaves) actually says it's
+ * possible there are multiple EPC resources on the machine (CPUID.0x12,
+ * ECX starting with 0x2 enumerates available EPC resources until invalid
+ * EPC resource is returned). But this is only for multiple socket server,
+ * which we current don't support now (there are additional things need to
+ * be done as well). So far for simplicity we assume there is only one EPC.
+ */
+struct sgx_cpuinfo {
+#define SGX_CAP_SGX1    (1UL << 0)
+#define SGX_CAP_SGX2    (1UL << 1)
+    uint32_t cap;
+    uint32_t miscselect;
+    uint8_t max_enclave_size64;
+    uint8_t max_enclave_size32;
+    uint32_t secs_attr_bitmask[4];
+    uint64_t epc_base;
+    uint64_t epc_size;
+};
+
+/* Detect SGX info for particular CPU via SGX CPUID */
+void detect_sgx(int cpu);
+
+#endif  /* __ASM_X86_HVM_VMX_SGX_H__ */