[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH v2 02/17] xen: x86: add early stage SGX feature detection



From: Kai Huang <kai.huang@xxxxxxxxxxxxxxx>

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
identify_cpu). 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.

Besides a boot parameter 'sgx' is added to allow the sysadmin control
whether SGX is supported to guests.

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.

The detection result is in the X86_FEATURE_SGX bit of 'boot_cpu_data',
and 'cpu_has_sgx' should be the only way to query for the SGX support
enabled or not in the whole system.

Dedicated files sgx.c and sgx.h are added for bulk of above SGX
detection code detection code, and for further SGX code as well.

Signed-off-by: Kai Huang <kai.huang@xxxxxxxxxxxxxxx>
Signed-off-by: Boqun Feng <boqun.feng@xxxxxxxxx>
---
 docs/misc/xen-command-line.markdown |   8 ++
 xen/arch/x86/Makefile               |   1 +
 xen/arch/x86/cpu/common.c           |  15 +++
 xen/arch/x86/sgx.c                  | 191 ++++++++++++++++++++++++++++++++++++
 xen/include/asm-x86/cpufeature.h    |   1 +
 xen/include/asm-x86/msr-index.h     |   1 +
 xen/include/asm-x86/sgx.h           |  61 ++++++++++++
 7 files changed, 278 insertions(+)
 create mode 100644 xen/arch/x86/sgx.c
 create mode 100644 xen/include/asm-x86/sgx.h

diff --git a/docs/misc/xen-command-line.markdown 
b/docs/misc/xen-command-line.markdown
index 781110d4b2a5..81f9936face2 100644
--- a/docs/misc/xen-command-line.markdown
+++ b/docs/misc/xen-command-line.markdown
@@ -1601,6 +1601,14 @@ hypervisors handle SErrors:
   All SErrors will crash the whole system. This option will avoid all overhead
   of the dsb/isb pairs.
 
+### sgx (Intel)
+> = <boolean>
+
+> Default: false
+
+Flag to enable Software Guard Extensions support
+for guest.
+
 ### smap
 > `= <boolean> | hvm`
 
diff --git a/xen/arch/x86/Makefile b/xen/arch/x86/Makefile
index d5d58a205ec8..c8a843fef540 100644
--- a/xen/arch/x86/Makefile
+++ b/xen/arch/x86/Makefile
@@ -54,6 +54,7 @@ obj-y += platform_hypercall.o x86_64/platform_hypercall.o
 obj-y += psr.o
 obj-y += setup.o
 obj-y += shutdown.o
+obj-y += sgx.o
 obj-y += smp.o
 obj-y += smpboot.o
 obj-y += srat.o
diff --git a/xen/arch/x86/cpu/common.c b/xen/arch/x86/cpu/common.c
index 6cf362849e85..0a93d5759a76 100644
--- a/xen/arch/x86/cpu/common.c
+++ b/xen/arch/x86/cpu/common.c
@@ -11,6 +11,7 @@
 #include <asm/apic.h>
 #include <mach_apic.h>
 #include <asm/setup.h>
+#include <asm/sgx.h>
 #include <public/sysctl.h> /* for XEN_INVALID_{SOCKET,CORE}_ID */
 
 #include "cpu.h"
@@ -430,14 +431,28 @@ void identify_cpu(struct cpuinfo_x86 *c)
         * executed, c == &boot_cpu_data.
         */
        if ( c != &boot_cpu_data ) {
+               struct sgx_cpuinfo tmp;
                /* AND the already accumulated flags with these */
                for ( i = 0 ; i < NCAPINTS ; i++ )
                        boot_cpu_data.x86_capability[i] &= c->x86_capability[i];
 
                mcheck_init(c, false);
+               /*
+                * 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.
+                */
+               detect_sgx(&tmp);
+               if ( memcmp(&tmp, &boot_sgx_cpudata, sizeof(tmp)) )
+                       disable_sgx();
        } else {
                mcheck_init(c, true);
 
+               detect_sgx(&boot_sgx_cpudata);
+
                mtrr_bp_init();
        }
 }
diff --git a/xen/arch/x86/sgx.c b/xen/arch/x86/sgx.c
new file mode 100644
index 000000000000..ead917543f3e
--- /dev/null
+++ b/xen/arch/x86/sgx.c
@@ -0,0 +1,191 @@
+/*
+ * Intel Software Guard Extensions support
+ *
+ * Copyright (c) 2017,  Intel Corporation
+ *
+ * Author: Kai Huang <kai.huang@xxxxxxxxxxxxxxx>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License v2 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.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <xen/sched.h>
+#include <asm/cpufeature.h>
+#include <asm/msr-index.h>
+#include <asm/msr.h>
+#include <asm/sgx.h>
+
+struct sgx_cpuinfo __read_mostly boot_sgx_cpudata;
+
+static bool __read_mostly opt_sgx_enabled = false;
+boolean_param("sgx", opt_sgx_enabled);
+
+static void __detect_sgx(struct sgx_cpuinfo *sgxinfo)
+{
+    u32 eax, ebx, ecx, edx;
+    uint64_t val;
+    uint64_t sgx_enabled = IA32_FEATURE_CONTROL_SGX_ENABLE |
+                           IA32_FEATURE_CONTROL_LOCK;
+    int cpu = smp_processor_id();
+
+    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.
+     */
+    rdmsrl(MSR_IA32_FEATURE_CONTROL, val);
+
+    if ( (val & sgx_enabled) != sgx_enabled )
+    {
+        printk("CPU%d: SGX disabled in BIOS.\n", cpu);
+        goto not_supported;
+    }
+
+    sgxinfo->lewr = !!(val & IA32_FEATURE_CONTROL_SGX_LE_WR);
+
+    /*
+     * 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));
+    disable_sgx();
+}
+
+void detect_sgx(struct sgx_cpuinfo *sgxinfo)
+{
+    if ( !opt_sgx_enabled )
+    {
+        setup_clear_cpu_cap(X86_FEATURE_SGX);
+        return;
+    }
+    else if ( sgxinfo != &boot_sgx_cpudata &&
+              ( !cpu_has_sgx || boot_cpu_data.cpuid_level < SGX_CPUID ))
+    {
+        setup_clear_cpu_cap(X86_FEATURE_SGX);
+        return;
+    }
+
+    __detect_sgx(sgxinfo);
+}
+
+void disable_sgx(void)
+{
+    /*
+     * 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);
+    opt_sgx_enabled = false;
+}
+
+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);
+}
+
+static int __init sgx_init(void)
+{
+    if ( !cpu_has_sgx )
+        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/include/asm-x86/cpufeature.h b/xen/include/asm-x86/cpufeature.h
index 84cc51d2bdc8..9793f8c1c586 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/msr-index.h b/xen/include/asm-x86/msr-index.h
index b99c623367b8..63e11931cd09 100644
--- a/xen/include/asm-x86/msr-index.h
+++ b/xen/include/asm-x86/msr-index.h
@@ -298,6 +298,7 @@
 #define IA32_FEATURE_CONTROL_ENABLE_SENTER            0x8000
 #define IA32_FEATURE_CONTROL_SGX_ENABLE               0x40000
 #define IA32_FEATURE_CONTROL_LMCE_ON                  0x100000
+#define IA32_FEATURE_CONTROL_SGX_LE_WR                0x20000
 
 #define MSR_IA32_TSC_ADJUST            0x0000003b
 
diff --git a/xen/include/asm-x86/sgx.h b/xen/include/asm-x86/sgx.h
new file mode 100644
index 000000000000..b37ebde64e84
--- /dev/null
+++ b/xen/include/asm-x86/sgx.h
@@ -0,0 +1,61 @@
+/*
+ * Intel Software Guard Extensions support
+ *
+ * Copyright (c) 2016-2017, Intel Corporation.
+ *
+ * Author: Kai Huang <kai.huang@xxxxxxxxxxxxxxx>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public
+ * License v2 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.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this program; If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_X86_SGX_H__
+#define __ASM_X86_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;
+    bool lewr;
+};
+
+extern struct sgx_cpuinfo __read_mostly boot_sgx_cpudata;
+/* Detect SGX info for particular CPU via SGX CPUID */
+void detect_sgx(struct sgx_cpuinfo *sgxinfo);
+void disable_sgx(void);
+#define sgx_lewr() (boot_sgx_cpudata.lewr)
+
+#endif  /* __ASM_X86_SGX_H__ */
-- 
2.15.0


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

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.