All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH RFC v3 00/12] Intel(R) SGX Driver
@ 2017-10-10 14:32 Jarkko Sakkinen
  2017-10-10 14:32 ` [PATCH RFC v3 01/12] intel_sgx: updated MAINTAINERS Jarkko Sakkinen
                   ` (11 more replies)
  0 siblings, 12 replies; 40+ messages in thread
From: Jarkko Sakkinen @ 2017-10-10 14:32 UTC (permalink / raw)
  To: intel-sgx-kernel-dev; +Cc: platform-driver-x86, Jarkko Sakkinen

Intel(R) SGX is a set of CPU instructions that can be used by applications to
set aside private regions of code and data. The code outside the enclave is
disallowed to access the memory inside the enclave by the CPU access control.
In a way you can think that SGX provides inverted sandbox. It protects the
application from a malicious host.

There is a new hardware unit in the processor called Memory Encryption Engine
(MEE) starting from the Skylake microachitecture. BIOS can define one or many
MEE regions that can hold enclave data by configuring them with PRMRR registers.

The MEE automatically encrypts the data leaving the processor package to the MEE
regions. The data is encrypted using a random key whose life-time is exactly one
power cycle.

You can tell if your CPU supports SGX by looking into ``/proc/cpuinfo``:

	``cat /proc/cpuinfo  | grep ' sgx '``

The GIT repositoy for SGX driver resides in

	https://github.com/jsakkine-intel/linux-sgx.git

'le' branch contains the upstream candidate patches.

'master' branch contains the same patches with the following differences:

* top-level patch modifies the ioctl API to be SDK compatible
* does not use flexible launch control but instead relies on SDK provided
  Intel launch enclave.

'master' is just maintained to allow people to test the code.

v3:
* Check that FEATURE_CONTROL_LOCKED and FEATURE_CONTROL_SGX_ENABLE are set.
* Return -ERESTARTSYS in __sgx_encl_add_page() when sgx_alloc_page() fails.
* Use unused bits in epc_page->pa to store the bank number.
* Removed #ifdef for WQ_NONREENTRANT.
* If mmu_notifier_register() fails with -EINTR, return -ERESTARTSYS.
* Added --remove-section=.got.plt to objcopy flags in order to prevent a
  dummy .got.plt, which will cause an inconsistent size for the LE.
* Documented sgx_encl_* functions.
* Added remark about AES implementation used inside the LE.
* Removed redundant sgx_sys_exit() from le/main.c.
* Fixed struct sgx_secinfo alignment from 128 to 64 bytes.
* Validate miscselect in sgx_encl_create().
* Fixed SSA frame size calculation to take the misc region into account.
* Implemented consistent exception handling to __encls() and __encls_ret().
* Implemented a proper device model in order to allow sysfs attributes
  and in-kernel API.
* Cleaned up various "find enclave" implementations to the unified
  sgx_encl_find().
* Validate that vm_pgoff is zero.
* Discard backing pages with shmem_truncate_range() after EADD.
* Added missing EEXTEND operations to LE signing and launch.
* Fixed SSA size for GPRS region from 168 to 184 bytes.
* Fixed the checks for TCS flags. Now DBGOPTIN is allowed.
* Check that TCS addresses are in ELRANGE and not just page aligned.
* Require kernel to be compiled with X64_64 and CPU_SUP_INTEL.
* Fixed an incorrect value for SGX_ATTR_DEBUG from 0x01 to 0x02.

v2:
* get_rand_uint32() changed the value of the pointer instead of value
  where it is pointing at.
* Launch enclave incorrectly used sigstruct attributes-field instead of
  enclave attributes-field.
* Removed unused struct sgx_add_page_req from sgx_ioctl.c
* Removed unused sgx_has_sgx2.
* Updated arch/x86/include/asm/sgx.h so that it provides stub
  implementations when sgx in not enabled.
* Removed cruft rdmsr-calls from sgx_set_pubkeyhash_msrs().
* return -ENOMEM in sgx_alloc_page() when VA pages consume too much space
* removed unused global sgx_nr_pids
* moved sgx_encl_release to sgx_encl.c
* return -ERESTARTSYS instead of -EINTR in sgx_encl_init()

Haim Cohen (1):
  x86: add SGX MSRs to msr-index.h

Jarkko Sakkinen (9):
  intel_sgx: updated MAINTAINERS
  x86: define the feature control MSR's SGX launch control bit
  fs/pipe.c: export create_pipe_files() and replace_fd()
  intel_sgx: driver for Intel Software Guard Extensions
  intel_sgx: ptrace() support
  intel_sgx: driver documentation
  intel_sgx: in-kernel launch enclave
  intel_sgx: glue code for in-kernel LE
  intel_sgx: update IA32_SGXLEPUBKEYHASH* MSRs

Kai Huang (1):
  x86: add SGX definition to cpufeature

Sean Christopherson (1):
  x86: define the feature control MSR's SGX enable bit

 Documentation/index.rst                            |    1 +
 Documentation/x86/intel_sgx.rst                    |  131 +++
 MAINTAINERS                                        |    5 +
 arch/x86/include/asm/cpufeatures.h                 |    2 +
 arch/x86/include/asm/msr-index.h                   |    8 +
 arch/x86/include/asm/sgx.h                         |  233 +++++
 arch/x86/include/asm/sgx_arch.h                    |  268 ++++++
 arch/x86/include/uapi/asm/sgx.h                    |  147 +++
 drivers/platform/x86/Kconfig                       |    2 +
 drivers/platform/x86/Makefile                      |    1 +
 drivers/platform/x86/intel_sgx/Kconfig             |   34 +
 drivers/platform/x86/intel_sgx/Makefile            |   32 +
 drivers/platform/x86/intel_sgx/le/Makefile         |   26 +
 drivers/platform/x86/intel_sgx/le/enclave/Makefile |   46 +
 .../x86/intel_sgx/le/enclave/aes_encrypt.c         |  191 ++++
 .../platform/x86/intel_sgx/le/enclave/cmac_mode.c  |  254 +++++
 .../x86/intel_sgx/le/enclave/encl_bootstrap.S      |  163 ++++
 .../intel_sgx/le/enclave/include/tinycrypt/aes.h   |  133 +++
 .../le/enclave/include/tinycrypt/cmac_mode.h       |  194 ++++
 .../le/enclave/include/tinycrypt/constants.h       |   59 ++
 .../intel_sgx/le/enclave/include/tinycrypt/utils.h |   95 ++
 drivers/platform/x86/intel_sgx/le/enclave/main.c   |  203 ++++
 .../platform/x86/intel_sgx/le/enclave/sgx_le.lds   |   28 +
 .../platform/x86/intel_sgx/le/enclave/sgxsign.c    |  537 +++++++++++
 drivers/platform/x86/intel_sgx/le/enclave/utils.c  |   78 ++
 drivers/platform/x86/intel_sgx/le/entry.S          |  117 +++
 .../platform/x86/intel_sgx/le/include/sgx_asm.h    |   64 ++
 .../platform/x86/intel_sgx/le/include/sgx_encl.h   |  105 ++
 drivers/platform/x86/intel_sgx/le/main.c           |  219 +++++
 drivers/platform/x86/intel_sgx/le/sgx_le_piggy.S   |   15 +
 drivers/platform/x86/intel_sgx/sgx.h               |  264 +++++
 drivers/platform/x86/intel_sgx/sgx_encl.c          | 1009 ++++++++++++++++++++
 drivers/platform/x86/intel_sgx/sgx_ioctl.c         |  282 ++++++
 drivers/platform/x86/intel_sgx/sgx_le.c            |  290 ++++++
 .../platform/x86/intel_sgx/sgx_le_proxy_piggy.S    |   15 +
 drivers/platform/x86/intel_sgx/sgx_main.c          |  475 +++++++++
 drivers/platform/x86/intel_sgx/sgx_page_cache.c    |  586 ++++++++++++
 drivers/platform/x86/intel_sgx/sgx_util.c          |  396 ++++++++
 drivers/platform/x86/intel_sgx/sgx_vma.c           |  230 +++++
 fs/file.c                                          |    1 +
 fs/pipe.c                                          |    1 +
 41 files changed, 6940 insertions(+)
 create mode 100644 Documentation/x86/intel_sgx.rst
 create mode 100644 arch/x86/include/asm/sgx.h
 create mode 100644 arch/x86/include/asm/sgx_arch.h
 create mode 100644 arch/x86/include/uapi/asm/sgx.h
 create mode 100644 drivers/platform/x86/intel_sgx/Kconfig
 create mode 100644 drivers/platform/x86/intel_sgx/Makefile
 create mode 100644 drivers/platform/x86/intel_sgx/le/Makefile
 create mode 100644 drivers/platform/x86/intel_sgx/le/enclave/Makefile
 create mode 100644 drivers/platform/x86/intel_sgx/le/enclave/aes_encrypt.c
 create mode 100644 drivers/platform/x86/intel_sgx/le/enclave/cmac_mode.c
 create mode 100644 drivers/platform/x86/intel_sgx/le/enclave/encl_bootstrap.S
 create mode 100644 drivers/platform/x86/intel_sgx/le/enclave/include/tinycrypt/aes.h
 create mode 100644 drivers/platform/x86/intel_sgx/le/enclave/include/tinycrypt/cmac_mode.h
 create mode 100644 drivers/platform/x86/intel_sgx/le/enclave/include/tinycrypt/constants.h
 create mode 100644 drivers/platform/x86/intel_sgx/le/enclave/include/tinycrypt/utils.h
 create mode 100644 drivers/platform/x86/intel_sgx/le/enclave/main.c
 create mode 100644 drivers/platform/x86/intel_sgx/le/enclave/sgx_le.lds
 create mode 100644 drivers/platform/x86/intel_sgx/le/enclave/sgxsign.c
 create mode 100644 drivers/platform/x86/intel_sgx/le/enclave/utils.c
 create mode 100644 drivers/platform/x86/intel_sgx/le/entry.S
 create mode 100644 drivers/platform/x86/intel_sgx/le/include/sgx_asm.h
 create mode 100644 drivers/platform/x86/intel_sgx/le/include/sgx_encl.h
 create mode 100644 drivers/platform/x86/intel_sgx/le/main.c
 create mode 100644 drivers/platform/x86/intel_sgx/le/sgx_le_piggy.S
 create mode 100644 drivers/platform/x86/intel_sgx/sgx.h
 create mode 100644 drivers/platform/x86/intel_sgx/sgx_encl.c
 create mode 100644 drivers/platform/x86/intel_sgx/sgx_ioctl.c
 create mode 100644 drivers/platform/x86/intel_sgx/sgx_le.c
 create mode 100644 drivers/platform/x86/intel_sgx/sgx_le_proxy_piggy.S
 create mode 100644 drivers/platform/x86/intel_sgx/sgx_main.c
 create mode 100644 drivers/platform/x86/intel_sgx/sgx_page_cache.c
 create mode 100644 drivers/platform/x86/intel_sgx/sgx_util.c
 create mode 100644 drivers/platform/x86/intel_sgx/sgx_vma.c

-- 
2.14.1

^ permalink raw reply	[flat|nested] 40+ messages in thread

* [PATCH RFC v3 01/12] intel_sgx: updated MAINTAINERS
  2017-10-10 14:32 [PATCH RFC v3 00/12] Intel(R) SGX Driver Jarkko Sakkinen
@ 2017-10-10 14:32 ` Jarkko Sakkinen
  2017-10-10 14:32 ` [PATCH RFC v3 02/12] x86: add SGX definition to cpufeature Jarkko Sakkinen
                   ` (10 subsequent siblings)
  11 siblings, 0 replies; 40+ messages in thread
From: Jarkko Sakkinen @ 2017-10-10 14:32 UTC (permalink / raw)
  To: intel-sgx-kernel-dev; +Cc: platform-driver-x86, Jarkko Sakkinen

Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
---
 MAINTAINERS | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index 2d3d750b19c0..30a4b7f97a93 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -14932,6 +14932,11 @@ L:	linux-mm@kvack.org
 S:	Maintained
 F:	mm/zswap.c
 
+INTEL SGX
+M:	Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
+L:	intel-sgx-kernel-dev@lists.01.org
+Q:	https://patchwork.kernel.org/project/intel-sgx/list/
+
 THE REST
 M:	Linus Torvalds <torvalds@linux-foundation.org>
 L:	linux-kernel@vger.kernel.org
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH RFC v3 02/12] x86: add SGX definition to cpufeature
  2017-10-10 14:32 [PATCH RFC v3 00/12] Intel(R) SGX Driver Jarkko Sakkinen
  2017-10-10 14:32 ` [PATCH RFC v3 01/12] intel_sgx: updated MAINTAINERS Jarkko Sakkinen
@ 2017-10-10 14:32 ` Jarkko Sakkinen
  2017-10-10 14:32 ` [PATCH RFC v3 03/12] x86: define the feature control MSR's SGX enable bit Jarkko Sakkinen
                   ` (9 subsequent siblings)
  11 siblings, 0 replies; 40+ messages in thread
From: Jarkko Sakkinen @ 2017-10-10 14:32 UTC (permalink / raw)
  To: intel-sgx-kernel-dev; +Cc: platform-driver-x86, Kai Huang

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

Signed-off-by: Kai Huang <kai.huang@linux.intel.com>
---
 arch/x86/include/asm/cpufeatures.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h
index 2519c6c801c9..31a7d1c0f204 100644
--- a/arch/x86/include/asm/cpufeatures.h
+++ b/arch/x86/include/asm/cpufeatures.h
@@ -219,6 +219,7 @@
 /* Intel-defined CPU features, CPUID level 0x00000007:0 (ebx), word 9 */
 #define X86_FEATURE_FSGSBASE	( 9*32+ 0) /* {RD/WR}{FS/GS}BASE instructions*/
 #define X86_FEATURE_TSC_ADJUST	( 9*32+ 1) /* TSC adjustment MSR 0x3b */
+#define X86_FEATURE_SGX		( 9*32+ 2) /* Software Guard Extensions */
 #define X86_FEATURE_BMI1	( 9*32+ 3) /* 1st group bit manipulation extensions */
 #define X86_FEATURE_HLE		( 9*32+ 4) /* Hardware Lock Elision */
 #define X86_FEATURE_AVX2	( 9*32+ 5) /* AVX2 instructions */
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH RFC v3 03/12] x86: define the feature control MSR's SGX enable bit
  2017-10-10 14:32 [PATCH RFC v3 00/12] Intel(R) SGX Driver Jarkko Sakkinen
  2017-10-10 14:32 ` [PATCH RFC v3 01/12] intel_sgx: updated MAINTAINERS Jarkko Sakkinen
  2017-10-10 14:32 ` [PATCH RFC v3 02/12] x86: add SGX definition to cpufeature Jarkko Sakkinen
@ 2017-10-10 14:32 ` Jarkko Sakkinen
  2017-10-10 14:32 ` [PATCH RFC v3 04/12] x86: define the feature control MSR's SGX launch control bit Jarkko Sakkinen
                   ` (8 subsequent siblings)
  11 siblings, 0 replies; 40+ messages in thread
From: Jarkko Sakkinen @ 2017-10-10 14:32 UTC (permalink / raw)
  To: intel-sgx-kernel-dev
  Cc: platform-driver-x86, Sean Christopherson, Jarkko Sakkinen

From: Sean Christopherson <sean.j.christopherson@intel.com>

Signed-off-by: Sean Christopherson <sean.j.christopherson@intel.com>
Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
---
 arch/x86/include/asm/msr-index.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h
index 17f5c12e1afd..b35cb98b5d60 100644
--- a/arch/x86/include/asm/msr-index.h
+++ b/arch/x86/include/asm/msr-index.h
@@ -435,6 +435,7 @@
 #define FEATURE_CONTROL_LOCKED				(1<<0)
 #define FEATURE_CONTROL_VMXON_ENABLED_INSIDE_SMX	(1<<1)
 #define FEATURE_CONTROL_VMXON_ENABLED_OUTSIDE_SMX	(1<<2)
+#define FEATURE_CONTROL_SGX_ENABLE                      (1<<18)
 #define FEATURE_CONTROL_LMCE				(1<<20)
 
 #define MSR_IA32_APICBASE		0x0000001b
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH RFC v3 04/12] x86: define the feature control MSR's SGX launch control bit
  2017-10-10 14:32 [PATCH RFC v3 00/12] Intel(R) SGX Driver Jarkko Sakkinen
                   ` (2 preceding siblings ...)
  2017-10-10 14:32 ` [PATCH RFC v3 03/12] x86: define the feature control MSR's SGX enable bit Jarkko Sakkinen
@ 2017-10-10 14:32 ` Jarkko Sakkinen
  2017-10-10 14:32 ` [PATCH RFC v3 05/12] x86: add SGX MSRs to msr-index.h Jarkko Sakkinen
                   ` (7 subsequent siblings)
  11 siblings, 0 replies; 40+ messages in thread
From: Jarkko Sakkinen @ 2017-10-10 14:32 UTC (permalink / raw)
  To: intel-sgx-kernel-dev; +Cc: platform-driver-x86, Jarkko Sakkinen

Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
---
 arch/x86/include/asm/cpufeatures.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h
index 31a7d1c0f204..43130f3c18a1 100644
--- a/arch/x86/include/asm/cpufeatures.h
+++ b/arch/x86/include/asm/cpufeatures.h
@@ -298,6 +298,7 @@
 #define X86_FEATURE_AVX512_VPOPCNTDQ (16*32+14) /* POPCNT for vectors of DW/QW */
 #define X86_FEATURE_LA57	(16*32+16) /* 5-level page tables */
 #define X86_FEATURE_RDPID	(16*32+22) /* RDPID instruction */
+#define X86_FEATURE_SGX_LC	(16*32+30) /* supports SGX launch configuration */
 
 /* AMD-defined CPU features, CPUID level 0x80000007 (ebx), word 17 */
 #define X86_FEATURE_OVERFLOW_RECOV (17*32+0) /* MCA overflow recovery support */
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH RFC v3 05/12] x86: add SGX MSRs to msr-index.h
  2017-10-10 14:32 [PATCH RFC v3 00/12] Intel(R) SGX Driver Jarkko Sakkinen
                   ` (3 preceding siblings ...)
  2017-10-10 14:32 ` [PATCH RFC v3 04/12] x86: define the feature control MSR's SGX launch control bit Jarkko Sakkinen
@ 2017-10-10 14:32 ` Jarkko Sakkinen
  2017-10-10 14:32 ` [PATCH RFC v3 06/12] fs/pipe.c: export create_pipe_files() and replace_fd() Jarkko Sakkinen
                   ` (6 subsequent siblings)
  11 siblings, 0 replies; 40+ messages in thread
From: Jarkko Sakkinen @ 2017-10-10 14:32 UTC (permalink / raw)
  To: intel-sgx-kernel-dev; +Cc: platform-driver-x86, Haim Cohen, Jarkko Sakkinen

From: Haim Cohen <haim.cohen@intel.com>

These MSRs hold the SHA256 checksum of the currently configured launch
enclave public key.

Signed-off-by: Haim Cohen <haim.cohen@intel.com>
Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
---
 arch/x86/include/asm/msr-index.h | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h
index b35cb98b5d60..22e27d46d046 100644
--- a/arch/x86/include/asm/msr-index.h
+++ b/arch/x86/include/asm/msr-index.h
@@ -436,6 +436,7 @@
 #define FEATURE_CONTROL_VMXON_ENABLED_INSIDE_SMX	(1<<1)
 #define FEATURE_CONTROL_VMXON_ENABLED_OUTSIDE_SMX	(1<<2)
 #define FEATURE_CONTROL_SGX_ENABLE                      (1<<18)
+#define FEATURE_CONTROL_SGX_LAUNCH_CONTROL_ENABLE	(1<<17)
 #define FEATURE_CONTROL_LMCE				(1<<20)
 
 #define MSR_IA32_APICBASE		0x0000001b
@@ -502,6 +503,12 @@
 #define PACKAGE_THERM_INT_LOW_ENABLE		(1 << 1)
 #define PACKAGE_THERM_INT_PLN_ENABLE		(1 << 24)
 
+/* Intel SGX MSRs */
+#define MSR_IA32_SGXLEPUBKEYHASH0	0x0000008C
+#define MSR_IA32_SGXLEPUBKEYHASH1	0x0000008D
+#define MSR_IA32_SGXLEPUBKEYHASH2	0x0000008E
+#define MSR_IA32_SGXLEPUBKEYHASH3	0x0000008F
+
 /* Thermal Thresholds Support */
 #define THERM_INT_THRESHOLD0_ENABLE    (1 << 15)
 #define THERM_SHIFT_THRESHOLD0        8
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH RFC v3 06/12] fs/pipe.c: export create_pipe_files() and replace_fd()
  2017-10-10 14:32 [PATCH RFC v3 00/12] Intel(R) SGX Driver Jarkko Sakkinen
                   ` (4 preceding siblings ...)
  2017-10-10 14:32 ` [PATCH RFC v3 05/12] x86: add SGX MSRs to msr-index.h Jarkko Sakkinen
@ 2017-10-10 14:32 ` Jarkko Sakkinen
  2017-10-10 14:32 ` [PATCH RFC v3 08/12] intel_sgx: ptrace() support Jarkko Sakkinen
                   ` (5 subsequent siblings)
  11 siblings, 0 replies; 40+ messages in thread
From: Jarkko Sakkinen @ 2017-10-10 14:32 UTC (permalink / raw)
  To: intel-sgx-kernel-dev; +Cc: platform-driver-x86, Jarkko Sakkinen

Export create_pipe_files() and replace_fd() so that the SGX driver is
able to create stdin and stdout pipes.

Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
---
 fs/file.c | 1 +
 fs/pipe.c | 1 +
 2 files changed, 2 insertions(+)

diff --git a/fs/file.c b/fs/file.c
index 1fc7fbbb4510..b1fa28919b22 100644
--- a/fs/file.c
+++ b/fs/file.c
@@ -871,6 +871,7 @@ int replace_fd(unsigned fd, struct file *file, unsigned flags)
 	spin_unlock(&files->file_lock);
 	return err;
 }
+EXPORT_SYMBOL_GPL(replace_fd);
 
 SYSCALL_DEFINE3(dup3, unsigned int, oldfd, unsigned int, newfd, int, flags)
 {
diff --git a/fs/pipe.c b/fs/pipe.c
index 97e5be897753..ee33a84127e7 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -784,6 +784,7 @@ int create_pipe_files(struct file **res, int flags)
 	iput(inode);
 	return err;
 }
+EXPORT_SYMBOL_GPL(create_pipe_files);
 
 static int __do_pipe_flags(int *fd, struct file **files, int flags)
 {
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH RFC v3 08/12] intel_sgx: ptrace() support
  2017-10-10 14:32 [PATCH RFC v3 00/12] Intel(R) SGX Driver Jarkko Sakkinen
                   ` (5 preceding siblings ...)
  2017-10-10 14:32 ` [PATCH RFC v3 06/12] fs/pipe.c: export create_pipe_files() and replace_fd() Jarkko Sakkinen
@ 2017-10-10 14:32 ` Jarkko Sakkinen
  2017-10-10 14:32 ` [PATCH RFC v3 09/12] intel_sgx: driver documentation Jarkko Sakkinen
                   ` (4 subsequent siblings)
  11 siblings, 0 replies; 40+ messages in thread
From: Jarkko Sakkinen @ 2017-10-10 14:32 UTC (permalink / raw)
  To: intel-sgx-kernel-dev; +Cc: platform-driver-x86, Jarkko Sakkinen

Implemented VMA callbacks in order to ptrace() debug enclaves.

Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
---
 drivers/platform/x86/intel_sgx/sgx_vma.c | 115 +++++++++++++++++++++++++++++++
 1 file changed, 115 insertions(+)

diff --git a/drivers/platform/x86/intel_sgx/sgx_vma.c b/drivers/platform/x86/intel_sgx/sgx_vma.c
index 29dd09f142c5..f83c0b8c7445 100644
--- a/drivers/platform/x86/intel_sgx/sgx_vma.c
+++ b/drivers/platform/x86/intel_sgx/sgx_vma.c
@@ -108,8 +108,123 @@ static int sgx_vma_fault(struct vm_fault *vmf)
 		return VM_FAULT_SIGBUS;
 }
 
+static inline int sgx_vma_access_word(struct sgx_encl *encl,
+				      unsigned long addr,
+				      void *buf,
+				      int len,
+				      int write,
+				      struct sgx_encl_page *encl_page,
+				      int i)
+{
+	char data[sizeof(unsigned long)];
+	int align, cnt, offset;
+	void *vaddr;
+	int ret;
+
+	offset = ((addr + i) & (PAGE_SIZE - 1)) & ~(sizeof(unsigned long) - 1);
+	align = (addr + i) & (sizeof(unsigned long) - 1);
+	cnt = sizeof(unsigned long) - align;
+	cnt = min(cnt, len - i);
+
+	if (write) {
+		if (encl_page->flags & SGX_ENCL_PAGE_TCS &&
+		    (offset < 8 || (offset + (len - i)) > 16))
+			return -ECANCELED;
+
+		if (align || (cnt != sizeof(unsigned long))) {
+			vaddr = sgx_get_page(encl_page->epc_page);
+			ret = __edbgrd((void *)((unsigned long)vaddr + offset),
+				       (unsigned long *)data);
+			sgx_put_page(vaddr);
+			if (ret) {
+				sgx_dbg(encl, "EDBGRD returned %d\n", ret);
+				return -EFAULT;
+			}
+		}
+
+		memcpy(data + align, buf + i, cnt);
+		vaddr = sgx_get_page(encl_page->epc_page);
+		ret = __edbgwr((void *)((unsigned long)vaddr + offset),
+			       (unsigned long *)data);
+		sgx_put_page(vaddr);
+		if (ret) {
+			sgx_dbg(encl, "EDBGWR returned %d\n", ret);
+			return -EFAULT;
+		}
+	} else {
+		if (encl_page->flags & SGX_ENCL_PAGE_TCS &&
+		    (offset + (len - i)) > 72)
+			return -ECANCELED;
+
+		vaddr = sgx_get_page(encl_page->epc_page);
+		ret = __edbgrd((void *)((unsigned long)vaddr + offset),
+			       (unsigned long *)data);
+		sgx_put_page(vaddr);
+		if (ret) {
+			sgx_dbg(encl, "EDBGRD returned %d\n", ret);
+			return -EFAULT;
+		}
+
+		memcpy(buf + i, data + align, cnt);
+	}
+
+	return cnt;
+}
+
+static int sgx_vma_access(struct vm_area_struct *vma, unsigned long addr,
+			  void *buf, int len, int write)
+{
+	struct sgx_encl *encl = vma->vm_private_data;
+	struct sgx_encl_page *entry = NULL;
+	const char *op_str = write ? "EDBGWR" : "EDBGRD";
+	int ret = 0;
+	int i;
+
+	/* If process was forked, VMA is still there but vm_private_data is set
+	 * to NULL.
+	 */
+	if (!encl)
+		return -EFAULT;
+
+	if (!(encl->flags & SGX_ENCL_DEBUG) ||
+	    !(encl->flags & SGX_ENCL_INITIALIZED) ||
+	    (encl->flags & SGX_ENCL_DEAD))
+		return -EFAULT;
+
+	sgx_dbg(encl, "%s addr=0x%lx, len=%d\n", op_str, addr, len);
+
+	for (i = 0; i < len; i += ret) {
+		if (!entry || !((addr + i) & (PAGE_SIZE - 1))) {
+			if (entry)
+				entry->flags &= ~SGX_ENCL_PAGE_RESERVED;
+
+			entry = sgx_fault_page(vma, (addr + i) & PAGE_MASK,
+					       SGX_FAULT_RESERVE);
+			if (IS_ERR(entry)) {
+				ret = PTR_ERR(entry);
+				entry = NULL;
+				break;
+			}
+		}
+
+		/* No locks are needed because used fields are immutable after
+		 * intialization.
+		 */
+		ret = sgx_vma_access_word(encl, addr, buf, len, write,
+					  entry, i);
+		if (ret < 0)
+			break;
+	}
+
+	if (entry)
+		entry->flags &= ~SGX_ENCL_PAGE_RESERVED;
+
+	return (ret < 0 && ret != -ECANCELED) ? ret : i;
+}
+
 const struct vm_operations_struct sgx_vm_ops = {
 	.close = sgx_vma_close,
 	.open = sgx_vma_open,
 	.fault = sgx_vma_fault,
+	.access = sgx_vma_access,
 };
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH RFC v3 09/12] intel_sgx: driver documentation
  2017-10-10 14:32 [PATCH RFC v3 00/12] Intel(R) SGX Driver Jarkko Sakkinen
                   ` (6 preceding siblings ...)
  2017-10-10 14:32 ` [PATCH RFC v3 08/12] intel_sgx: ptrace() support Jarkko Sakkinen
@ 2017-10-10 14:32 ` Jarkko Sakkinen
  2017-10-10 14:32 ` [PATCH RFC v3 10/12] intel_sgx: in-kernel launch enclave Jarkko Sakkinen
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 40+ messages in thread
From: Jarkko Sakkinen @ 2017-10-10 14:32 UTC (permalink / raw)
  To: intel-sgx-kernel-dev; +Cc: platform-driver-x86, Jarkko Sakkinen

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain; charset=a, Size: 5990 bytes --]

Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
---
 Documentation/index.rst         |   1 +
 Documentation/x86/intel_sgx.rst | 131 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 132 insertions(+)
 create mode 100644 Documentation/x86/intel_sgx.rst

diff --git a/Documentation/index.rst b/Documentation/index.rst
index cb7f1ba5b3b1..ccfebc260e04 100644
--- a/Documentation/index.rst
+++ b/Documentation/index.rst
@@ -86,6 +86,7 @@ implementation.
    :maxdepth: 2
 
    sh/index
+   x86/index
 
 Korean translations
 -------------------
diff --git a/Documentation/x86/intel_sgx.rst b/Documentation/x86/intel_sgx.rst
new file mode 100644
index 000000000000..ee7fe9487d7b
--- /dev/null
+++ b/Documentation/x86/intel_sgx.rst
@@ -0,0 +1,131 @@
+===================
+Intel(R) SGX driver
+===================
+
+Introduction
+============
+
+Intel(R) SGX is a set of CPU instructions that can be used by applications to
+set aside private regions of code and data. The code outside the enclave is
+disallowed to access the memory inside the enclave by the CPU access control.
+In a way you can think that SGX provides inverted sandbox. It protects the
+application from a malicious host.
+
+There is a new hardware unit in the processor called Memory Encryption Engine
+(MEE) starting from the Skylake microachitecture. BIOS can define one or many
+MEE regions that can hold enclave data by configuring them with PRMRR registers.
+
+The MEE automatically encrypts the data leaving the processor package to the MEE
+regions. The data is encrypted using a random key whose life-time is exactly one
+power cycle.
+
+You can tell if your CPU supports SGX by looking into ``/proc/cpuinfo``:
+
+	``cat /proc/cpuinfo  | grep ' sgx '``
+
+Enclave data types
+==================
+
+SGX defines new data types to maintain information about the enclaves and their
+security properties.
+
+The following data structures exist in MEE regions:
+
+* **Enclave Page Cache (EPC):** memory pages for protected code and data
+* **Enclave Page Cache Map (EPCM):** meta-data for each EPC page
+
+The Enclave Page Cache holds following types of pages:
+
+* **SGX Enclave Control Structure (SECS)**: meta-data defining the global
+  properties of an enclave such as range of addresses it can access.
+* **Regular (REG):** containing code and data for the enclave.
+* **Thread Control Structure (TCS):** defines an entry point for a hardware
+  thread to enter into the enclave. The enclave can only be entered through
+  these entry points.
+* **Version Array (VA)**: an EPC page receives a unique 8 byte version number
+  when it is swapped, which is then stored into a VA page. A VA page can hold up
+  to 512 version numbers.
+
+Launch control
+==============
+
+For launching an enclave, two structures must be provided for ENCLS(EINIT):
+
+1. **SIGSTRUCT:** a signed measurement of the enclave binary.
+2. **EINITTOKEN:** the measurement, the public key of the signer and various
+   enclave attributes. This structure contains a MAC of its contents using
+   hardware derived symmetric key called *launch key*.
+
+The hardware platform contains a root key pair for signing the SIGTRUCT
+for a *launch enclave* that is able to acquire the *launch key* for
+creating EINITTOKEN's for other enclaves.  For the launch enclave
+EINITTOKEN is not needed because it is signed with the private root key.
+
+There are two feature control bits associate with launch control
+
+* **IA32_FEATURE_CONTROL[0]**: locks down the feature control register
+* **IA32_FEATURE_CONTROL[17]**: allow runtime reconfiguration of
+  IA32_SGXLEPUBKEYHASHn MSRs that define MRSIGNER hash for the launch
+  enclave. Essentially they define a signing key that does not require
+  EINITTOKEN to be let run.
+
+The BIOS can configure IA32_SGXLEPUBKEYHASHn MSRs before feature control
+register is locked.
+
+It could be tempting to implement launch control by writing the MSRs
+every time when an enclave is launched. This does not scale because for
+generic case because BIOS might lock down the MSRs before handover to
+the OS.
+
+Debug enclaves
+--------------
+
+Enclave can be set as a *debug enclave* of which memory can be read or written
+by using the ENCLS(EDBGRD) and ENCLS(EDBGWR) opcodes. The Intel provided launch
+enclave provides them always a valid EINITTOKEN and therefore they are a low
+hanging fruit way to try out SGX.
+
+Virtualization
+==============
+
+Launch control
+--------------
+
+The values for IA32_SGXLEPUBKEYHASHn MSRs cannot be emulated for a virtual
+machine guest. It would easily seem feasible to hold virtual values for these
+MSRs, trap ENCLS(EINIT) and use the host LE to generate a token when a guest LE
+is initialized.
+
+However, looking at the pseudo code of ENCLS(EINIT) from the SDM there is a
+constraint that the instruction will fail if ATTRIBUTES.EINITTOKENKEY is set
+(the documentation does not tell the reason why the constraint exists but it
+exists).
+
+Thus, only when the MSRs are left unlocked before handover to the OS the
+setting of these MSRs can be supported for VM guests.
+
+Suspend and resume
+------------------
+
+If the host suspends and resumes, the enclave memory for the VM guest could
+become invalid. This can make ENCLS leaf operations suddenly fail.
+
+The driver has a graceful fallback mechanism to manage this situation. If any of
+the ENCLS leaf operations fail, the driver will fallback by kicking threads out
+of the enclave, removing the TCS entries and marking enclave as invalid. After
+this no new pages can be allocated for the enclave and no entry can be done.
+
+SGX uapi
+========
+
+.. kernel-doc:: drivers/platform/x86/intel_sgx_ioctl.c
+   :functions: sgx_ioc_enclave_create
+               sgx_ioc_enclave_add_page
+               sgx_ioc_enclave_init
+
+.. kernel-doc:: arch/x86/include/uapi/asm/sgx.h
+
+References
+==========
+
+* System Programming Manual: 39.1.4 Intel® SGX Launch Control Configuration
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH RFC v3 10/12] intel_sgx: in-kernel launch enclave
  2017-10-10 14:32 [PATCH RFC v3 00/12] Intel(R) SGX Driver Jarkko Sakkinen
                   ` (7 preceding siblings ...)
  2017-10-10 14:32 ` [PATCH RFC v3 09/12] intel_sgx: driver documentation Jarkko Sakkinen
@ 2017-10-10 14:32 ` Jarkko Sakkinen
  2017-11-08 20:07   ` [intel-sgx-kernel-dev] " Sean Christopherson
  2017-10-10 14:32 ` [PATCH RFC v3 11/12] intel_sgx: glue code for in-kernel LE Jarkko Sakkinen
                   ` (2 subsequent siblings)
  11 siblings, 1 reply; 40+ messages in thread
From: Jarkko Sakkinen @ 2017-10-10 14:32 UTC (permalink / raw)
  To: intel-sgx-kernel-dev; +Cc: platform-driver-x86, Jarkko Sakkinen

This commits implements the in-kernel launch enclave. It is wrapped into
a user space program that reads SIGSTRUCT instances from stdin and
outputs launch tokens to stdout.

The commit also adds enclave signing tool that is used by kbuild to
measure and sign the lauch enclave.

CONFIG_INTEL_SGX_SIGNING_KEY points to a PEM-file for the 3072-bit RSA
key that is used as the LE public key pair. The default location is:

  drivers/platform/x86/intel_sgx/intel_sgx_signing_key.pem

If the default key does not exist kbuild will generate a random key and
place it to this location. KBUILD_SGX_SIGN_PIN can be used to specify
the passphrase for the LE public key.

TinyCrypt (https://github.com/01org/tinycrypt) is used as AES
implementation, which is not timing resistant. Eventually this needs to
be replaced with AES-NI based implementation that could be either

- re-use existing AES-NI code in the kernel
- have its own hand written code

Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
---
 drivers/platform/x86/intel_sgx/Kconfig             |  13 +
 drivers/platform/x86/intel_sgx/Makefile            |  18 +
 drivers/platform/x86/intel_sgx/le/Makefile         |  26 +
 drivers/platform/x86/intel_sgx/le/enclave/Makefile |  46 ++
 .../x86/intel_sgx/le/enclave/aes_encrypt.c         | 191 ++++++++
 .../platform/x86/intel_sgx/le/enclave/cmac_mode.c  | 254 ++++++++++
 .../x86/intel_sgx/le/enclave/encl_bootstrap.S      | 163 +++++++
 .../intel_sgx/le/enclave/include/tinycrypt/aes.h   | 133 +++++
 .../le/enclave/include/tinycrypt/cmac_mode.h       | 194 ++++++++
 .../le/enclave/include/tinycrypt/constants.h       |  59 +++
 .../intel_sgx/le/enclave/include/tinycrypt/utils.h |  95 ++++
 drivers/platform/x86/intel_sgx/le/enclave/main.c   | 203 ++++++++
 .../platform/x86/intel_sgx/le/enclave/sgx_le.lds   |  28 ++
 .../platform/x86/intel_sgx/le/enclave/sgxsign.c    | 537 +++++++++++++++++++++
 drivers/platform/x86/intel_sgx/le/enclave/utils.c  |  78 +++
 drivers/platform/x86/intel_sgx/le/entry.S          | 117 +++++
 .../platform/x86/intel_sgx/le/include/sgx_asm.h    |  64 +++
 .../platform/x86/intel_sgx/le/include/sgx_encl.h   | 105 ++++
 drivers/platform/x86/intel_sgx/le/main.c           | 219 +++++++++
 drivers/platform/x86/intel_sgx/le/sgx_le_piggy.S   |  15 +
 .../platform/x86/intel_sgx/sgx_le_proxy_piggy.S    |  11 +
 21 files changed, 2569 insertions(+)
 create mode 100644 drivers/platform/x86/intel_sgx/le/Makefile
 create mode 100644 drivers/platform/x86/intel_sgx/le/enclave/Makefile
 create mode 100644 drivers/platform/x86/intel_sgx/le/enclave/aes_encrypt.c
 create mode 100644 drivers/platform/x86/intel_sgx/le/enclave/cmac_mode.c
 create mode 100644 drivers/platform/x86/intel_sgx/le/enclave/encl_bootstrap.S
 create mode 100644 drivers/platform/x86/intel_sgx/le/enclave/include/tinycrypt/aes.h
 create mode 100644 drivers/platform/x86/intel_sgx/le/enclave/include/tinycrypt/cmac_mode.h
 create mode 100644 drivers/platform/x86/intel_sgx/le/enclave/include/tinycrypt/constants.h
 create mode 100644 drivers/platform/x86/intel_sgx/le/enclave/include/tinycrypt/utils.h
 create mode 100644 drivers/platform/x86/intel_sgx/le/enclave/main.c
 create mode 100644 drivers/platform/x86/intel_sgx/le/enclave/sgx_le.lds
 create mode 100644 drivers/platform/x86/intel_sgx/le/enclave/sgxsign.c
 create mode 100644 drivers/platform/x86/intel_sgx/le/enclave/utils.c
 create mode 100644 drivers/platform/x86/intel_sgx/le/entry.S
 create mode 100644 drivers/platform/x86/intel_sgx/le/include/sgx_asm.h
 create mode 100644 drivers/platform/x86/intel_sgx/le/include/sgx_encl.h
 create mode 100644 drivers/platform/x86/intel_sgx/le/main.c
 create mode 100644 drivers/platform/x86/intel_sgx/le/sgx_le_piggy.S
 create mode 100644 drivers/platform/x86/intel_sgx/sgx_le_proxy_piggy.S

diff --git a/drivers/platform/x86/intel_sgx/Kconfig b/drivers/platform/x86/intel_sgx/Kconfig
index 5c7e61ecb524..9c445e9f89fa 100644
--- a/drivers/platform/x86/intel_sgx/Kconfig
+++ b/drivers/platform/x86/intel_sgx/Kconfig
@@ -2,6 +2,8 @@
 # Intel SGX
 #
 
+menu "Intel SGX"
+
 config INTEL_SGX
 	tristate "Intel(R) SGX Driver"
 	default n
@@ -17,3 +19,14 @@ config INTEL_SGX
 	called Enclave Page Cache (EPC). There is a hardware unit in the
 	processor called Memory Encryption Engine. The MEE encrypts and decrypts
 	the EPC pages as they enter and leave the processor package.
+
+
+config INTEL_SGX_SIGNING_KEY
+	string "Path to the Intel SGX LE signing key"
+	default "drivers/platform/x86/intel_sgx/intel_sgx_signing_key.pem"
+	depends on INTEL_SGX
+	---help---
+	Provide a path to a 3072-bit RSA private key that will be used to
+	sign the launch enclave.
+
+endmenu
diff --git a/drivers/platform/x86/intel_sgx/Makefile b/drivers/platform/x86/intel_sgx/Makefile
index 92af94668508..39c0a5ad242c 100644
--- a/drivers/platform/x86/intel_sgx/Makefile
+++ b/drivers/platform/x86/intel_sgx/Makefile
@@ -11,3 +11,21 @@ intel_sgx-$(CONFIG_INTEL_SGX) += \
 	sgx_page_cache.o \
 	sgx_util.o \
 	sgx_vma.o \
+	sgx_le_proxy_piggy.o
+
+$(eval $(call config_filename,INTEL_SGX_SIGNING_KEY))
+
+INTEL_SGX_SIGNING_KEY_PATH := \
+	$(INTEL_SGX_SIGNING_KEY_SRCPREFIX)$(INTEL_SGX_SIGNING_KEY_FILENAME)
+
+ifeq ($(CONFIG_INTEL_SGX_SIGNING_KEY),"drivers/platform/x86/intel_sgx/intel_sgx_signing_key.pem")
+$(INTEL_SGX_SIGNING_KEY_PATH):
+	$(Q)openssl genrsa -3 -out $(INTEL_SGX_SIGNING_KEY_PATH) 3072
+endif
+
+$(obj)/sgx_le_proxy_piggy.o: $(INTEL_SGX_SIGNING_KEY_PATH) \
+			     $(obj)/le/sgx_le_proxy
+$(obj)/le/sgx_le_proxy: FORCE
+	$(Q)$(MAKE) $(build)=$(obj)/le $@
+
+export INTEL_SGX_SIGNING_KEY_PATH
diff --git a/drivers/platform/x86/intel_sgx/le/Makefile b/drivers/platform/x86/intel_sgx/le/Makefile
new file mode 100644
index 000000000000..50fe1849f6ca
--- /dev/null
+++ b/drivers/platform/x86/intel_sgx/le/Makefile
@@ -0,0 +1,26 @@
+KASAN_SANITIZE := n
+OBJECT_FILES_NON_STANDARD := y
+KCOV_INSTRUMENT := n
+KBUILD_CFLAGS := -Wall -Werror -static -nostdlib -nostartfiles -I$(obj)/include
+KBUILD_AFLAGS += -I$(obj)/include
+
+subdir- := enclave
+
+always := sgx_le_proxy
+clean-files := sgx_le_proxy
+
+#
+# sgx_le_proxy
+#
+
+sgx_le_proxy-y += main.o entry.o sgx_le_piggy.o
+targets += $(sgx_le_proxy-y)
+SGX_LE_PROXY_OBJS = $(addprefix $(obj)/,$(sgx_le_proxy-y))
+
+$(obj)/sgx_le_piggy.o: $(obj)/enclave/sgx_le.bin $(obj)/enclave/sgx_le.ss
+$(obj)/enclave/sgx_le.bin $(obj)/enclave/sgx_le.ss: FORCE
+	$(Q)$(MAKE) $(build)=$(obj)/enclave $@
+
+targets += sgx_le_proxy
+$(obj)/sgx_le_proxy: $(SGX_LE_PROXY_OBJS)
+	$(call if_changed,ld)
diff --git a/drivers/platform/x86/intel_sgx/le/enclave/Makefile b/drivers/platform/x86/intel_sgx/le/enclave/Makefile
new file mode 100644
index 000000000000..dbe3d41a9a8c
--- /dev/null
+++ b/drivers/platform/x86/intel_sgx/le/enclave/Makefile
@@ -0,0 +1,46 @@
+KASAN_SANITIZE := n
+OBJECT_FILES_NON_STANDARD := y
+KCOV_INSTRUMENT := n
+KBUILD_CFLAGS := -Wall -Werror -static -nostdlib -nostartfiles -fPIC \
+		 -fno-stack-protector -mrdrnd  -I$(obj)/../include \
+		 -I$(obj)/include -I$(srctree)/arch/x86/include
+
+always := sgx_le.elf sgx_le.bin sgx_le.ss
+clean-files := sgx_le.elf sgx_le.bin sgx_le.ss
+
+#
+# sgx_le.ss
+#
+
+HOST_EXTRACFLAGS += -I$(srctree)/arch/x86/include
+HOSTLOADLIBES_sgxsign = -lcrypto
+hostprogs-y += sgxsign
+quiet_cmd_sgxsign = SGXSIGN $@
+      cmd_sgxsign = drivers/platform/x86/intel_sgx/le/enclave/sgxsign \
+		    $(INTEL_SGX_SIGNING_KEY_PATH) $< $@
+
+targets += sgx_le.ss
+$(obj)/sgx_le.ss: $(obj)/sgx_le.bin $(obj)/sgxsign FORCE
+	$(call if_changed,sgxsign)
+
+#
+# sgx_le.bin
+#
+
+targets += sgx_le.bin
+OBJCOPYFLAGS_sgx_le.bin := --remove-section=.got.plt -O binary
+$(obj)/sgx_le.bin: $(obj)/sgx_le.elf FORCE
+	$(call if_changed,objcopy)
+
+#
+# sgx_le.elf
+#
+
+sgx_le-y +=  main.o encl_bootstrap.o aes_encrypt.o cmac_mode.o utils.o
+targets += $(sgx_le-y)
+SGX_LE_OBJS = $(addprefix $(obj)/,$(sgx_le-y))
+
+targets += sgx_le.elf
+LDFLAGS_sgx_le.elf := -T
+$(obj)/sgx_le.elf: $(obj)/sgx_le.lds $(SGX_LE_OBJS)
+	$(call if_changed,ld)
diff --git a/drivers/platform/x86/intel_sgx/le/enclave/aes_encrypt.c b/drivers/platform/x86/intel_sgx/le/enclave/aes_encrypt.c
new file mode 100644
index 000000000000..6bc73a581037
--- /dev/null
+++ b/drivers/platform/x86/intel_sgx/le/enclave/aes_encrypt.c
@@ -0,0 +1,191 @@
+/* aes_encrypt.c - TinyCrypt implementation of AES encryption procedure */
+
+/*
+ *  Copyright (C) 2015 by Intel Corporation, All Rights Reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are met:
+ *
+ *    - Redistributions of source code must retain the above copyright notice,
+ *     this list of conditions and the following disclaimer.
+ *
+ *    - Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ *    - Neither the name of Intel Corporation nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ *  POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <tinycrypt/aes.h>
+#include <tinycrypt/utils.h>
+#include <tinycrypt/constants.h>
+
+static const uint8_t sbox[256] = {
+	0x63, 0x7c, 0x77, 0x7b, 0xf2, 0x6b, 0x6f, 0xc5, 0x30, 0x01, 0x67, 0x2b,
+	0xfe, 0xd7, 0xab, 0x76, 0xca, 0x82, 0xc9, 0x7d, 0xfa, 0x59, 0x47, 0xf0,
+	0xad, 0xd4, 0xa2, 0xaf, 0x9c, 0xa4, 0x72, 0xc0, 0xb7, 0xfd, 0x93, 0x26,
+	0x36, 0x3f, 0xf7, 0xcc, 0x34, 0xa5, 0xe5, 0xf1, 0x71, 0xd8, 0x31, 0x15,
+	0x04, 0xc7, 0x23, 0xc3, 0x18, 0x96, 0x05, 0x9a, 0x07, 0x12, 0x80, 0xe2,
+	0xeb, 0x27, 0xb2, 0x75, 0x09, 0x83, 0x2c, 0x1a, 0x1b, 0x6e, 0x5a, 0xa0,
+	0x52, 0x3b, 0xd6, 0xb3, 0x29, 0xe3, 0x2f, 0x84, 0x53, 0xd1, 0x00, 0xed,
+	0x20, 0xfc, 0xb1, 0x5b, 0x6a, 0xcb, 0xbe, 0x39, 0x4a, 0x4c, 0x58, 0xcf,
+	0xd0, 0xef, 0xaa, 0xfb, 0x43, 0x4d, 0x33, 0x85, 0x45, 0xf9, 0x02, 0x7f,
+	0x50, 0x3c, 0x9f, 0xa8, 0x51, 0xa3, 0x40, 0x8f, 0x92, 0x9d, 0x38, 0xf5,
+	0xbc, 0xb6, 0xda, 0x21, 0x10, 0xff, 0xf3, 0xd2, 0xcd, 0x0c, 0x13, 0xec,
+	0x5f, 0x97, 0x44, 0x17, 0xc4, 0xa7, 0x7e, 0x3d, 0x64, 0x5d, 0x19, 0x73,
+	0x60, 0x81, 0x4f, 0xdc, 0x22, 0x2a, 0x90, 0x88, 0x46, 0xee, 0xb8, 0x14,
+	0xde, 0x5e, 0x0b, 0xdb, 0xe0, 0x32, 0x3a, 0x0a, 0x49, 0x06, 0x24, 0x5c,
+	0xc2, 0xd3, 0xac, 0x62, 0x91, 0x95, 0xe4, 0x79, 0xe7, 0xc8, 0x37, 0x6d,
+	0x8d, 0xd5, 0x4e, 0xa9, 0x6c, 0x56, 0xf4, 0xea, 0x65, 0x7a, 0xae, 0x08,
+	0xba, 0x78, 0x25, 0x2e, 0x1c, 0xa6, 0xb4, 0xc6, 0xe8, 0xdd, 0x74, 0x1f,
+	0x4b, 0xbd, 0x8b, 0x8a, 0x70, 0x3e, 0xb5, 0x66, 0x48, 0x03, 0xf6, 0x0e,
+	0x61, 0x35, 0x57, 0xb9, 0x86, 0xc1, 0x1d, 0x9e, 0xe1, 0xf8, 0x98, 0x11,
+	0x69, 0xd9, 0x8e, 0x94, 0x9b, 0x1e, 0x87, 0xe9, 0xce, 0x55, 0x28, 0xdf,
+	0x8c, 0xa1, 0x89, 0x0d, 0xbf, 0xe6, 0x42, 0x68, 0x41, 0x99, 0x2d, 0x0f,
+	0xb0, 0x54, 0xbb, 0x16
+};
+
+static inline uint32_t rotword(uint32_t a)
+{
+	return (((a) >> 24)|((a) << 8));
+}
+
+#define subbyte(a, o)(sbox[((a) >> (o))&0xff] << (o))
+#define subword(a)(subbyte(a, 24)|subbyte(a, 16)|subbyte(a, 8)|subbyte(a, 0))
+
+int32_t tc_aes128_set_encrypt_key(TCAesKeySched_t s, const uint8_t *k)
+{
+	const uint32_t rconst[11] = {
+	0x00000000, 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000,
+	0x20000000, 0x40000000, 0x80000000, 0x1b000000, 0x36000000
+	};
+	uint32_t i;
+	uint32_t t;
+
+	if (s == (TCAesKeySched_t) 0) {
+		return TC_CRYPTO_FAIL;
+	} else if (k == (const uint8_t *) 0) {
+		return TC_CRYPTO_FAIL;
+	}
+
+	for (i = 0; i < Nk; ++i) {
+		s->words[i] = (k[Nb*i]<<24) | (k[Nb*i+1]<<16) |
+			      (k[Nb*i+2]<<8) | (k[Nb*i+3]);
+	}
+
+	for (; i < (Nb*(Nr+1)); ++i) {
+		t = s->words[i-1];
+		if ((i % Nk) == 0) {
+			t = subword(rotword(t)) ^ rconst[i/Nk];
+		}
+		s->words[i] = s->words[i-Nk] ^ t;
+	}
+
+	return TC_CRYPTO_SUCCESS;
+}
+
+static inline void add_round_key(uint8_t *s, const uint32_t *k)
+{
+	s[0] ^= (uint8_t)(k[0] >> 24); s[1] ^= (uint8_t)(k[0] >> 16);
+	s[2] ^= (uint8_t)(k[0] >> 8); s[3] ^= (uint8_t)(k[0]);
+	s[4] ^= (uint8_t)(k[1] >> 24); s[5] ^= (uint8_t)(k[1] >> 16);
+	s[6] ^= (uint8_t)(k[1] >> 8); s[7] ^= (uint8_t)(k[1]);
+	s[8] ^= (uint8_t)(k[2] >> 24); s[9] ^= (uint8_t)(k[2] >> 16);
+	s[10] ^= (uint8_t)(k[2] >> 8); s[11] ^= (uint8_t)(k[2]);
+	s[12] ^= (uint8_t)(k[3] >> 24); s[13] ^= (uint8_t)(k[3] >> 16);
+	s[14] ^= (uint8_t)(k[3] >> 8); s[15] ^= (uint8_t)(k[3]);
+}
+
+static inline void sub_bytes(uint8_t *s)
+{
+	uint32_t i;
+
+	for (i = 0; i < (Nb*Nk); ++i) {
+		s[i] = sbox[s[i]];
+	}
+}
+
+#define triple(a)(_double_byte(a)^(a))
+
+static inline void mult_row_column(uint8_t *out, const uint8_t *in)
+{
+	out[0] = _double_byte(in[0]) ^ triple(in[1]) ^ in[2] ^ in[3];
+	out[1] = in[0] ^ _double_byte(in[1]) ^ triple(in[2]) ^ in[3];
+	out[2] = in[0] ^ in[1] ^ _double_byte(in[2]) ^ triple(in[3]);
+	out[3] = triple(in[0]) ^ in[1] ^ in[2] ^ _double_byte(in[3]);
+}
+
+static inline void mix_columns(uint8_t *s)
+{
+	uint8_t t[Nb*Nk];
+
+	mult_row_column(t, s);
+	mult_row_column(&t[Nb], s+Nb);
+	mult_row_column(&t[2*Nb], s+(2*Nb));
+	mult_row_column(&t[3*Nb], s+(3*Nb));
+	(void) _copy(s, sizeof(t), t, sizeof(t));
+}
+
+/*
+ * This shift_rows also implements the matrix flip required for mix_columns, but
+ * performs it here to reduce the number of memory operations.
+ */
+static inline void shift_rows(uint8_t *s)
+{
+	uint8_t t[Nb*Nk];
+
+	t[0]  = s[0]; t[1] = s[5]; t[2] = s[10]; t[3] = s[15];
+	t[4]  = s[4]; t[5] = s[9]; t[6] = s[14]; t[7] = s[3];
+	t[8]  = s[8]; t[9] = s[13]; t[10] = s[2]; t[11] = s[7];
+	t[12] = s[12]; t[13] = s[1]; t[14] = s[6]; t[15] = s[11];
+	(void) _copy(s, sizeof(t), t, sizeof(t));
+}
+
+int32_t tc_aes_encrypt(uint8_t *out, const uint8_t *in, const TCAesKeySched_t s)
+{
+	uint8_t state[Nk*Nb];
+	uint32_t i;
+
+	if (out == (uint8_t *) 0) {
+		return TC_CRYPTO_FAIL;
+	} else if (in == (const uint8_t *) 0) {
+		return TC_CRYPTO_FAIL;
+	} else if (s == (TCAesKeySched_t) 0) {
+		return TC_CRYPTO_FAIL;
+	}
+
+	(void)_copy(state, sizeof(state), in, sizeof(state));
+	add_round_key(state, s->words);
+
+	for (i = 0; i < (Nr-1); ++i) {
+		sub_bytes(state);
+		shift_rows(state);
+		mix_columns(state);
+		add_round_key(state, s->words + Nb*(i+1));
+	}
+
+	sub_bytes(state);
+	shift_rows(state);
+	add_round_key(state, s->words + Nb*(i+1));
+
+	(void)_copy(out, sizeof(state), state, sizeof(state));
+
+	/* zeroing out the state buffer */
+	_set(state, TC_ZERO_BYTE, sizeof(state));
+
+	return TC_CRYPTO_SUCCESS;
+}
diff --git a/drivers/platform/x86/intel_sgx/le/enclave/cmac_mode.c b/drivers/platform/x86/intel_sgx/le/enclave/cmac_mode.c
new file mode 100644
index 000000000000..0da74d1c4aa5
--- /dev/null
+++ b/drivers/platform/x86/intel_sgx/le/enclave/cmac_mode.c
@@ -0,0 +1,254 @@
+/* cmac_mode.c - TinyCrypt CMAC mode implementation */
+
+/*
+ *  Copyright (C) 2015 by Intel Corporation, All Rights Reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are met:
+ *
+ *    - Redistributions of source code must retain the above copyright notice,
+ *     this list of conditions and the following disclaimer.
+ *
+ *    - Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ *    - Neither the name of Intel Corporation nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ *  POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <tinycrypt/aes.h>
+#include <tinycrypt/cmac_mode.h>
+#include <tinycrypt/constants.h>
+#include <tinycrypt/utils.h>
+
+/* max number of calls until change the key (2^48).*/
+const static uint64_t MAX_CALLS = ((uint64_t)1 << 48);
+
+/*
+ *  gf_wrap -- In our implementation, GF(2^128) is represented as a 16 byte
+ *  array with byte 0 the most significant and byte 15 the least significant.
+ *  High bit carry reduction is based on the primitive polynomial
+ *
+ *                     X^128 + X^7 + X^2 + X + 1,
+ *
+ *  which leads to the reduction formula X^128 = X^7 + X^2 + X + 1. Indeed,
+ *  since 0 = (X^128 + X^7 + X^2 + 1) mod (X^128 + X^7 + X^2 + X + 1) and since
+ *  addition of polynomials with coefficients in Z/Z(2) is just XOR, we can
+ *  add X^128 to both sides to get
+ *
+ *       X^128 = (X^7 + X^2 + X + 1) mod (X^128 + X^7 + X^2 + X + 1)
+ *
+ *  and the coefficients of the polynomial on the right hand side form the
+ *  string 1000 0111 = 0x87, which is the value of gf_wrap.
+ *
+ *  This gets used in the following way. Doubling in GF(2^128) is just a left
+ *  shift by 1 bit, except when the most significant bit is 1. In the latter
+ *  case, the relation X^128 = X^7 + X^2 + X + 1 says that the high order bit
+ *  that overflows beyond 128 bits can be replaced by addition of
+ *  X^7 + X^2 + X + 1 <--> 0x87 to the low order 128 bits. Since addition
+ *  in GF(2^128) is represented by XOR, we therefore only have to XOR 0x87
+ *  into the low order byte after a left shift when the starting high order
+ *  bit is 1.
+ */
+const unsigned char gf_wrap = 0x87;
+
+/*
+ *  assumes: out != NULL and points to a GF(2^n) value to receive the
+ *            doubled value;
+ *           in != NULL and points to a 16 byte GF(2^n) value
+ *            to double;
+ *           the in and out buffers do not overlap.
+ *  effects: doubles the GF(2^n) value pointed to by "in" and places
+ *           the result in the GF(2^n) value pointed to by "out."
+ */
+void gf_double(uint8_t *out, uint8_t *in)
+{
+
+	/* start with low order byte */
+	uint8_t *x = in + (TC_AES_BLOCK_SIZE - 1);
+
+	/* if msb == 1, we need to add the gf_wrap value, otherwise add 0 */
+	uint8_t carry = (in[0] >> 7) ? gf_wrap : 0;
+
+	out += (TC_AES_BLOCK_SIZE - 1);
+	for (;;) {
+		*out-- = (*x << 1) ^ carry;
+		if (x == in) {
+			break;
+		}
+		carry = *x-- >> 7;
+	}
+}
+
+int32_t tc_cmac_setup(TCCmacState_t s, const uint8_t *key, TCAesKeySched_t sched)
+{
+
+	/* input sanity check: */
+	if (s == (TCCmacState_t) 0 ||
+	    key == (const uint8_t *) 0) {
+		return TC_CRYPTO_FAIL;
+	}
+
+	/* put s into a known state */
+	_set(s, 0, sizeof(*s));
+	s->sched = sched;
+
+	/* configure the encryption key used by the underlying block cipher */
+	tc_aes128_set_encrypt_key(s->sched, key);
+
+	/* compute s->K1 and s->K2 from s->iv using s->keyid */
+	_set(s->iv, 0, TC_AES_BLOCK_SIZE);
+	tc_aes_encrypt(s->iv, s->iv, s->sched);
+	gf_double (s->K1, s->iv);
+	gf_double (s->K2, s->K1);
+
+	/* reset s->iv to 0 in case someone wants to compute now */
+	tc_cmac_init(s);
+
+	return TC_CRYPTO_SUCCESS;
+}
+
+int32_t tc_cmac_erase(TCCmacState_t s)
+{
+	if (s == (TCCmacState_t) 0) {
+		return TC_CRYPTO_FAIL;
+	}
+
+	/* destroy the current state */
+	_set(s, 0, sizeof(*s));
+
+	return TC_CRYPTO_SUCCESS;
+}
+
+int32_t tc_cmac_init(TCCmacState_t s)
+{
+	/* input sanity check: */
+	if (s == (TCCmacState_t) 0) {
+		return TC_CRYPTO_FAIL;
+	}
+
+	/* CMAC starts with an all zero initialization vector */
+	_set(s->iv, 0, TC_AES_BLOCK_SIZE);
+
+	/* and the leftover buffer is empty */
+	_set(s->leftover, 0, TC_AES_BLOCK_SIZE);
+	s->leftover_offset = 0;
+
+	/* Set countdown to max number of calls allowed before re-keying: */
+	s->countdown = MAX_CALLS;
+
+	return TC_CRYPTO_SUCCESS;
+}
+
+int32_t tc_cmac_update(TCCmacState_t s, const uint8_t *data, size_t data_length)
+{
+	uint32_t i;
+
+	/* input sanity check: */
+	if (s == (TCCmacState_t) 0) {
+		return TC_CRYPTO_FAIL;
+	}
+	if (data_length == 0) {
+		return  TC_CRYPTO_SUCCESS;
+	}
+	if (data == (const uint8_t *) 0) {
+		return TC_CRYPTO_FAIL;
+	}
+
+	if (s->countdown == 0) {
+		return TC_CRYPTO_FAIL;
+	}
+
+	s->countdown--;
+
+	if (s->leftover_offset > 0) {
+		/* last data added to s didn't end on a TC_AES_BLOCK_SIZE byte boundary */
+		size_t remaining_space = TC_AES_BLOCK_SIZE - s->leftover_offset;
+
+		if (data_length < remaining_space) {
+			/* still not enough data to encrypt this time either */
+			_copy(&s->leftover[s->leftover_offset], data_length, data, data_length);
+			s->leftover_offset += data_length;
+			return TC_CRYPTO_SUCCESS;
+		}
+		/* leftover block is now full; encrypt it first */
+		_copy(&s->leftover[s->leftover_offset],
+		      remaining_space,
+		      data,
+		      remaining_space);
+		data_length -= remaining_space;
+		data += remaining_space;
+		s->leftover_offset = 0;
+
+		for (i = 0; i < TC_AES_BLOCK_SIZE; ++i) {
+			s->iv[i] ^= s->leftover[i];
+		}
+		tc_aes_encrypt(s->iv, s->iv, s->sched);
+	}
+
+	/* CBC encrypt each (except the last) of the data blocks */
+	while (data_length > TC_AES_BLOCK_SIZE) {
+		for (i = 0; i < TC_AES_BLOCK_SIZE; ++i) {
+			s->iv[i] ^= data[i];
+		}
+		tc_aes_encrypt(s->iv, s->iv, s->sched);
+		data += TC_AES_BLOCK_SIZE;
+		data_length  -= TC_AES_BLOCK_SIZE;
+	}
+
+	if (data_length > 0) {
+		/* save leftover data for next time */
+		_copy(s->leftover, data_length, data, data_length);
+		s->leftover_offset = data_length;
+	}
+
+	return TC_CRYPTO_SUCCESS;
+}
+
+int32_t tc_cmac_final(uint8_t *tag, TCCmacState_t s)
+{
+	uint8_t *k;
+	uint32_t i;
+
+	/* input sanity check: */
+	if (tag == (uint8_t *) 0 ||
+	    s == (TCCmacState_t) 0) {
+		return TC_CRYPTO_FAIL;
+	}
+
+	if (s->leftover_offset == TC_AES_BLOCK_SIZE) {
+		/* the last message block is a full-sized block */
+		k = (uint8_t *) s->K1;
+	} else {
+		/* the final message block is not a full-sized  block */
+		size_t remaining = TC_AES_BLOCK_SIZE - s->leftover_offset;
+
+		_set(&s->leftover[s->leftover_offset], 0, remaining);
+		s->leftover[s->leftover_offset] = TC_CMAC_PADDING;
+		k = (uint8_t *) s->K2;
+	}
+	for (i = 0; i < TC_AES_BLOCK_SIZE; ++i) {
+		s->iv[i] ^= s->leftover[i] ^ k[i];
+	}
+
+	tc_aes_encrypt(tag, s->iv, s->sched);
+
+	/* erasing state: */
+	tc_cmac_erase(s);
+
+	return TC_CRYPTO_SUCCESS;
+}
diff --git a/drivers/platform/x86/intel_sgx/le/enclave/encl_bootstrap.S b/drivers/platform/x86/intel_sgx/le/enclave/encl_bootstrap.S
new file mode 100644
index 000000000000..616e000d74ec
--- /dev/null
+++ b/drivers/platform/x86/intel_sgx/le/enclave/encl_bootstrap.S
@@ -0,0 +1,163 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2016, 2017 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License 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.
+ *
+ * Contact Information:
+ * Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
+ * Intel Finland Oy - BIC 0357606-4 - Westendinkatu 7, 02160 Espoo
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2016, 2017 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in
+ *     the documentation and/or other materials provided with the
+ *     distribution.
+ *   * Neither the name of Intel Corporation nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors:
+ *
+ * Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
+ * Haim Cohen <haim.cohen@intel.com>
+ */
+
+#include <sgx_asm.h>
+
+	.section ".tcs", "a"
+	.balign	4096
+
+	.fill	1, 8, 0			# STATE (set by CPU)
+	.fill	1, 8, 0			# FLAGS
+	.long	encl_ssa		# OSSA
+	.fill	1, 4, 0
+	.fill	1, 4, 0			# CSSA (set by CPU)
+	.fill	1, 4, 1			# NSSA
+	.long	encl_entry		# OENTRY
+	.fill	1, 4, 0
+	.fill	1, 8, 0			# AEP (set by EENTER and ERESUME)
+	.fill	1, 8, 0			# OFSBASE
+	.fill	1, 8, 0			# OGSBASE
+	.fill	1, 4, 0xFFFFFFFF 	# FSLIMIT
+	.fill	1, 4, 0xFFFFFFFF	# GSLIMIT
+
+	.text
+
+encl_entry:
+	# %rbx contains the base address for TCS, which is also the first
+	# address inside the enclave. By adding $le_stack_end to it, we get the
+	# absolute address for the stack.
+	lea	(encl_stack)(%rbx), %rax
+	xchg	%rsp, %rax
+	push	%rax
+
+	push	%rcx # push the address after EENTER
+	push	%rbx # push the enclave base address
+
+	call	encl_body
+
+	pop	%rbx # pop the enclave base address
+
+	# Restore XSAVE registers to a synthetic state.
+	mov     $0xFFFFFFFF, %rax
+	mov     $0xFFFFFFFF, %rdx
+	lea	(xsave_area)(%rbx), %rdi
+	fxrstor	(%rdi)
+
+	# Clear GPRs
+	xor     %rcx, %rcx
+	xor     %rdx, %rdx
+	xor     %rdi, %rdi
+	xor     %rsi, %rsi
+	xor     %r8, %r8
+	xor     %r9, %r9
+	xor     %r10, %r10
+	xor     %r11, %r11
+	xor     %r12, %r12
+	xor     %r13, %r13
+	xor     %r14, %r14
+	xor     %r15, %r15
+
+	# Reset status flags
+	add     %rdx, %rdx # OF = SF = AF = CF = 0; ZF = PF = 1
+
+	pop	%rbx # pop the address after EENTER
+
+	# Restore the caller stack.
+	pop	%rax
+	mov	%rax, %rsp
+
+	# EEXIT
+	mov	$4, %rax
+	enclu
+
+	.global sgx_ereport
+sgx_ereport:
+	push	%rbx
+	xor	%rax, %rax /* EREPORT */
+	mov	%rdi, %rbx  /* TARGETINFO */
+	mov	%rsi, %rcx /* REPORTDATA */
+	ENCLU
+	pop	%rbx
+	ret
+
+	.global sgx_egetkey
+sgx_egetkey:
+	push	%rbx
+	mov	$0x01, %rax /* EGETKEY */
+	mov	%rdi, %rbx /* KEYREQUEST */
+	mov	%rsi, %rcx  /* KEY */
+	ENCLU
+	pop	%rbx
+	ret
+
+	.section ".data", "aw"
+
+encl_ssa:
+	.space 4096
+
+xsave_area:
+	.fill	1, 4, 0x037F		# FCW
+	.fill	5, 4, 0
+	.fill	1, 4, 0x1F80		# MXCSR
+	.fill	1, 4, 0xFFFF		# MXCSR_MASK
+	.fill	123, 4, 0
+	.fill	1, 4, 0x80000000	# XCOMP_BV[63] = 1, compaction mode
+	.fill	12, 4, 0
+
+	.balign 4096
+	.space 8192
+encl_stack:
diff --git a/drivers/platform/x86/intel_sgx/le/enclave/include/tinycrypt/aes.h b/drivers/platform/x86/intel_sgx/le/enclave/include/tinycrypt/aes.h
new file mode 100644
index 000000000000..fe6e439d7d9e
--- /dev/null
+++ b/drivers/platform/x86/intel_sgx/le/enclave/include/tinycrypt/aes.h
@@ -0,0 +1,133 @@
+/* aes.h - TinyCrypt interface to an AES-128 implementation */
+
+/*
+ *  Copyright (C) 2015 by Intel Corporation, All Rights Reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are met:
+ *
+ *    - Redistributions of source code must retain the above copyright notice,
+ *     this list of conditions and the following disclaimer.
+ *
+ *    - Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ *    - Neither the name of Intel Corporation nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ *  POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ * @brief -- Interface to an AES-128 implementation.
+ *
+ *  Overview:   AES-128 is a NIST approved block cipher specified in
+ *              FIPS 197. Block ciphers are deterministic algorithms that
+ *              perform a transformation specified by a symmetric key in fixed-
+ *              length data sets, also called blocks.
+ *
+ *  Security:   AES-128 provides approximately 128 bits of security.
+ *
+ *  Usage:      1) call tc_aes128_set_encrypt/decrypt_key to set the key.
+ *
+ *              2) call tc_aes_encrypt/decrypt to process the data.
+ */
+
+#ifndef __TC_AES_H__
+#define __TC_AES_H__
+
+#include <linux/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define Nb (4)  /* number of columns (32-bit words) comprising the state */
+#define Nk (4)  /* number of 32-bit words comprising the key */
+#define Nr (10) /* number of rounds */
+#define TC_AES_BLOCK_SIZE (Nb*Nk)
+#define TC_AES_KEY_SIZE (Nb*Nk)
+
+struct tc_aes_key_sched_struct {
+	uint32_t words[Nb*(Nr+1)];
+};
+typedef struct tc_aes_key_sched_struct *TCAesKeySched_t;
+
+/**
+ *  @brief Set AES-128 encryption key
+ *  Uses key k to initialize s
+ *  @return  returns TC_CRYPTO_SUCCESS (1)
+ *           returns TC_CRYPTO_FAIL (0) if: s == NULL or k == NULL
+ *  @note       This implementation skips the additional steps required for keys
+ *              larger than 128 bits, and must not be used for AES-192 or
+ *              AES-256 key schedule -- see FIPS 197 for details
+ *  @param      s IN/OUT -- initialized struct tc_aes_key_sched_struct
+ *  @param      k IN -- points to the AES key
+ */
+int32_t tc_aes128_set_encrypt_key(TCAesKeySched_t s, const uint8_t *k);
+
+/**
+ *  @brief AES-128 Encryption procedure
+ *  Encrypts contents of in buffer into out buffer under key;
+ *              schedule s
+ *  @note Assumes s was initialized by aes_set_encrypt_key;
+ *              out and in point to 16 byte buffers
+ *  @return  returns TC_CRYPTO_SUCCESS (1)
+ *           returns TC_CRYPTO_FAIL (0) if: out == NULL or in == NULL or s == NULL
+ *  @param out IN/OUT -- buffer to receive ciphertext block
+ *  @param in IN -- a plaintext block to encrypt
+ *  @param s IN -- initialized AES key schedule
+ */
+int32_t tc_aes_encrypt(uint8_t *out,
+		       const uint8_t *in,
+		       const TCAesKeySched_t s);
+
+/**
+ *  @brief Set the AES-128 decryption key
+ *  Uses key k to initialize s
+ *  @return returns TC_CRYPTO_SUCCESS (1)
+ *          returns TC_CRYPTO_FAIL (0) if: s == NULL or k == NULL
+ *  @note       This is the implementation of the straightforward inverse cipher
+ *              using the cipher documented in FIPS-197 figure 12, not the
+ *              equivalent inverse cipher presented in Figure 15
+ *  @warning    This routine skips the additional steps required for keys larger
+ *              than 128, and must not be used for AES-192 or AES-256 key
+ *              schedule -- see FIPS 197 for details
+ *  @param s  IN/OUT -- initialized struct tc_aes_key_sched_struct
+ *  @param k  IN -- points to the AES key
+ */
+int32_t tc_aes128_set_decrypt_key(TCAesKeySched_t s, const uint8_t *k);
+
+/**
+ *  @brief AES-128 Encryption procedure
+ *  Decrypts in buffer into out buffer under key schedule s
+ *  @return returns TC_CRYPTO_SUCCESS (1)
+ *          returns TC_CRYPTO_FAIL (0) if: out is NULL or in is NULL or s is NULL
+ *  @note   Assumes s was initialized by aes_set_encrypt_key
+ *          out and in point to 16 byte buffers
+ *  @param out IN/OUT -- buffer to receive ciphertext block
+ *  @param in IN -- a plaintext block to encrypt
+ *  @param s IN -- initialized AES key schedule
+ */
+int32_t tc_aes_decrypt(uint8_t *out,
+		       const uint8_t *in,
+		       const TCAesKeySched_t s);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/drivers/platform/x86/intel_sgx/le/enclave/include/tinycrypt/cmac_mode.h b/drivers/platform/x86/intel_sgx/le/enclave/include/tinycrypt/cmac_mode.h
new file mode 100644
index 000000000000..9d3f13051dfd
--- /dev/null
+++ b/drivers/platform/x86/intel_sgx/le/enclave/include/tinycrypt/cmac_mode.h
@@ -0,0 +1,194 @@
+/*  cmac_mode.h -- interface to a CMAC implementation */
+
+/*
+ *  Copyright (C) 2015 by Intel Corporation, All Rights Reserved
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are met:
+ *
+ *    - Redistributions of source code must retain the above copyright notice,
+ *     this list of conditions and the following disclaimer.
+ *
+ *    - Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ *    - Neither the name of Intel Corporation nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ *  POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ * @brief Interface to a CMAC implementation.
+ *
+ *  Overview: CMAC is defined NIST in SP 800-38B, and is the standard algorithm
+ *            for computing a MAC using a block cipher. It can compute the MAC
+ *            for a byte string of any length. It is distinguished from CBC-MAC
+ *            in the processing of the final message block; CMAC uses a
+ *            different technique to compute the final message block is full
+ *            size or only partial, while CBC-MAC uses the same technique for
+ *            both. This difference permits CMAC to be applied to variable
+ *            length messages, while all messages authenticated by CBC-MAC must
+ *            be the same length.
+ *
+ *  Security: AES128-CMAC mode of operation offers 64 bits of security against
+ *            collision attacks. Note however that an external attacker cannot
+ *            generate the tags him/herself without knowing the MAC key. In this
+ *            sense, to attack the collision property of AES128-CMAC, an
+ *            external attacker would need the cooperation of the legal user to
+ *            produce an exponentially high number of tags (e.g. 2^64) to
+ *            finally be able to look for collisions and benefit from them. As
+ *            an extra precaution, the current implementation allows to at most
+ *            2^48 calls to the tc_cmac_update function before re-calling
+ *            tc_cmac_setup (allowing a new key to be set), as suggested in
+ *            Appendix B of SP 800-38B.
+ *
+ *  Requires: AES-128
+ *
+ *  Usage:   This implementation provides a "scatter-gather" interface, so that
+ *           the CMAC value can be computed incrementally over a message
+ *           scattered in different segments throughout memory. Experience shows
+ *           this style of interface tends to minimize the burden of programming
+ *           correctly. Like all symmetric key operations, it is session
+ *           oriented.
+ *
+ *           To begin a CMAC session, use tc_cmac_setup to initialize a struct
+ *           tc_cmac_struct with encryption key and buffer. Our implementation
+ *           always assume that the AES key to be the same size as the block
+ *           cipher block size. Once setup, this data structure can be used for
+ *           many CMAC computations.
+ *
+ *           Once the state has been setup with a key, computing the CMAC of
+ *           some data requires three steps:
+ *
+ *           (1) first use tc_cmac_init to initialize a new CMAC computation.
+ *           (2) next mix all of the data into the CMAC computation state using
+ *               tc_cmac_update. If all of the data resides in a single data
+ *               segment then only one tc_cmac_update call is needed; if data
+ *               is scattered throughout memory in n data segments, then n calls
+ *               will be needed. CMAC IS ORDER SENSITIVE, to be able to detect
+ *               attacks that swap bytes, so the order in which data is mixed
+ *               into the state is critical!
+ *           (3) Once all of the data for a message has been mixed, use
+ *               tc_cmac_final to compute the CMAC tag value.
+ *
+ *           Steps (1)-(3) can be repeated as many times as you want to CMAC
+ *           multiple messages. A practical limit is 2^48 1K messages before you
+ *           have to change the key.
+ *
+ *           Once you are done computing CMAC with a key, it is a good idea to
+ *           destroy the state so an attacker cannot recover the key; use
+ *           tc_cmac_erase to accomplish this.
+ */
+
+#ifndef __TC_CMAC_MODE_H__
+#define __TC_CMAC_MODE_H__
+
+#include <tinycrypt/aes.h>
+
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* padding for last message block */
+#define TC_CMAC_PADDING 0x80
+
+/* struct tc_cmac_struct represents the state of a CMAC computation */
+typedef struct tc_cmac_struct {
+/* initialization vector */
+	uint8_t iv[TC_AES_BLOCK_SIZE];
+/* used if message length is a multiple of block_size bytes */
+	uint8_t K1[TC_AES_BLOCK_SIZE];
+/* used if message length isn't a multiple block_size bytes */
+	uint8_t K2[TC_AES_BLOCK_SIZE];
+/* where to put bytes that didn't fill a block */
+	uint8_t leftover[TC_AES_BLOCK_SIZE];
+/* identifies the encryption key */
+	uint32_t keyid;
+/* next available leftover location */
+	uint32_t leftover_offset;
+/* AES key schedule */
+	TCAesKeySched_t sched;
+/* calls to tc_cmac_update left before re-key */
+	uint64_t countdown;
+} *TCCmacState_t;
+
+/**
+ * @brief Configures the CMAC state to use the given AES key
+ * @return returns TC_CRYPTO_SUCCESS (1) after having configured the CMAC state
+ *         returns TC_CRYPTO_FAIL (0) if:
+ *              s == NULL or
+ *              key == NULL
+ *
+ * @param s IN/OUT -- the state to set up
+ * @param key IN -- the key to use
+ * @param sched IN -- AES key schedule
+ */
+int32_t tc_cmac_setup(TCCmacState_t s, const uint8_t *key,
+			   TCAesKeySched_t sched);
+
+/**
+ * @brief Erases the CMAC state
+ * @return returns TC_CRYPTO_SUCCESS (1) after having configured the CMAC state
+ *         returns TC_CRYPTO_FAIL (0) if:
+ *              s == NULL
+ *
+ * @param s IN/OUT -- the state to erase
+ */
+int32_t tc_cmac_erase(TCCmacState_t s);
+
+/**
+ * @brief Initializes a new CMAC computation
+ * @return returns TC_CRYPTO_SUCCESS (1) after having initialized the CMAC state
+ *         returns TC_CRYPTO_FAIL (0) if:
+ *              s == NULL
+ *
+ * @param s IN/OUT -- the state to initialize
+ */
+int32_t tc_cmac_init(TCCmacState_t s);
+
+/**
+ * @brief Incrementally computes CMAC over the next data segment
+ * @return returns TC_CRYPTO_SUCCESS (1) after successfully updating the CMAC state
+ *         returns TC_CRYPTO_FAIL (0) if:
+ *              s == NULL or
+ *              if data == NULL when dlen > 0
+ *
+ * @param s IN/OUT -- the CMAC state
+ * @param data IN -- the next data segment to MAC
+ * @param dlen IN -- the length of data in bytes
+ */
+int32_t tc_cmac_update(TCCmacState_t s, const uint8_t *data, size_t dlen);
+
+/**
+ * @brief Generates the tag from the CMAC state
+ * @return returns TC_CRYPTO_SUCCESS (1) after successfully generating the tag
+ *         returns TC_CRYPTO_FAIL (0) if:
+ *              tag == NULL or
+ *              s == NULL
+ *
+ * @param tag OUT -- the CMAC tag
+ * @param s IN -- CMAC state
+ */
+int32_t tc_cmac_final(uint8_t *tag, TCCmacState_t s);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/drivers/platform/x86/intel_sgx/le/enclave/include/tinycrypt/constants.h b/drivers/platform/x86/intel_sgx/le/enclave/include/tinycrypt/constants.h
new file mode 100644
index 000000000000..1a7c9df3676f
--- /dev/null
+++ b/drivers/platform/x86/intel_sgx/le/enclave/include/tinycrypt/constants.h
@@ -0,0 +1,59 @@
+/* constants.h - TinyCrypt interface to constants */
+
+/*
+ *  Copyright (C) 2015 by Intel Corporation, All Rights Reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are met:
+ *
+ *    - Redistributions of source code must retain the above copyright notice,
+ *     this list of conditions and the following disclaimer.
+ *
+ *    - Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ *    - Neither the name of Intel Corporation nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ *  POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ * @brief -- Interface to constants.
+ *
+ */
+
+#ifndef __TC_CONSTANTS_H__
+#define __TC_CONSTANTS_H__
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef NULL
+#define NULL ((void *)0)
+#endif
+
+#define TC_CRYPTO_SUCCESS 1
+#define TC_CRYPTO_FAIL 0
+
+#define TC_ZERO_BYTE 0x00
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/drivers/platform/x86/intel_sgx/le/enclave/include/tinycrypt/utils.h b/drivers/platform/x86/intel_sgx/le/enclave/include/tinycrypt/utils.h
new file mode 100644
index 000000000000..615e7111a719
--- /dev/null
+++ b/drivers/platform/x86/intel_sgx/le/enclave/include/tinycrypt/utils.h
@@ -0,0 +1,95 @@
+/* utils.h - TinyCrypt interface to platform-dependent run-time operations */
+
+/*
+ *  Copyright (C) 2015 by Intel Corporation, All Rights Reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are met:
+ *
+ *    - Redistributions of source code must retain the above copyright notice,
+ *     this list of conditions and the following disclaimer.
+ *
+ *    - Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ *    - Neither the name of Intel Corporation nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ *  POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/**
+ * @file
+ * @brief Interface to platform-dependent run-time operations.
+ *
+ */
+
+#ifndef __TC_UTILS_H__
+#define __TC_UTILS_H__
+
+#include <linux/types.h>
+#include <stddef.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @brief Copy the the buffer 'from' to the buffer 'to'.
+ * @return returns TC_CRYPTO_SUCCESS (1)
+ *         returns TC_CRYPTO_FAIL (0) if:
+ *                from_len > to_len.
+ *
+ * @param to OUT -- destination buffer
+ * @param to_len IN -- length of destination buffer
+ * @param from IN -- origin buffer
+ * @param from_len IN -- length of origin buffer
+ */
+uint32_t _copy(uint8_t *to, uint32_t to_len,
+	       const uint8_t *from, uint32_t from_len);
+
+/**
+ * @brief Set the value 'val' into the buffer 'to', 'len' times.
+ *
+ * @param to OUT -- destination buffer
+ * @param val IN -- value to be set in 'to'
+ * @param len IN -- number of times the value will be copied
+ */
+void _set(void *to, uint8_t val, uint32_t len);
+
+/*
+ * @brief AES specific doubling function, which utilizes
+ * the finite field used by AES.
+ * @return Returns a^2
+ *
+ * @param a IN/OUT -- value to be doubled
+ */
+uint8_t _double_byte(uint8_t a);
+
+/*
+ * @brief Constant-time algorithm to compare if two sequences of bytes are equal
+ * @return Returns 0 if equal, and non-zero otherwise
+ *
+ * @param a IN -- sequence of bytes a
+ * @param b IN -- sequence of bytes b
+ * @param size IN -- size of sequences a and b
+ */
+int32_t _compare(const uint8_t *a, const uint8_t *b, size_t size);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/drivers/platform/x86/intel_sgx/le/enclave/main.c b/drivers/platform/x86/intel_sgx/le/enclave/main.c
new file mode 100644
index 000000000000..358f0c5684c8
--- /dev/null
+++ b/drivers/platform/x86/intel_sgx/le/enclave/main.c
@@ -0,0 +1,203 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2016, 2017 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License 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.
+ *
+ * Contact Information:
+ * Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
+ * Intel Finland Oy - BIC 0357606-4 - Westendinkatu 7, 02160 Espoo
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2016, 2017 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in
+ *     the documentation and/or other materials provided with the
+ *     distribution.
+ *   * Neither the name of Intel Corporation nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors:
+ *
+ * Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
+ */
+
+#include <tinycrypt/cmac_mode.h>
+#include <stdbool.h>
+#include <linux/types.h>
+#include <asm/sgx_arch.h>
+#include <uapi/asm/sgx.h>
+#include <sgx_encl.h>
+
+static bool get_rand_uint32(uint32_t *value)
+{
+	int i;
+
+	for (i = 0; i < 10; i++) {
+		if (__builtin_ia32_rdrand32_step((unsigned int *)value))
+			return true;
+	}
+
+	return false;
+}
+
+static bool read_rand(uint8_t *data, unsigned long size)
+{
+	uint32_t value;
+	uint8_t* bytes = (uint8_t *)&value;
+	unsigned long i;
+
+	for (i = 0; i < size; i++) {
+		if (!(i & 3)) {
+			if (!get_rand_uint32(&value))
+				return false;
+		}
+
+		data[i] = bytes[i & 3];
+	}
+
+	return true;
+}
+
+static bool sign_einittoken(struct sgx_einittoken *einittoken)
+{
+	struct sgx_keyrequest keyrequest __attribute__((aligned (512)));
+	uint8_t launch_key[16] __attribute__((aligned (16)));
+	struct tc_cmac_struct cmac_state;
+	struct tc_aes_key_sched_struct cmac_sched;
+
+	/* a random unique key id */
+	if (!read_rand(einittoken->keyid, sizeof(einittoken->keyid)))
+		return false;
+
+	sgx_memset(&keyrequest, 0, sizeof(keyrequest));
+	keyrequest.keyname = 0; /* LICENSE_KEY */
+	sgx_memcpy(&keyrequest.keyid, &einittoken->keyid,
+		   sizeof(keyrequest.keyid));
+	sgx_memcpy(&keyrequest.cpusvn, &(einittoken->cpusvnle),
+		   sizeof(keyrequest.cpusvn));
+	sgx_memcpy(&keyrequest.isvsvn, &(einittoken->isvsvnle),
+		   sizeof(keyrequest.isvsvn));
+
+	keyrequest.attributemask = ~SGX_ATTR_MODE64BIT;
+	keyrequest.xfrmmask = 0;
+	keyrequest.miscmask = 0xFFFFFFFF;
+
+	einittoken->maskedmiscselectle &= keyrequest.miscmask;
+	einittoken->maskedattributesle &= keyrequest.attributemask;
+	einittoken->maskedxfrmle &= keyrequest.xfrmmask;
+
+	if (sgx_egetkey(&keyrequest, launch_key))
+		return false;
+
+	tc_cmac_setup(&cmac_state, launch_key, &cmac_sched);
+	tc_cmac_init(&cmac_state);
+	tc_cmac_update(&cmac_state, (const uint8_t *)&einittoken->payload,
+		       sizeof(einittoken->payload));
+	tc_cmac_final(einittoken->mac, &cmac_state);
+
+	sgx_memset(launch_key, 0, sizeof(launch_key));
+
+	return true;
+}
+
+static bool create_einittoken(uint8_t *mrenclave,
+			      uint8_t *mrsigner,
+			      uint64_t attributes,
+			      uint64_t xfrm,
+			      struct sgx_einittoken *einittoken)
+{
+
+	struct sgx_targetinfo tginfo __attribute__((aligned (512)));
+	struct sgx_report report __attribute__((aligned (512)));
+	uint8_t reportdata[64] __attribute__((aligned (128)));
+
+	if (attributes & 8 /* RESERVED */)
+		return false;
+
+	sgx_memset(&tginfo, 0, sizeof(tginfo));
+	sgx_memset(reportdata, 0, sizeof(reportdata));
+	sgx_memset(&report, 0, sizeof(report));
+
+	if (sgx_ereport(&tginfo, reportdata, &report))
+		return false;
+
+	sgx_memset(einittoken, 0, sizeof(*einittoken));
+
+	einittoken->payload.valid = 1;
+
+	sgx_memcpy(einittoken->payload.mrenclave, mrenclave, 32);
+	sgx_memcpy(einittoken->payload.mrsigner, mrsigner, 32);
+	einittoken->payload.attributes = attributes;
+	einittoken->payload.xfrm = xfrm;
+
+	sgx_memcpy(&einittoken->cpusvnle, &report.cpusvn,
+		   sizeof(report.cpusvn));
+	einittoken->isvsvnle = report.isvsvn;
+	einittoken->isvprodidle = report.isvprodid;
+
+	einittoken->maskedattributesle = report.attributes;
+	einittoken->maskedxfrmle = report.xfrm;
+	einittoken->maskedmiscselectle = report.miscselect;
+
+	if (!sign_einittoken(einittoken))
+		return false;
+
+	return true;
+}
+
+void encl_body(void *req_ptr)
+{
+	struct sgx_le_request *req = (struct sgx_le_request *)req_ptr;
+	struct sgx_einittoken token;
+	uint8_t mrenclave[32];
+	uint8_t mrsigner[32];
+	uint64_t attributes;
+	uint64_t xfrm;
+
+	if (!req || !req->mrenclave || !req->mrsigner || !req->einittoken)
+		return;
+
+	sgx_memcpy(mrenclave, req->mrenclave, sizeof(mrenclave));
+	sgx_memcpy(mrsigner, req->mrsigner, sizeof(mrsigner));
+	sgx_memcpy(&attributes, &req->attributes, sizeof(uint64_t));
+	sgx_memcpy(&xfrm, &req->xfrm, sizeof(uint64_t));
+	sgx_memset(&token, 0, sizeof(token));
+
+	if (!create_einittoken(mrenclave, mrsigner, attributes, xfrm, &token))
+		return;
+
+	sgx_memcpy(req->einittoken, &token, sizeof(token));
+}
diff --git a/drivers/platform/x86/intel_sgx/le/enclave/sgx_le.lds b/drivers/platform/x86/intel_sgx/le/enclave/sgx_le.lds
new file mode 100644
index 000000000000..56b694c15ebe
--- /dev/null
+++ b/drivers/platform/x86/intel_sgx/le/enclave/sgx_le.lds
@@ -0,0 +1,28 @@
+OUTPUT_FORMAT(elf64-x86-64)
+
+SECTIONS
+{
+	. = 0;
+	.tcs : {
+		*(.tcs*)
+	}
+
+	. = ALIGN(4096);
+	.text : {
+		*(.text*)
+		*(.rodata*)
+	}
+
+	. = ALIGN(4096);
+	.data : {
+		*(.data*)
+	}
+
+	/DISCARD/ : {
+		*(.data*)
+		*(.comment*)
+		*(.note*)
+		*(.debug*)
+		*(.eh_frame*)
+	}
+}
diff --git a/drivers/platform/x86/intel_sgx/le/enclave/sgxsign.c b/drivers/platform/x86/intel_sgx/le/enclave/sgxsign.c
new file mode 100644
index 000000000000..27e8c61d033c
--- /dev/null
+++ b/drivers/platform/x86/intel_sgx/le/enclave/sgxsign.c
@@ -0,0 +1,537 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2017 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License 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.
+ *
+ * Contact Information:
+ * Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
+ * Intel Finland Oy - BIC 0357606-4 - Westendinkatu 7, 02160 Espoo
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2017 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in
+ *     the documentation and/or other materials provided with the
+ *     distribution.
+ *   * Neither the name of Intel Corporation nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors:
+ *
+ * Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
+ */
+
+#define _GNU_SOURCE
+#include <getopt.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <asm/sgx_arch.h>
+#include <openssl/err.h>
+#include <openssl/pem.h>
+
+static const char *sign_key_pass;
+
+static bool check_crypto_errors(void)
+{
+	int err;
+	bool had_errors = false;
+	const char *filename;
+	int line;
+	char str[256];
+
+	for ( ; ; ) {
+		if (ERR_peek_error() == 0)
+			break;
+
+		had_errors = true;
+		err = ERR_get_error_line(&filename, &line);
+		ERR_error_string_n(err, str, sizeof(str));
+		fprintf(stderr, "crypto: %s: %s:%d\n", str, filename, line);
+	}
+
+	return had_errors;
+}
+
+static void exit_usage(const char *program)
+{
+	fprintf(stderr,
+		"Usage: %s/sign-le <key> <enclave> <sigstruct>\n", program);
+	exit(1);
+}
+
+static int pem_passwd_cb(char *buf, int size, int rwflag, void *u)
+{
+	if (!sign_key_pass)
+		return -1;
+
+	strncpy(buf, sign_key_pass, size);
+	/* no retry */
+	sign_key_pass = NULL;
+
+	return strlen(buf) >= size ? size - 1 : strlen(buf);
+}
+
+static RSA *load_sign_key(const char *path)
+{
+	FILE *f;
+	RSA *key;
+
+	f = fopen(path, "rb");
+	if (!f) {
+		fprintf(stderr, "Unable to open %s\n", path);
+		return NULL;
+	}
+	key = RSA_new();
+	if (!PEM_read_RSAPrivateKey(f, &key, pem_passwd_cb, NULL))
+		return NULL;
+	fclose(f);
+
+	if (BN_num_bytes(key->n) != SGX_MODULUS_SIZE) {
+		fprintf(stderr, "Invalid key size %d\n", BN_num_bytes(key->n));
+		RSA_free(key);
+		return NULL;
+	}
+
+	return key;
+}
+
+static void reverse_bytes(void *data, int length)
+{
+	int i = 0;
+	int j = length - 1;
+	uint8_t temp;
+	uint8_t *ptr = data;
+
+	while (i < j) {
+		temp = ptr[i];
+		ptr[i] = ptr[j];
+		ptr[j] = temp;
+		i++;
+		j--;
+	}
+}
+
+enum mrtags {
+	MRECREATE = 0x0045544145524345,
+	MREADD = 0x0000000044444145,
+	MREEXTEND = 0x00444E4554584545,
+};
+
+static bool mrenclave_update(EVP_MD_CTX *ctx, const void *data)
+{
+	if (!EVP_DigestUpdate(ctx, data, 64)) {
+		fprintf(stderr, "digest update failed\n");
+		return false;
+	}
+
+	return true;
+}
+
+static bool mrenclave_commit(EVP_MD_CTX *ctx, uint8_t *mrenclave)
+{
+	unsigned int size;
+
+	if (!EVP_DigestFinal_ex(ctx, (unsigned char *)mrenclave, &size)) {
+		fprintf(stderr, "digest commit failed\n");
+		return false;
+	}
+
+	if (size != 32) {
+		fprintf(stderr, "invalid digest size = %u\n", size);
+		return false;
+	}
+
+	return true;
+}
+
+struct mrecreate {
+	uint64_t tag;
+	uint32_t ssaframesize;
+	uint64_t size;
+	uint8_t reserved[44];
+} __attribute__((__packed__));
+
+
+static bool mrenclave_ecreate(EVP_MD_CTX *ctx, uint64_t blob_size)
+{
+	struct mrecreate mrecreate;
+	uint64_t encl_size;
+
+	for (encl_size = 0x1000; encl_size < blob_size; encl_size <<= 1);
+
+	memset(&mrecreate, 0, sizeof(mrecreate));
+	mrecreate.tag = MRECREATE;
+	mrecreate.ssaframesize = 1;
+	mrecreate.size = encl_size;
+
+	if (!EVP_DigestInit_ex(ctx, EVP_sha256(), NULL))
+		return false;
+
+	return mrenclave_update(ctx, &mrecreate);
+}
+
+struct mreadd {
+	uint64_t tag;
+	uint64_t offset;
+	uint64_t flags; /* SECINFO flags */
+	uint8_t reserved[40];
+} __attribute__((__packed__));
+
+static bool mrenclave_eadd(EVP_MD_CTX *ctx, uint64_t offset, uint64_t flags)
+{
+	struct mreadd mreadd;
+
+	memset(&mreadd, 0, sizeof(mreadd));
+	mreadd.tag = MREADD;
+	mreadd.offset = offset;
+	mreadd.flags = flags;
+
+	return mrenclave_update(ctx, &mreadd);
+}
+
+struct mreextend {
+	uint64_t tag;
+	uint64_t offset;
+	uint8_t reserved[48];
+} __attribute__((__packed__));
+
+static bool mrenclave_eextend(EVP_MD_CTX *ctx, uint64_t offset, uint8_t *data)
+{
+	struct mreextend mreextend;
+	int i;
+
+	for (i = 0; i < 0x1000; i += 0x100) {
+		memset(&mreextend, 0, sizeof(mreextend));
+		mreextend.tag = MREEXTEND;
+		mreextend.offset = offset + i;
+
+		if (!mrenclave_update(ctx, &mreextend))
+			return false;
+
+		if (!mrenclave_update(ctx, &data[i + 0x00]))
+			return false;
+
+		if (!mrenclave_update(ctx, &data[i + 0x40]))
+			return false;
+
+		if (!mrenclave_update(ctx, &data[i + 0x80]))
+			return false;
+
+		if (!mrenclave_update(ctx, &data[i + 0xC0]))
+			return false;
+	}
+
+	return true;
+}
+
+/**
+ * measure_encl - measure enclave
+ * @path: path to the enclave
+ * @mrenclave: measurement
+ *
+ * Calculates MRENCLAVE. Assumes that the very first page is a TCS page and
+ * following pages are regular pages. Does not measure the contents of the
+ * enclave as the signing tool is used at the moment only for the launch
+ * enclave, which is pass-through (everything gets a token).
+ */
+static bool measure_encl(const char *path, uint8_t *mrenclave)
+{
+	FILE *file;
+	struct stat sb;
+	EVP_MD_CTX *ctx;
+	uint64_t flags;
+	uint64_t offset;
+	uint8_t data[0x1000];
+	int rc;
+
+	ctx = EVP_MD_CTX_create();
+	if (!ctx)
+		return false;
+
+	file = fopen(path, "rb");
+	if (!file) {
+		perror("fopen");
+		EVP_MD_CTX_destroy(ctx);
+		return false;
+	}
+
+	rc = stat(path, &sb);
+	if (rc) {
+		perror("stat");
+		goto out;
+	}
+
+	if (!sb.st_size || sb.st_size & 0xfff) {
+		fprintf(stderr, "Invalid blob size %lu\n", sb.st_size);
+		goto out;
+	}
+
+	if (!mrenclave_ecreate(ctx, sb.st_size))
+		goto out;
+
+	for (offset = 0; offset < sb.st_size; offset += 0x1000) {
+		if (!offset)
+			flags = SGX_SECINFO_TCS;
+		else
+			flags = SGX_SECINFO_REG | SGX_SECINFO_R |
+				SGX_SECINFO_W | SGX_SECINFO_X;
+
+		if (!mrenclave_eadd(ctx, offset, flags))
+			goto out;
+
+		rc = fread(data, 1, 0x1000, file);
+		if (!rc)
+			break;
+		if (rc < 0x1000)
+			goto out;
+
+		if (!mrenclave_eextend(ctx, offset, data))
+			goto out;
+	}
+
+	if (!mrenclave_commit(ctx, mrenclave))
+		goto out;
+
+	fclose(file);
+	EVP_MD_CTX_destroy(ctx);
+	return true;
+out:
+	fclose(file);
+	EVP_MD_CTX_destroy(ctx);
+	return false;
+}
+
+/**
+ * sign_encl - sign enclave
+ * @sigstruct: pointer to SIGSTRUCT
+ * @key: 3072-bit RSA key
+ * @signature: byte array for the signature
+ *
+ * Calculates EMSA-PKCSv1.5 signature for the given SIGSTRUCT. The result is
+ * stored in big-endian format so that it can be further passed to OpenSSL
+ * libcrypto functions.
+ */
+static bool sign_encl(const struct sgx_sigstruct *sigstruct, RSA *key,
+		      uint8_t *signature)
+{
+	struct sgx_sigstruct_payload payload;
+	unsigned int siglen;
+	uint8_t digest[SHA256_DIGEST_LENGTH];
+	bool ret;
+
+	memcpy(&payload.header, &sigstruct->header, sizeof(sigstruct->header));
+	memcpy(&payload.body, &sigstruct->body, sizeof(sigstruct->body));
+
+	SHA256((unsigned char *)&payload, sizeof(payload), digest);
+
+	ret = RSA_sign(NID_sha256, digest, SHA256_DIGEST_LENGTH, signature,
+		       &siglen, key);
+
+	return ret;
+}
+
+struct q1q2_ctx {
+	BN_CTX *bn_ctx;
+	BIGNUM *m;
+	BIGNUM *s;
+	BIGNUM *q1;
+	BIGNUM *qr;
+	BIGNUM *q2;
+};
+
+static void free_q1q2_ctx(struct q1q2_ctx *ctx)
+{
+	BN_CTX_free(ctx->bn_ctx);
+	BN_free(ctx->m);
+	BN_free(ctx->s);
+	BN_free(ctx->q1);
+	BN_free(ctx->qr);
+	BN_free(ctx->q2);
+}
+
+static bool alloc_q1q2_ctx(const uint8_t *s, const uint8_t *m,
+			   struct q1q2_ctx *ctx)
+{
+	ctx->bn_ctx = BN_CTX_new();
+	ctx->s = BN_bin2bn(s, SGX_MODULUS_SIZE, NULL);
+	ctx->m = BN_bin2bn(m, SGX_MODULUS_SIZE, NULL);
+	ctx->q1 = BN_new();
+	ctx->qr = BN_new();
+	ctx->q2 = BN_new();
+
+	if (!ctx->bn_ctx || !ctx->s || !ctx->m || !ctx->q1 || !ctx->qr ||
+	    !ctx->q2) {
+		free_q1q2_ctx(ctx);
+		return false;
+	}
+
+	return true;
+}
+
+static bool calc_q1q2(const uint8_t *s, const uint8_t *m, uint8_t *q1,
+		      uint8_t *q2)
+{
+	struct q1q2_ctx ctx;
+
+	if (!alloc_q1q2_ctx(s, m, &ctx)) {
+		fprintf(stderr, "Not enough memory for Q1Q2 calculation\n");
+		return false;
+	}
+
+	if (!BN_mul(ctx.q1, ctx.s, ctx.s, ctx.bn_ctx))
+		goto out;
+
+	if (!BN_div(ctx.q1, ctx.qr, ctx.q1, ctx.m, ctx.bn_ctx))
+		goto out;
+
+	if (BN_num_bytes(ctx.q1) > SGX_MODULUS_SIZE) {
+		fprintf(stderr, "Too large Q1 %d bytes\n",
+			BN_num_bytes(ctx.q1));
+		goto out;
+	}
+
+	if (!BN_mul(ctx.q2, ctx.s, ctx.qr, ctx.bn_ctx))
+		goto out;
+
+	if (!BN_div(ctx.q2, NULL, ctx.q2, ctx.m, ctx.bn_ctx))
+		goto out;
+
+	if (BN_num_bytes(ctx.q2) > SGX_MODULUS_SIZE) {
+		fprintf(stderr, "Too large Q2 %d bytes\n",
+			BN_num_bytes(ctx.q2));
+		goto out;
+	}
+
+	BN_bn2bin(ctx.q1, q1);
+	BN_bn2bin(ctx.q2, q2);
+
+	free_q1q2_ctx(&ctx);
+	return true;
+out:
+	free_q1q2_ctx(&ctx);
+	return false;
+}
+
+static bool save_sigstruct(const struct sgx_sigstruct *sigstruct,
+			   const char *path)
+{
+	FILE *f = fopen(path, "wb");
+
+	if (!f) {
+		fprintf(stderr, "Unable to open %s\n", path);
+		return false;
+	}
+
+	fwrite(sigstruct, sizeof(*sigstruct), 1, f);
+	fclose(f);
+	return true;
+}
+
+int main(int argc, char **argv)
+{
+	uint64_t header1[2] = {0x000000E100000006, 0x0000000000010000};
+	uint64_t header2[2] = {0x0000006000000101, 0x0000000100000060};
+	struct sgx_sigstruct ss;
+	const char *program;
+	int opt;
+	RSA *sign_key;
+
+	memset(&ss, 0, sizeof(ss));
+	ss.header.header1[0] = header1[0];
+	ss.header.header1[1] = header1[1];
+	ss.header.header2[0] = header2[0];
+	ss.header.header2[1] = header2[1];
+	ss.exponent = 3;
+	ss.body.attributes = SGX_ATTR_MODE64BIT | SGX_ATTR_EINITTOKENKEY;
+	ss.body.xfrm = 3,
+
+	sign_key_pass = getenv("KBUILD_SGX_SIGN_PIN");
+	program = argv[0];
+
+	do {
+		opt = getopt(argc, argv, "");
+		switch (opt) {
+		case -1:
+			break;
+		default:
+			exit_usage(program);
+		}
+	} while (opt != -1);
+
+	argc -= optind;
+	argv += optind;
+
+	if (argc < 3)
+		exit_usage(program);
+
+	/* sanity check only */
+	if (check_crypto_errors())
+		exit(1);
+
+	sign_key = load_sign_key(argv[0]);
+	if (!sign_key)
+		goto out;
+
+	BN_bn2bin(sign_key->n, ss.modulus);
+
+	if (!measure_encl(argv[1], ss.body.mrenclave))
+		goto out;
+
+	if (!sign_encl(&ss, sign_key, ss.signature))
+		goto out;
+
+	if (!calc_q1q2(ss.signature, ss.modulus, ss.q1, ss.q2))
+		goto out;
+
+	/* convert to little endian */
+	reverse_bytes(ss.signature, SGX_MODULUS_SIZE);
+	reverse_bytes(ss.modulus, SGX_MODULUS_SIZE);
+	reverse_bytes(ss.q1, SGX_MODULUS_SIZE);
+	reverse_bytes(ss.q2, SGX_MODULUS_SIZE);
+
+	if (!save_sigstruct(&ss, argv[2]))
+		goto out;
+	exit(0);
+out:
+	check_crypto_errors();
+	exit(1);
+}
diff --git a/drivers/platform/x86/intel_sgx/le/enclave/utils.c b/drivers/platform/x86/intel_sgx/le/enclave/utils.c
new file mode 100644
index 000000000000..f95b67762416
--- /dev/null
+++ b/drivers/platform/x86/intel_sgx/le/enclave/utils.c
@@ -0,0 +1,78 @@
+/* utils.c - TinyCrypt platform-dependent run-time operations */
+
+/*
+ *  Copyright (C) 2015 by Intel Corporation, All Rights Reserved.
+ *
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are met:
+ *
+ *    - Redistributions of source code must retain the above copyright notice,
+ *     this list of conditions and the following disclaimer.
+ *
+ *    - Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ *    - Neither the name of Intel Corporation nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ *  AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ *  IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ *  ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ *  LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ *  CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ *  SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ *  INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ *  CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ *  ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ *  POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <tinycrypt/utils.h>
+#include <tinycrypt/constants.h>
+
+#include <sgx_encl.h>
+
+#define MASK_MOST_SIG_BIT 0x80
+#define MASK_TWENTY_SEVEN 0x1b
+
+uint32_t _copy(uint8_t *to, uint32_t to_len,
+	       const uint8_t *from, uint32_t from_len)
+{
+	if (from_len <= to_len) {
+		(void)sgx_memcpy(to, from, from_len);
+		return from_len;
+	} else {
+		return TC_CRYPTO_FAIL;
+	}
+}
+
+void _set(void *to, uint8_t val, uint32_t len)
+{
+	(void)sgx_memset(to, val, len);
+}
+
+/*
+ * Doubles the value of a byte for values up to 127. Original 'return
+ * ((a<<1) ^ ((a>>7) * 0x1b))' re-written to avoid extra multiplication which
+ * the compiler won't be able to optimize
+ */
+uint8_t _double_byte(uint8_t a)
+{
+	return (a & MASK_MOST_SIG_BIT) ?
+		((a << 1) ^ MASK_TWENTY_SEVEN) : (a << 1);
+}
+
+int32_t _compare(const uint8_t *a, const uint8_t *b, size_t size)
+{
+	const uint8_t *tempa = a;
+	const uint8_t *tempb = b;
+	uint8_t result = 0;
+
+	for (uint32_t i = 0; i < size; i++) {
+		result |= tempa[i] ^ tempb[i];
+	}
+	return result;
+}
diff --git a/drivers/platform/x86/intel_sgx/le/entry.S b/drivers/platform/x86/intel_sgx/le/entry.S
new file mode 100644
index 000000000000..97554b93107d
--- /dev/null
+++ b/drivers/platform/x86/intel_sgx/le/entry.S
@@ -0,0 +1,117 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2017 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License 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.
+ *
+ * Contact Information:
+ * Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
+ * Intel Finland Oy - BIC 0357606-4 - Westendinkatu 7, 02160 Espoo
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2016, 2017 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in
+ *     the documentation and/or other materials provided with the
+ *     distribution.
+ *   * Neither the name of Intel Corporation nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors:
+ *
+ * Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
+ */
+
+#include <sgx_asm.h>
+
+	.text
+
+	.global sgx_le_request_token
+sgx_le_request_token:
+	push	%rbx
+	mov	$0x02, %rax
+	mov	%rsi, %rbx
+	mov	$sgx_async_exit, %rcx
+sgx_async_exit:
+	ENCLU
+	pop	%rbx
+	ret
+
+	.global sgx_sys_read
+sgx_sys_read:
+	mov	$0, %rax
+	mov	%rsi, %rdx /* buf */
+	mov	%rdi, %rsi /* count */
+	xor	%rdi, %rdi /* stdin */
+	syscall
+	ret
+
+	.global sgx_sys_write
+sgx_sys_write:
+	mov	$1, %rax
+	mov	%rsi, %rdx /* buf */
+	mov	%rdi, %rsi /* count */
+	mov	$1, %rdi /* stout */
+	syscall
+	ret
+
+	.global sgx_sys_close
+sgx_sys_close:
+	mov	$3, %rax
+	syscall
+	ret
+
+	.global sgx_sys_mmap
+sgx_sys_mmap:
+	mov	$9, %rax
+	mov	%rdi, %r8 /* fd */
+	xor	%rdi, %rdi /* any address */
+
+	mov	$0x07, %rdx /* rwx */
+	mov	$0x01, %r10 /* shared */
+	mov	$0x00, %r9 /* offset */
+	syscall
+	ret
+
+	.global sgx_sys_ioctl
+sgx_sys_ioctl:
+	mov	$16, %rax
+	syscall
+	ret
+
+	.global sgx_sys_exit
+sgx_sys_exit:
+	mov	$60, %rax
+	syscall
diff --git a/drivers/platform/x86/intel_sgx/le/include/sgx_asm.h b/drivers/platform/x86/intel_sgx/le/include/sgx_asm.h
new file mode 100644
index 000000000000..d1d5fbd70137
--- /dev/null
+++ b/drivers/platform/x86/intel_sgx/le/include/sgx_asm.h
@@ -0,0 +1,64 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2016, 2017 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License 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.
+ *
+ * Contact Information:
+ * Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
+ * Intel Finland Oy - BIC 0357606-4 - Westendinkatu 7, 02160 Espoo
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2016, 2017 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in
+ *     the documentation and/or other materials provided with the
+ *     distribution.
+ *   * Neither the name of Intel Corporation nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors:
+ *
+ * Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
+ */
+
+#ifndef SGX_ASM_H
+#define SGX_ASM_H
+
+.macro ENCLU
+.byte 0x0f, 0x01, 0xd7
+.endm
+
+#endif /* SGX_ASM_H */
diff --git a/drivers/platform/x86/intel_sgx/le/include/sgx_encl.h b/drivers/platform/x86/intel_sgx/le/include/sgx_encl.h
new file mode 100644
index 000000000000..c0be08c78bdb
--- /dev/null
+++ b/drivers/platform/x86/intel_sgx/le/include/sgx_encl.h
@@ -0,0 +1,105 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2016, 2017 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License 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.
+ *
+ * Contact Information:
+ * Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
+ * Intel Finland Oy - BIC 0357606-4 - Westendinkatu 7, 02160 Espoo
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2016, 2017 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in
+ *     the documentation and/or other materials provided with the
+ *     distribution.
+ *   * Neither the name of Intel Corporation nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors:
+ *
+ * Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
+ */
+
+#ifndef SGX_ENCL_H
+#define SGX_ENCL_H
+
+struct sgx_le_request {
+	void *mrenclave; /* input */
+	void *mrsigner; /* input */
+	uint64_t attributes; /* input */
+	uint64_t xfrm; /* input */
+	void *einittoken; /* output */
+};
+
+/* Outside enclave */
+
+void sgx_le_request_token(struct sgx_le_request *req, void *entry);
+long sgx_sys_read(void *buf, unsigned long count);
+long sgx_sys_write(const void *buf, unsigned long count);
+long sgx_sys_close(long fd);
+long sgx_sys_mmap(long fd, unsigned long size);
+long sgx_sys_ioctl(long fd, unsigned long cmd, void *arg);
+long sgx_sys_exit(long status);
+
+/* Inside enclave */
+
+int sgx_ereport(const void *target_info, const void *report_data,
+		void *report);
+int sgx_egetkey(void *key_request, void *key);
+
+/* Common */
+
+static inline void sgx_memset(void *dst, unsigned char value,
+			      unsigned long size)
+{
+	unsigned long i;
+
+	for (i = 0; i < size; i++)
+		((unsigned char *)dst)[i] = value;
+}
+
+static inline void sgx_memcpy(void *dst, const void *src,
+			      unsigned long size)
+{
+	unsigned long i;
+
+	for (i = 0; i < size; i++)
+		((unsigned char *)dst)[i] =
+			((unsigned char *)src)[i];
+}
+
+#endif /* SGX_ENCL_H */
diff --git a/drivers/platform/x86/intel_sgx/le/main.c b/drivers/platform/x86/intel_sgx/le/main.c
new file mode 100644
index 000000000000..2da7a8444837
--- /dev/null
+++ b/drivers/platform/x86/intel_sgx/le/main.c
@@ -0,0 +1,219 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2016, 2017 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License 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.
+ *
+ * Contact Information:
+ * Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
+ * Intel Finland Oy - BIC 0357606-4 - Westendinkatu 7, 02160 Espoo
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2016, 2017 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in
+ *     the documentation and/or other materials provided with the
+ *     distribution.
+ *   * Neither the name of Intel Corporation nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors:
+ *
+ * Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
+ */
+
+#include <linux/types.h>
+#include <asm/sgx_arch.h>
+#include <sgx_encl.h>
+#include <uapi/asm/sgx.h>
+
+#define SGX_LE_PROXY_FD 3
+#define SGX_LE_DEV_FD 4
+
+#ifndef NULL
+#define NULL ((void *)0)
+#endif
+
+#ifndef MAP_FAILED
+#define MAP_FAILED ((void *)-1)
+#endif
+
+extern unsigned char sgx_aex[];
+extern unsigned char sgx_le_blob[];
+extern unsigned char sgx_le_blob_end[];
+extern unsigned char sgx_le_ss[];
+
+static void *start_launch_enclave(void)
+{
+	struct sgx_enclave_create create_ioc;
+	struct sgx_enclave_add_page add_ioc;
+	struct sgx_enclave_init init_ioc;
+	struct sgx_secs secs;
+	struct sgx_secinfo secinfo;
+	unsigned long blob_base;
+	unsigned long blob_size;
+	unsigned long offset;
+	int rc;
+
+	sgx_memset(&secs, 0, sizeof(secs));
+	sgx_memset(&secinfo, 0, sizeof(secinfo));
+
+	secs.ssaframesize = 1;
+	secs.attributes = SGX_ATTR_MODE64BIT | SGX_ATTR_EINITTOKENKEY;
+	secs.xfrm = 3;
+
+	blob_base = (unsigned long)&sgx_le_blob;
+	blob_size = (unsigned long)&sgx_le_blob_end - blob_base;
+
+	for (secs.size = 4096; secs.size < blob_size; secs.size <<= 1);
+
+	secs.base = (unsigned long)sgx_sys_mmap(SGX_LE_DEV_FD, secs.size);
+	if (secs.base == (unsigned long)MAP_FAILED)
+		goto out;
+
+	create_ioc.src = (unsigned long)&secs;
+	rc = sgx_sys_ioctl(SGX_LE_DEV_FD, SGX_IOC_ENCLAVE_CREATE, &create_ioc);
+	if (rc)
+		goto out;
+
+	add_ioc.secinfo = (unsigned long)&secinfo;
+	add_ioc.mrmask = 0xFFFF;
+
+	for (offset = 0; offset < blob_size; offset += 0x1000) {
+		if (!offset)
+			secinfo.flags = SGX_SECINFO_TCS;
+		else
+			secinfo.flags = SGX_SECINFO_REG | SGX_SECINFO_R |
+					SGX_SECINFO_W | SGX_SECINFO_X;
+
+		add_ioc.addr = secs.base + offset;
+		add_ioc.src = blob_base + offset;
+
+		rc = sgx_sys_ioctl(SGX_LE_DEV_FD, SGX_IOC_ENCLAVE_ADD_PAGE,
+				   &add_ioc);
+		if (rc)
+			goto out;
+	}
+
+	init_ioc.addr = secs.base;
+	init_ioc.sigstruct = (uint64_t)&sgx_le_ss;
+	init_ioc.flags = SGX_ENCLAVE_INIT_ARCH;
+	rc = sgx_sys_ioctl(SGX_LE_DEV_FD, SGX_IOC_ENCLAVE_INIT, &init_ioc);
+	if (rc)
+		goto out;
+
+	return (void *)secs.base;
+out:
+	return NULL;
+}
+
+static int read_input(void *data, unsigned int len)
+{
+	uint8_t *ptr = (uint8_t *)data;
+	long i;
+	long ret;
+
+	for (i = 0; i < len; ) {
+		ret = sgx_sys_read(&ptr[i], len - i);
+		if (ret < 0)
+			return ret;
+
+		i += ret;
+	}
+
+	return 0;
+}
+
+static int write_token(const struct sgx_einittoken *token)
+{
+	const uint8_t *ptr = (const uint8_t *)token;
+	long i;
+	long ret;
+
+	for (i = 0; i < sizeof(*token); ) {
+		ret = sgx_sys_write(&ptr[i], sizeof(*token) - i);
+		if (ret < 0)
+			return ret;
+
+		i += ret;
+	}
+
+	return 0;
+}
+
+void _start(void)
+{
+	struct sgx_einittoken token;
+	struct sgx_le_request req;
+	uint8_t mrenclave[32];
+	uint8_t mrsigner[32];
+	uint64_t attributes;
+	uint64_t xfrm;
+	void *entry;
+
+	sgx_sys_close(SGX_LE_PROXY_FD);
+	entry = start_launch_enclave();
+	sgx_sys_close(SGX_LE_DEV_FD);
+	if (!entry)
+		sgx_sys_exit(1);
+
+	for ( ; ; ) {
+		if (read_input(mrenclave, sizeof(mrenclave)))
+			sgx_sys_exit(1);
+
+		if (read_input(mrsigner, sizeof(mrsigner)))
+			sgx_sys_exit(1);
+
+		if (read_input(&attributes, sizeof(uint64_t)))
+			sgx_sys_exit(1);
+
+		if (read_input(&xfrm, sizeof(uint64_t)))
+			sgx_sys_exit(1);
+
+		req.mrenclave = mrenclave;
+		req.mrsigner = mrsigner;
+		req.attributes = attributes;
+		req.xfrm = xfrm;
+
+		sgx_memset(&token, 0, sizeof(token));
+		req.einittoken = &token;
+		sgx_le_request_token(&req, entry);
+
+		if (write_token(&token))
+			sgx_sys_exit(1);
+	}
+
+	__builtin_unreachable();
+}
diff --git a/drivers/platform/x86/intel_sgx/le/sgx_le_piggy.S b/drivers/platform/x86/intel_sgx/le/sgx_le_piggy.S
new file mode 100644
index 000000000000..e5631e8a755d
--- /dev/null
+++ b/drivers/platform/x86/intel_sgx/le/sgx_le_piggy.S
@@ -0,0 +1,15 @@
+#include <linux/linkage.h>
+#include <asm/page_types.h>
+
+	.section ".rodata","a"
+	.balign PAGE_SIZE
+
+GLOBAL(sgx_le_blob)
+	.incbin	"drivers/platform/x86/intel_sgx/le/enclave/sgx_le.bin"
+END(sgx_le_blob)
+
+GLOBAL(sgx_le_blob_end);
+
+GLOBAL(sgx_le_ss)
+	.incbin	"drivers/platform/x86/intel_sgx/le/enclave/sgx_le.ss"
+END(sgx_le_ss)
diff --git a/drivers/platform/x86/intel_sgx/sgx_le_proxy_piggy.S b/drivers/platform/x86/intel_sgx/sgx_le_proxy_piggy.S
new file mode 100644
index 000000000000..faced8a9a75a
--- /dev/null
+++ b/drivers/platform/x86/intel_sgx/sgx_le_proxy_piggy.S
@@ -0,0 +1,11 @@
+#include <linux/linkage.h>
+#include <asm/export.h>
+#include <asm/page_types.h>
+
+	.section ".rodata","a"
+
+GLOBAL(sgx_le_proxy)
+	.incbin	"drivers/platform/x86/intel_sgx/le/sgx_le_proxy"
+END(sgx_le_proxy)
+
+GLOBAL(sgx_le_proxy_end)
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH RFC v3 11/12] intel_sgx: glue code for in-kernel LE
  2017-10-10 14:32 [PATCH RFC v3 00/12] Intel(R) SGX Driver Jarkko Sakkinen
                   ` (8 preceding siblings ...)
  2017-10-10 14:32 ` [PATCH RFC v3 10/12] intel_sgx: in-kernel launch enclave Jarkko Sakkinen
@ 2017-10-10 14:32 ` Jarkko Sakkinen
  2017-10-10 14:32 ` [PATCH RFC v3 12/12] intel_sgx: update IA32_SGXLEPUBKEYHASH* MSRs Jarkko Sakkinen
       [not found] ` <20171010143258.21623-8-jarkko.sakkinen@linux.intel.com>
  11 siblings, 0 replies; 40+ messages in thread
From: Jarkko Sakkinen @ 2017-10-10 14:32 UTC (permalink / raw)
  To: intel-sgx-kernel-dev; +Cc: platform-driver-x86, Jarkko Sakkinen

Implements a simple framework for hosting in-kernel LE by using the user
space helper framework.

Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
---
 drivers/platform/x86/intel_sgx/Kconfig     |   2 +
 drivers/platform/x86/intel_sgx/Makefile    |   1 +
 drivers/platform/x86/intel_sgx/sgx.h       |  15 ++
 drivers/platform/x86/intel_sgx/sgx_ioctl.c |  13 +-
 drivers/platform/x86/intel_sgx/sgx_le.c    | 290 +++++++++++++++++++++++++++++
 drivers/platform/x86/intel_sgx/sgx_main.c  |  12 +-
 drivers/platform/x86/intel_sgx/sgx_util.c  |  25 +++
 7 files changed, 352 insertions(+), 6 deletions(-)
 create mode 100644 drivers/platform/x86/intel_sgx/sgx_le.c

diff --git a/drivers/platform/x86/intel_sgx/Kconfig b/drivers/platform/x86/intel_sgx/Kconfig
index 9c445e9f89fa..1a80ca0ddca3 100644
--- a/drivers/platform/x86/intel_sgx/Kconfig
+++ b/drivers/platform/x86/intel_sgx/Kconfig
@@ -9,6 +9,8 @@ config INTEL_SGX
 	default n
 	depends on X86_64 && CPU_SUP_INTEL
 	select MMU_NOTIFIER
+	select CRYPTO
+	select CRYPTO_SHA256
 	---help---
 	Intel(R) SGX is a set of CPU instructions that can be used by
 	applications to set aside private regions of code and data.  The code
diff --git a/drivers/platform/x86/intel_sgx/Makefile b/drivers/platform/x86/intel_sgx/Makefile
index 39c0a5ad242c..34abcdd8eb72 100644
--- a/drivers/platform/x86/intel_sgx/Makefile
+++ b/drivers/platform/x86/intel_sgx/Makefile
@@ -11,6 +11,7 @@ intel_sgx-$(CONFIG_INTEL_SGX) += \
 	sgx_page_cache.o \
 	sgx_util.o \
 	sgx_vma.o \
+	sgx_le.o \
 	sgx_le_proxy_piggy.o
 
 $(eval $(call config_filename,INTEL_SGX_SIGNING_KEY))
diff --git a/drivers/platform/x86/intel_sgx/sgx.h b/drivers/platform/x86/intel_sgx/sgx.h
index 74bb91fe6176..94b6855fdad0 100644
--- a/drivers/platform/x86/intel_sgx/sgx.h
+++ b/drivers/platform/x86/intel_sgx/sgx.h
@@ -68,6 +68,7 @@
 #include <linux/workqueue.h>
 #include <linux/mmu_notifier.h>
 #include <linux/radix-tree.h>
+#include <crypto/hash.h>
 #include <asm/sgx.h>
 
 #define SGX_EINIT_SPIN_COUNT	20
@@ -178,6 +179,7 @@ extern u32 sgx_misc_reserved;
 extern u32 sgx_xsave_size_tbl[64];
 extern bool sgx_locked_msrs;
 
+extern const struct file_operations sgx_fops;
 extern const struct vm_operations_struct sgx_vm_ops;
 
 #define sgx_pr_ratelimited(level, encl, fmt, ...)			  \
@@ -231,6 +233,9 @@ struct sgx_encl_page *sgx_fault_page(struct vm_area_struct *vma,
 				     unsigned int flags);
 
 
+int sgx_get_key_hash(struct crypto_shash *tfm, const void *modulus, void *hash);
+int sgx_get_key_hash_simple(const void *modulus, void *hash);
+
 extern struct mutex sgx_tgid_ctx_mutex;
 extern struct list_head sgx_tgid_ctx_list;
 extern atomic_t sgx_va_pages_cnt;
@@ -245,4 +250,14 @@ void sgx_put_page(void *epc_page_vaddr);
 void sgx_eblock(struct sgx_encl *encl, struct sgx_epc_page *epc_page);
 void sgx_etrack(struct sgx_encl *encl);
 
+extern struct sgx_le_ctx sgx_le_ctx;
+
+int sgx_le_init(struct sgx_le_ctx *ctx);
+void sgx_le_exit(struct sgx_le_ctx *ctx);
+
+int sgx_le_get_token(struct sgx_le_ctx *ctx,
+		     const struct sgx_encl *encl,
+		     const struct sgx_sigstruct *sigstruct,
+		     struct sgx_einittoken *token);
+
 #endif /* __ARCH_X86_INTEL_SGX_H__ */
diff --git a/drivers/platform/x86/intel_sgx/sgx_ioctl.c b/drivers/platform/x86/intel_sgx/sgx_ioctl.c
index 7a3af4863356..e4860d75e6b8 100644
--- a/drivers/platform/x86/intel_sgx/sgx_ioctl.c
+++ b/drivers/platform/x86/intel_sgx/sgx_ioctl.c
@@ -69,7 +69,7 @@
 #include <linux/hashtable.h>
 #include <linux/shmem_fs.h>
 
-static int sgx_get_encl(unsigned long addr, struct sgx_encl **encl)
+static int sgx_encl_get(unsigned long addr, struct sgx_encl **encl)
 {
 	struct mm_struct *mm = current->mm;
 	struct vm_area_struct *vma;
@@ -156,7 +156,7 @@ static long sgx_ioc_enclave_add_page(struct file *filep, unsigned int cmd,
 	void *data;
 	int ret;
 
-	ret = sgx_get_encl(addp->addr, &encl);
+	ret = sgx_encl_get(addp->addr, &encl);
 	if (ret)
 		return ret;
 
@@ -227,11 +227,16 @@ static long sgx_ioc_enclave_init(struct file *filep, unsigned int cmd,
 	if (ret)
 		goto out;
 
-	ret = sgx_get_encl(encl_id, &encl);
+	ret = sgx_encl_get(encl_id, &encl);
 	if (ret)
 		goto out;
 
-	ret = sgx_encl_init(encl, sigstruct, einittoken);
+	if (!(initp->flags && SGX_ENCLAVE_INIT_ARCH))
+		ret = sgx_le_get_token(&sgx_le_ctx, encl, sigstruct,
+				       einittoken);
+
+	if (!ret)
+		ret = sgx_encl_init(encl, sigstruct, einittoken);
 
 	kref_put(&encl->refcount, sgx_encl_release);
 
diff --git a/drivers/platform/x86/intel_sgx/sgx_le.c b/drivers/platform/x86/intel_sgx/sgx_le.c
new file mode 100644
index 000000000000..c4ed8e1ea70b
--- /dev/null
+++ b/drivers/platform/x86/intel_sgx/sgx_le.c
@@ -0,0 +1,290 @@
+/*
+ * This file is provided under a dual BSD/GPLv2 license.  When using or
+ * redistributing this file, you may do so under either license.
+ *
+ * GPL LICENSE SUMMARY
+ *
+ * Copyright(c) 2017 Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License 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.
+ *
+ * Contact Information:
+ * Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
+ * Intel Finland Oy - BIC 0357606-4 - Westendinkatu 7, 02160 Espoo
+ *
+ * BSD LICENSE
+ *
+ * Copyright(c) 2016 Intel Corporation.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ *   * Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ *   * Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in
+ *     the documentation and/or other materials provided with the
+ *     distribution.
+ *   * Neither the name of Intel Corporation nor the names of its
+ *     contributors may be used to endorse or promote products derived
+ *     from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * Authors:
+ *
+ * Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
+ */
+
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/kmod.h>
+#include <linux/mutex.h>
+#include <linux/wait.h>
+#include <linux/pipe_fs_i.h>
+#include <linux/sched/signal.h>
+#include <linux/shmem_fs.h>
+#include <linux/anon_inodes.h>
+#include "sgx.h"
+
+#define SGX_LE_PROXY_PATH "/proc/self/fd/3"
+#define SGX_LE_PROXY_FD 3
+#define SGX_LE_DEV_FD 4
+
+extern unsigned char sgx_le_proxy[];
+extern unsigned char sgx_le_proxy_end[];
+
+struct sgx_le_ctx {
+	struct pid *tgid;
+	char *argv[2];
+	struct file *pipes[2];
+	struct crypto_shash *tfm;
+	struct mutex lock;
+};
+
+struct sgx_le_ctx sgx_le_ctx;
+
+static int sgx_le_create_pipe(struct sgx_le_ctx *ctx,
+			      unsigned int fd)
+{
+	struct file *files[2];
+	int ret;
+
+	ret = create_pipe_files(files, 0);
+	if (ret)
+		goto out;
+
+	ctx->pipes[fd] = files[fd ^ 1];
+	ret = replace_fd(fd, files[fd], 0);
+	fput(files[fd]);
+
+out:
+	return ret;
+}
+
+static int sgx_le_read(struct file *file, void *data, unsigned int len)
+{
+	ssize_t ret;
+	loff_t pos = 0;
+
+	ret = kernel_read(file, data, len, &pos);
+
+	if (ret != len && ret >= 0)
+		return -ENOMEM;
+
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int sgx_le_write(struct file *file, const void *data,
+			unsigned int len)
+{
+	ssize_t ret;
+	loff_t pos = 0;
+
+	ret = kernel_write(file, data, len, &pos);
+
+	if (ret != len && ret >= 0)
+		return -ENOMEM;
+
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+static int sgx_le_task_init(struct subprocess_info *subinfo, struct cred *new)
+{
+	struct sgx_le_ctx *ctx =
+		(struct sgx_le_ctx *)subinfo->data;
+	unsigned long len;
+	struct file *tmp_filp;
+	int ret;
+
+	len = (unsigned long)&sgx_le_proxy_end - (unsigned long)&sgx_le_proxy;
+
+	tmp_filp = shmem_file_setup("[sgx_le_proxy]", len, 0);
+	if (IS_ERR(tmp_filp)) {
+		ret = PTR_ERR(tmp_filp);
+		return ret;
+	}
+	ret = replace_fd(SGX_LE_PROXY_FD, tmp_filp, 0);
+	fput(tmp_filp);
+	if (ret < 0)
+		return ret;
+
+	ret = sgx_le_write(tmp_filp, &sgx_le_proxy, len);
+	if (ret)
+		return ret;
+
+	tmp_filp = anon_inode_getfile("[/dev/sgx]", &sgx_fops, NULL, O_RDWR);
+	if (IS_ERR(tmp_filp))
+		return PTR_ERR(tmp_filp);
+	ret = replace_fd(SGX_LE_DEV_FD, tmp_filp, 0);
+	fput(tmp_filp);
+	if (ret < 0)
+		return ret;
+
+	ret = sgx_le_create_pipe(ctx, 0);
+	if (ret < 0)
+		return ret;
+
+	ret = sgx_le_create_pipe(ctx, 1);
+	if (ret < 0)
+		return ret;
+
+	ctx->tgid = get_pid(task_tgid(current));
+
+	return 0;
+}
+
+static void sgx_le_stop(struct sgx_le_ctx *ctx)
+{
+	int i;
+
+	if (ctx->tgid)
+		kill_pid(ctx->tgid, SIGKILL, 1);
+
+	for (i = 0; i < ARRAY_SIZE(ctx->pipes); i++) {
+		if (ctx->pipes[i]) {
+			fput(ctx->pipes[i]);
+			ctx->pipes[i] = NULL;
+		}
+	}
+
+	if (ctx->tgid) {
+		put_pid(ctx->tgid);
+		ctx->tgid = NULL;
+	}
+}
+
+static int sgx_le_start(struct sgx_le_ctx *ctx)
+{
+	struct subprocess_info *subinfo;
+	int ret;
+
+	if (ctx->tgid)
+		return 0;
+
+	ctx->argv[0] = SGX_LE_PROXY_PATH;
+	ctx->argv[1] = NULL;
+
+	subinfo = call_usermodehelper_setup(ctx->argv[0], ctx->argv,
+					    NULL, GFP_KERNEL, sgx_le_task_init,
+					    NULL, &sgx_le_ctx);
+	if (!subinfo)
+		return -ENOMEM;
+
+	ret = call_usermodehelper_exec(subinfo, UMH_WAIT_EXEC);
+	if (ret) {
+		sgx_le_stop(ctx);
+		return ret;
+	}
+
+	return 0;
+}
+
+int sgx_le_init(struct sgx_le_ctx *ctx)
+{
+	struct crypto_shash *tfm;
+
+	tfm = crypto_alloc_shash("sha256", 0, CRYPTO_ALG_ASYNC);
+	if (IS_ERR(tfm))
+		return PTR_ERR(tfm);
+
+	ctx->tfm = tfm;
+	mutex_init(&ctx->lock);
+
+	return 0;
+}
+
+void sgx_le_exit(struct sgx_le_ctx *ctx)
+{
+	mutex_lock(&ctx->lock);
+	sgx_le_stop(ctx);
+	crypto_free_shash(ctx->tfm);
+	mutex_unlock(&ctx->lock);
+}
+
+int sgx_le_get_token(struct sgx_le_ctx *ctx,
+		     const struct sgx_encl *encl,
+		     const struct sgx_sigstruct *sigstruct,
+		     struct sgx_einittoken *token)
+{
+	u8 mrsigner[32];
+	ssize_t ret;
+
+	mutex_lock(&ctx->lock);
+
+	ret = sgx_get_key_hash(ctx->tfm, sigstruct->modulus, mrsigner);
+	if (ret)
+		goto out_unlock;
+
+	ret = sgx_le_start(ctx);
+	if (ret)
+		goto out_unlock;
+
+	ret = sgx_le_write(ctx->pipes[0], sigstruct->body.mrenclave, 32);
+	if (ret)
+		goto out_stop;
+
+	ret = sgx_le_write(ctx->pipes[0], mrsigner, 32);
+	if (ret)
+		goto out_stop;
+
+	ret = sgx_le_write(ctx->pipes[0], &encl->attributes, sizeof(uint64_t));
+	if (ret)
+		goto out_stop;
+
+	ret = sgx_le_write(ctx->pipes[0], &encl->xfrm, sizeof(uint64_t));
+	if (ret)
+		goto out_stop;
+
+	ret = sgx_le_read(ctx->pipes[1], token, sizeof(*token));
+
+out_stop:
+	sgx_le_stop(ctx);
+out_unlock:
+	mutex_unlock(&ctx->lock);
+	return ret;
+}
diff --git a/drivers/platform/x86/intel_sgx/sgx_main.c b/drivers/platform/x86/intel_sgx/sgx_main.c
index 2ad2dc88edff..0747be390570 100644
--- a/drivers/platform/x86/intel_sgx/sgx_main.c
+++ b/drivers/platform/x86/intel_sgx/sgx_main.c
@@ -143,7 +143,7 @@ static unsigned long sgx_get_unmapped_area(struct file *file,
 	return addr;
 }
 
-static const struct file_operations sgx_fops = {
+const struct file_operations sgx_fops = {
 	.owner			= THIS_MODULE,
 	.unlocked_ioctl		= sgx_ioctl,
 #ifdef CONFIG_COMPAT
@@ -315,11 +315,17 @@ static int sgx_dev_init(struct device *parent, bool locked_msrs)
 		goto out_iounmap;
 	}
 
-	ret = cdev_device_add(&sgx_dev->cdev, &sgx_dev->dev);
+	ret = sgx_le_init(&sgx_le_ctx);
 	if (ret)
 		goto out_workqueue;
 
+	ret = cdev_device_add(&sgx_dev->cdev, &sgx_dev->dev);
+	if (ret)
+		goto out_le;
+
 	return 0;
+out_le:
+	sgx_le_exit(&sgx_le_ctx);
 out_workqueue:
 	destroy_workqueue(sgx_add_page_wq);
 out_iounmap:
@@ -387,6 +393,8 @@ static int sgx_drv_remove(struct platform_device *pdev)
 
 	cdev_device_del(&ctx->cdev, &ctx->dev);
 
+	sgx_le_exit(&sgx_le_ctx);
+
 	destroy_workqueue(sgx_add_page_wq);
 #ifdef CONFIG_X86_64
 	for (i = 0; i < sgx_nr_epc_banks; i++)
diff --git a/drivers/platform/x86/intel_sgx/sgx_util.c b/drivers/platform/x86/intel_sgx/sgx_util.c
index 0ea5670f65a4..1df60ade7829 100644
--- a/drivers/platform/x86/intel_sgx/sgx_util.c
+++ b/drivers/platform/x86/intel_sgx/sgx_util.c
@@ -369,3 +369,28 @@ void sgx_etrack(struct sgx_encl *encl)
 		sgx_invalidate(encl, true);
 	}
 }
+
+int sgx_get_key_hash(struct crypto_shash *tfm, const void *modulus, void *hash)
+{
+	SHASH_DESC_ON_STACK(shash, tfm);
+
+	shash->tfm = tfm;
+	shash->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
+
+	return crypto_shash_digest(shash, modulus, SGX_MODULUS_SIZE, hash);
+}
+
+int sgx_get_key_hash_simple(const void *modulus, void *hash)
+{
+	struct crypto_shash *tfm;
+	int ret;
+
+	tfm = crypto_alloc_shash("sha256", 0, CRYPTO_ALG_ASYNC);
+	if (IS_ERR(tfm))
+		return PTR_ERR(tfm);
+
+	ret = sgx_get_key_hash(tfm, modulus, hash);
+
+	crypto_free_shash(tfm);
+	return ret;
+}
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 40+ messages in thread

* [PATCH RFC v3 12/12] intel_sgx: update IA32_SGXLEPUBKEYHASH* MSRs
  2017-10-10 14:32 [PATCH RFC v3 00/12] Intel(R) SGX Driver Jarkko Sakkinen
                   ` (9 preceding siblings ...)
  2017-10-10 14:32 ` [PATCH RFC v3 11/12] intel_sgx: glue code for in-kernel LE Jarkko Sakkinen
@ 2017-10-10 14:32 ` Jarkko Sakkinen
       [not found] ` <20171010143258.21623-8-jarkko.sakkinen@linux.intel.com>
  11 siblings, 0 replies; 40+ messages in thread
From: Jarkko Sakkinen @ 2017-10-10 14:32 UTC (permalink / raw)
  To: intel-sgx-kernel-dev; +Cc: platform-driver-x86, Jarkko Sakkinen

Check if IA32_SGXLEPUBKEYHASH* MSRs match. If they do not match, allow
the driver initialization to continue only if they are writable. In this
case update them with the MRSIGNER of the launch enclave.

Signed-off-by: Jarkko Sakkinen <jarkko.sakkinen@linux.intel.com>
---
 drivers/platform/x86/intel_sgx/sgx.h                |  1 +
 drivers/platform/x86/intel_sgx/sgx_encl.c           | 20 ++++++++++++++++++++
 drivers/platform/x86/intel_sgx/sgx_le_proxy_piggy.S |  4 ++++
 drivers/platform/x86/intel_sgx/sgx_main.c           |  7 ++++++-
 4 files changed, 31 insertions(+), 1 deletion(-)

diff --git a/drivers/platform/x86/intel_sgx/sgx.h b/drivers/platform/x86/intel_sgx/sgx.h
index 94b6855fdad0..cf66bda37c1f 100644
--- a/drivers/platform/x86/intel_sgx/sgx.h
+++ b/drivers/platform/x86/intel_sgx/sgx.h
@@ -178,6 +178,7 @@ extern u64 sgx_xfrm_mask;
 extern u32 sgx_misc_reserved;
 extern u32 sgx_xsave_size_tbl[64];
 extern bool sgx_locked_msrs;
+extern u64 sgx_le_pubkeyhash[4];
 
 extern const struct file_operations sgx_fops;
 extern const struct vm_operations_struct sgx_vm_ops;
diff --git a/drivers/platform/x86/intel_sgx/sgx_encl.c b/drivers/platform/x86/intel_sgx/sgx_encl.c
index aa0deed08cee..ac4c28c527c2 100644
--- a/drivers/platform/x86/intel_sgx/sgx_encl.c
+++ b/drivers/platform/x86/intel_sgx/sgx_encl.c
@@ -68,6 +68,7 @@
 #include <linux/slab.h>
 #include <linux/hashtable.h>
 #include <linux/shmem_fs.h>
+#include <linux/percpu.h>
 
 struct sgx_add_page_req {
 	struct sgx_encl *encl;
@@ -874,6 +875,17 @@ static int sgx_einit(struct sgx_encl *encl, struct sgx_sigstruct *sigstruct,
 	return ret;
 }
 
+static void sgx_update_pubkeyhash(void)
+{
+	if (sgx_locked_msrs)
+		return;
+
+	wrmsrl(MSR_IA32_SGXLEPUBKEYHASH0, sgx_le_pubkeyhash[0]);
+	wrmsrl(MSR_IA32_SGXLEPUBKEYHASH1, sgx_le_pubkeyhash[1]);
+	wrmsrl(MSR_IA32_SGXLEPUBKEYHASH2, sgx_le_pubkeyhash[2]);
+	wrmsrl(MSR_IA32_SGXLEPUBKEYHASH3, sgx_le_pubkeyhash[3]);
+}
+
 /**
  * sgx_encl_init - perform EINIT for the given enclave
  *
@@ -909,6 +921,14 @@ int sgx_encl_init(struct sgx_encl *encl, struct sgx_sigstruct *sigstruct,
 		for (j = 0; j < SGX_EINIT_SPIN_COUNT; j++) {
 			ret = sgx_einit(encl, sigstruct, token);
 
+			if (ret == SGX_INVALID_ATTRIBUTE ||
+			    ret == SGX_INVALID_EINITTOKEN) {
+				preempt_disable();
+				sgx_update_pubkeyhash();
+				ret = sgx_einit(encl, sigstruct, token);
+				preempt_enable();
+			}
+
 			if (ret == SGX_UNMASKED_EVENT)
 				continue;
 			else
diff --git a/drivers/platform/x86/intel_sgx/sgx_le_proxy_piggy.S b/drivers/platform/x86/intel_sgx/sgx_le_proxy_piggy.S
index faced8a9a75a..e1e3742a0c93 100644
--- a/drivers/platform/x86/intel_sgx/sgx_le_proxy_piggy.S
+++ b/drivers/platform/x86/intel_sgx/sgx_le_proxy_piggy.S
@@ -9,3 +9,7 @@ GLOBAL(sgx_le_proxy)
 END(sgx_le_proxy)
 
 GLOBAL(sgx_le_proxy_end)
+
+GLOBAL(sgx_le_ss)
+	.incbin	"drivers/platform/x86/intel_sgx/le/enclave/sgx_le.ss"
+END(sgx_le_ss)
diff --git a/drivers/platform/x86/intel_sgx/sgx_main.c b/drivers/platform/x86/intel_sgx/sgx_main.c
index 0747be390570..8380ad56f6a0 100644
--- a/drivers/platform/x86/intel_sgx/sgx_main.c
+++ b/drivers/platform/x86/intel_sgx/sgx_main.c
@@ -80,6 +80,7 @@ MODULE_VERSION(DRV_VERSION);
  * Global data.
  */
 
+extern struct sgx_sigstruct sgx_le_ss;
 struct workqueue_struct *sgx_add_page_wq;
 #define SGX_MAX_EPC_BANKS 8
 struct sgx_epc_bank sgx_epc_banks[SGX_MAX_EPC_BANKS];
@@ -90,6 +91,7 @@ u64 sgx_xfrm_mask = 0x3;
 u32 sgx_misc_reserved;
 u32 sgx_xsave_size_tbl[64];
 bool sgx_locked_msrs;
+u64 sgx_le_pubkeyhash[4];
 
 #ifdef CONFIG_COMPAT
 long sgx_compat_ioctl(struct file *filep, unsigned int cmd, unsigned long arg)
@@ -267,6 +269,10 @@ static int sgx_dev_init(struct device *parent, bool locked_msrs)
 		}
 	}
 
+	ret = sgx_get_key_hash_simple(sgx_le_ss.modulus, sgx_le_pubkeyhash);
+	if (ret)
+		return ret;
+
 	for (i = 0; i < SGX_MAX_EPC_BANKS; i++) {
 		cpuid_count(SGX_CPUID, i + SGX_CPUID_EPC_BANKS, &eax, &ebx,
 			    &ecx, &edx);
@@ -356,7 +362,6 @@ static int sgx_drv_probe(struct platform_device *pdev)
 	}
 
 	rdmsrl(MSR_IA32_FEATURE_CONTROL, fc);
-
 	if (!(fc & FEATURE_CONTROL_LOCKED)) {
 		pr_err("intel_sgx: the feature control MSR is not locked\n");
 		return -ENODEV;
-- 
2.14.1

^ permalink raw reply related	[flat|nested] 40+ messages in thread

* Re: [intel-sgx-kernel-dev] [PATCH RFC v3 07/12] intel_sgx: driver for Intel Software Guard Extensions
       [not found] ` <20171010143258.21623-8-jarkko.sakkinen@linux.intel.com>
@ 2017-10-10 15:41   ` Sean Christopherson
  2017-10-11 11:46     ` Jarkko Sakkinen
  2017-10-10 18:26   ` Sean Christopherson
                     ` (4 subsequent siblings)
  5 siblings, 1 reply; 40+ messages in thread
From: Sean Christopherson @ 2017-10-10 15:41 UTC (permalink / raw)
  To: Jarkko Sakkinen; +Cc: intel-sgx-kernel-dev, platform-driver-x86

On Tue, Oct 10, 2017 at 05:32:53PM +0300, Jarkko Sakkinen wrote:
> diff --git a/drivers/platform/x86/intel_sgx/sgx_page_cache.c b/drivers/platform/x86/intel_sgx/sgx_page_cache.c
> new file mode 100644
> index 000000000000..1089b563e07b
> --- /dev/null
> +++ b/drivers/platform/x86/intel_sgx/sgx_page_cache.c
>
> +/**
> + * sgx_alloc_page - allocate an EPC page
> + * @flags:	allocation flags
> + *
> + * Try to grab a page from the free EPC page list. If there is a free page
> + * available, it is returned to the caller. If called with SGX_ALLOC_ATOMIC,
> + * the function will return immediately if the list is empty. Otherwise, it
> + * will swap pages up until there is a free page available. Before returning
> + * the low watermark is checked and ksgxswapd is waken up if we are below it.
> + *
> + * Return: an EPC page or a system error code
> + */
> +struct sgx_epc_page *sgx_alloc_page(unsigned int flags)
> +{
> +	struct sgx_epc_page *entry;
> +
> +	for ( ; ; ) {
> +		entry = sgx_alloc_page_fast();
> +		if (entry)
> +			break;
> +
> +		/* We need at minimum two pages for the #PF handler. */
> +		if (atomic_read(&sgx_va_pages_cnt) >
> +		    (sgx_nr_total_epc_pages - 2))
> +			return ERR_PTR(-ENOMEM);
> +
> +		if (flags & SGX_ALLOC_ATOMIC) {
> +			entry = ERR_PTR(-EBUSY);
> +			break;
> +		}
> +
> +		if (signal_pending(current)) {
> +			entry = ERR_PTR(-ERESTARTSYS);
> +			break;
> +		}
> +
> +		sgx_swap_pages(SGX_NR_SWAP_CLUSTER_MAX);
> +		schedule();
> +	}
> +
> +	if (sgx_nr_free_pages < sgx_nr_low_pages)
> +		wake_up(&ksgxswapd_waitq);
> +
> +	return entry;
> +}
> +EXPORT_SYMBOL(sgx_alloc_page);

I think it makes sense to remove the exports from sgx_page_cache.c
for the initial upstreaming given that the only consumer is the
pre-release/out-of-tree KVM module, which generally requires
recompiling the entire kernel anyways.

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [intel-sgx-kernel-dev] [PATCH RFC v3 07/12] intel_sgx: driver for Intel Software Guard Extensions
       [not found] ` <20171010143258.21623-8-jarkko.sakkinen@linux.intel.com>
  2017-10-10 15:41   ` [intel-sgx-kernel-dev] [PATCH RFC v3 07/12] intel_sgx: driver for Intel Software Guard Extensions Sean Christopherson
@ 2017-10-10 18:26   ` Sean Christopherson
  2017-10-13 19:58     ` Jarkko Sakkinen
  2017-10-12 16:48   ` Sean Christopherson
                     ` (3 subsequent siblings)
  5 siblings, 1 reply; 40+ messages in thread
From: Sean Christopherson @ 2017-10-10 18:26 UTC (permalink / raw)
  To: Jarkko Sakkinen; +Cc: intel-sgx-kernel-dev, platform-driver-x86

On Tue, Oct 10, 2017 at 05:32:53PM +0300, Jarkko Sakkinen wrote:
> diff --git a/drivers/platform/x86/intel_sgx/sgx_encl.c b/drivers/platform/x86/intel_sgx/sgx_encl.c
> new file mode 100644
> index 000000000000..aa0deed08cee
> --- /dev/null
> +++ b/drivers/platform/x86/intel_sgx/sgx_encl.c
> @@ -0,0 +1,989 @@
>
> +/**
> + * sgx_encl_find - find an enclave
> + * @mm:		mm struct of the current process
> + * @addr:	address in the ELRANGE
> + * @created	is the enclave already created?
> + * @vma:	the resulting VMA
> + *
> + * Finds an enclave identified by the given address. Gives back the VMA, that is
> + * part of the enclave, located in that address.
> + *
> + * Return:
> + * 0 on success,
> + * -EINVAL if not found,
> + */
> +int sgx_encl_find(struct mm_struct *mm, unsigned long addr, bool created,
> +		  struct vm_area_struct **vma)
> +{
> +	struct vm_area_struct *result;
> +	struct sgx_encl *encl;
> +
> +	result = find_vma(mm, addr);
> +	if (!result || result->vm_ops != &sgx_vm_ops || addr < result->vm_start)
> +		return -EINVAL;
> +
> +	encl = result->vm_private_data;
> +	if (created) {
> +		if (!encl)
> +			return -EINVAL;
> +	} else {
> +		if (encl)
> +			return -EINVAL;
> +	}

What about removing @created and returning -ENOENT (or -ENXIO?) if 
result->vm_private_data is NULL?  Removing @created will eliminate
any potential confusion for the common case of @created=true.  For
@created=false, which should be limited to sgx_encl_create, I think
that explicitly checking for "ret != -ENOENT" is more intuitive
than checking whether or not sgx_encl_find succeeded, e.g. I knew
the intent of the check in sgx_encl_create ahead of time and I still
had to walk through sgx_encl_find to verify the behavior.

> +
> +	*vma = result;
> +	return 0;
> +}
> +

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [intel-sgx-kernel-dev] [PATCH RFC v3 07/12] intel_sgx: driver for Intel Software Guard Extensions
  2017-10-10 15:41   ` [intel-sgx-kernel-dev] [PATCH RFC v3 07/12] intel_sgx: driver for Intel Software Guard Extensions Sean Christopherson
@ 2017-10-11 11:46     ` Jarkko Sakkinen
  2017-10-11 15:56       ` Sean Christopherson
  0 siblings, 1 reply; 40+ messages in thread
From: Jarkko Sakkinen @ 2017-10-11 11:46 UTC (permalink / raw)
  To: Sean Christopherson; +Cc: intel-sgx-kernel-dev, platform-driver-x86

On Tue, Oct 10, 2017 at 08:41:36AM -0700, Sean Christopherson wrote:
> On Tue, Oct 10, 2017 at 05:32:53PM +0300, Jarkko Sakkinen wrote:
> > diff --git a/drivers/platform/x86/intel_sgx/sgx_page_cache.c b/drivers/platform/x86/intel_sgx/sgx_page_cache.c
> > new file mode 100644
> > index 000000000000..1089b563e07b
> > --- /dev/null
> > +++ b/drivers/platform/x86/intel_sgx/sgx_page_cache.c
> >
> > +/**
> > + * sgx_alloc_page - allocate an EPC page
> > + * @flags:	allocation flags
> > + *
> > + * Try to grab a page from the free EPC page list. If there is a free page
> > + * available, it is returned to the caller. If called with SGX_ALLOC_ATOMIC,
> > + * the function will return immediately if the list is empty. Otherwise, it
> > + * will swap pages up until there is a free page available. Before returning
> > + * the low watermark is checked and ksgxswapd is waken up if we are below it.
> > + *
> > + * Return: an EPC page or a system error code
> > + */
> > +struct sgx_epc_page *sgx_alloc_page(unsigned int flags)
> > +{
> > +	struct sgx_epc_page *entry;
> > +
> > +	for ( ; ; ) {
> > +		entry = sgx_alloc_page_fast();
> > +		if (entry)
> > +			break;
> > +
> > +		/* We need at minimum two pages for the #PF handler. */
> > +		if (atomic_read(&sgx_va_pages_cnt) >
> > +		    (sgx_nr_total_epc_pages - 2))
> > +			return ERR_PTR(-ENOMEM);
> > +
> > +		if (flags & SGX_ALLOC_ATOMIC) {
> > +			entry = ERR_PTR(-EBUSY);
> > +			break;
> > +		}
> > +
> > +		if (signal_pending(current)) {
> > +			entry = ERR_PTR(-ERESTARTSYS);
> > +			break;
> > +		}
> > +
> > +		sgx_swap_pages(SGX_NR_SWAP_CLUSTER_MAX);
> > +		schedule();
> > +	}
> > +
> > +	if (sgx_nr_free_pages < sgx_nr_low_pages)
> > +		wake_up(&ksgxswapd_waitq);
> > +
> > +	return entry;
> > +}
> > +EXPORT_SYMBOL(sgx_alloc_page);
> 
> I think it makes sense to remove the exports from sgx_page_cache.c
> for the initial upstreaming given that the only consumer is the
> pre-release/out-of-tree KVM module, which generally requires
> recompiling the entire kernel anyways.

Forgot them. Thanks.

For the same reason as you described I removed them from
arch/x86/include/asm/sgx.h

/Jarkko

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [intel-sgx-kernel-dev] [PATCH RFC v3 07/12] intel_sgx: driver for Intel Software Guard Extensions
  2017-10-11 11:46     ` Jarkko Sakkinen
@ 2017-10-11 15:56       ` Sean Christopherson
  0 siblings, 0 replies; 40+ messages in thread
From: Sean Christopherson @ 2017-10-11 15:56 UTC (permalink / raw)
  To: Jarkko Sakkinen; +Cc: intel-sgx-kernel-dev, platform-driver-x86

On Wed, Oct 11, 2017 at 02:46:51PM +0300, Jarkko Sakkinen wrote:
> On Tue, Oct 10, 2017 at 08:41:36AM -0700, Sean Christopherson wrote:
> > On Tue, Oct 10, 2017 at 05:32:53PM +0300, Jarkko Sakkinen wrote:
> > > diff --git a/drivers/platform/x86/intel_sgx/sgx_page_cache.c b/drivers/platform/x86/intel_sgx/sgx_page_cache.c
> > > new file mode 100644
> > > index 000000000000..1089b563e07b
> > > --- /dev/null
> > > +++ b/drivers/platform/x86/intel_sgx/sgx_page_cache.c
> > >
> > > +/**
> > > + * sgx_alloc_page - allocate an EPC page
> > > + * @flags:	allocation flags
> > > + *
> > > + * Try to grab a page from the free EPC page list. If there is a free page
> > > + * available, it is returned to the caller. If called with SGX_ALLOC_ATOMIC,
> > > + * the function will return immediately if the list is empty. Otherwise, it
> > > + * will swap pages up until there is a free page available. Before returning
> > > + * the low watermark is checked and ksgxswapd is waken up if we are below it.
> > > + *
> > > + * Return: an EPC page or a system error code
> > > + */
> > > +struct sgx_epc_page *sgx_alloc_page(unsigned int flags)
> > > +{
> > > +	struct sgx_epc_page *entry;
> > > +
> > > +	for ( ; ; ) {
> > > +		entry = sgx_alloc_page_fast();
> > > +		if (entry)
> > > +			break;
> > > +
> > > +		/* We need at minimum two pages for the #PF handler. */
> > > +		if (atomic_read(&sgx_va_pages_cnt) >
> > > +		    (sgx_nr_total_epc_pages - 2))
> > > +			return ERR_PTR(-ENOMEM);
> > > +
> > > +		if (flags & SGX_ALLOC_ATOMIC) {
> > > +			entry = ERR_PTR(-EBUSY);
> > > +			break;
> > > +		}
> > > +
> > > +		if (signal_pending(current)) {
> > > +			entry = ERR_PTR(-ERESTARTSYS);
> > > +			break;
> > > +		}
> > > +
> > > +		sgx_swap_pages(SGX_NR_SWAP_CLUSTER_MAX);
> > > +		schedule();
> > > +	}
> > > +
> > > +	if (sgx_nr_free_pages < sgx_nr_low_pages)
> > > +		wake_up(&ksgxswapd_waitq);
> > > +
> > > +	return entry;
> > > +}
> > > +EXPORT_SYMBOL(sgx_alloc_page);
> > 
> > I think it makes sense to remove the exports from sgx_page_cache.c
> > for the initial upstreaming given that the only consumer is the
> > pre-release/out-of-tree KVM module, which generally requires
> > recompiling the entire kernel anyways.
> 
> Forgot them. Thanks.
> 
> For the same reason as you described I removed them from
> arch/x86/include/asm/sgx.h

sgx_free_page can also be cleaned up a bit if it's no longer
exported, proposed patch below.


intel_sgx: make encl a required param for sgx_free_page

sgx_free_page is no longer exported, and so encl is no longer an
optional param as all driver usage must specify the encl.  Making
encl required also eliminates the path that returns a value, i.e.
modify sgx_free_page to have a void return.

Signed-off-by: Sean Christopherson <sean.j.christopherson@intel.com>
---
 drivers/platform/x86/intel_sgx/sgx.h            |  2 +-
 drivers/platform/x86/intel_sgx/sgx_page_cache.c | 29 ++++++-------------------
 2 files changed, 8 insertions(+), 23 deletions(-)

diff --git a/drivers/platform/x86/intel_sgx/sgx.h b/drivers/platform/x86/intel_sgx/sgx.h
index cf66bda37c1f..17eb75604184 100644
--- a/drivers/platform/x86/intel_sgx/sgx.h
+++ b/drivers/platform/x86/intel_sgx/sgx.h
@@ -245,7 +245,7 @@ int sgx_add_epc_bank(resource_size_t start, unsigned long size, int bank);
 int sgx_page_cache_init(void);
 void sgx_page_cache_teardown(void);
 struct sgx_epc_page *sgx_alloc_page(unsigned int flags);
-int sgx_free_page(struct sgx_epc_page *entry, struct sgx_encl *encl);
+void sgx_free_page(struct sgx_epc_page *entry, struct sgx_encl *encl);
 void *sgx_get_page(struct sgx_epc_page *entry);
 void sgx_put_page(void *epc_page_vaddr);
 void sgx_eblock(struct sgx_encl *encl, struct sgx_epc_page *epc_page);
diff --git a/drivers/platform/x86/intel_sgx/sgx_page_cache.c b/drivers/platform/x86/intel_sgx/sgx_page_cache.c
index f8252a8b3893..bbd8ca630d9c 100644
--- a/drivers/platform/x86/intel_sgx/sgx_page_cache.c
+++ b/drivers/platform/x86/intel_sgx/sgx_page_cache.c
@@ -522,23 +522,14 @@ struct sgx_epc_page *sgx_alloc_page(unsigned int flags)
 /**
  * sgx_free_page - free an EPC page
  *
- * EREMOVE an EPC page and insert it back to the list of free pages. Optionally,
- * an enclave can be given as a parameter. If the enclave is given, the
- * resulting error is printed out loud as a critical error. It is an indicator
- * of a driver bug if that would happen.
- *
- * If the enclave is not given as a parameter (like in the case when VMM uses
- * this function)), it is fully up to the caller to deal with the return value,
- * including printing it to the klog if it wants to do such a thing.
+ * EREMOVE an EPC page and insert it back to the list of free pages.
+ * If EREMOVE fails, the error is printed out loud as a critical error.
+ * It is an indicator of a driver bug if that would happen.
  *
  * @entry:	any EPC page
- * @encl:	enclave that owns the given EPC page (optional)
- *
- * Return:
- * 0 on success,
- * SGX error code if an enclave is not defined
+ * @encl:	enclave that owns the given EPC page
  */
-int sgx_free_page(struct sgx_epc_page *entry, struct sgx_encl *encl)
+void sgx_free_page(struct sgx_epc_page *entry, struct sgx_encl *encl)
 {
 	void *epc;
 	int ret;
@@ -547,19 +538,13 @@ int sgx_free_page(struct sgx_epc_page *entry, struct sgx_encl *encl)
 	ret = __eremove(epc);
 	sgx_put_page(epc);
 
-	if (ret) {
-		if (encl)
-			sgx_crit(encl, "EREMOVE returned %d\n", ret);
-		else
-			return ret;
-	}
+	if (ret)
+		sgx_crit(encl, "EREMOVE returned %d\n", ret);
 
 	spin_lock(&sgx_free_list_lock);
 	list_add(&entry->list, &sgx_free_list);
 	sgx_nr_free_pages++;
 	spin_unlock(&sgx_free_list_lock);
-
-	return 0;
 }
 
 void *sgx_get_page(struct sgx_epc_page *entry)
-- 
2.14.2

^ permalink raw reply related	[flat|nested] 40+ messages in thread

* Re: [intel-sgx-kernel-dev] [PATCH RFC v3 07/12] intel_sgx: driver for Intel Software Guard Extensions
       [not found] ` <20171010143258.21623-8-jarkko.sakkinen@linux.intel.com>
  2017-10-10 15:41   ` [intel-sgx-kernel-dev] [PATCH RFC v3 07/12] intel_sgx: driver for Intel Software Guard Extensions Sean Christopherson
  2017-10-10 18:26   ` Sean Christopherson
@ 2017-10-12 16:48   ` Sean Christopherson
  2017-10-13 19:16     ` Jarkko Sakkinen
  2017-11-02 19:48   ` Sean Christopherson
                     ` (2 subsequent siblings)
  5 siblings, 1 reply; 40+ messages in thread
From: Sean Christopherson @ 2017-10-12 16:48 UTC (permalink / raw)
  To: Jarkko Sakkinen; +Cc: intel-sgx-kernel-dev, platform-driver-x86

On Tue, Oct 10, 2017 at 05:32:53PM +0300, Jarkko Sakkinen wrote:
> diff --git a/drivers/platform/x86/intel_sgx/sgx_main.c b/drivers/platform/x86/intel_sgx/sgx_main.c
> new file mode 100644
> index 000000000000..2ad2dc88edff
> --- /dev/null
> +++ b/drivers/platform/x86/intel_sgx/sgx_main.c
>
> +static dev_t sgx_devt;
> +
> +static void sgx_dev_release(struct device *dev)
> +{
> +	struct sgx_context *ctx = container_of(dev, struct sgx_context, dev);
> +	kfree(ctx);
> +}
> +
> +static struct sgx_context *sgx_ctx_alloc(struct device *parent)
> +{
> +	struct sgx_context *ctx;
> +
> +	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
> +	if (!ctx)
> +		return ERR_PTR(-ENOMEM);
> +
> +	device_initialize(&ctx->dev);
> +
> +	ctx->dev.bus = &sgx_subsys;
> +	ctx->dev.parent = parent;
> +	ctx->dev.devt = MKDEV(MAJOR(sgx_devt), 0);
> +	ctx->dev.release = sgx_dev_release;
> +
> +	dev_set_name(&ctx->dev, "sgx");

/dev/sgx is created with 0600 permissions, does access to SGX really
need to be restricted to root by default?

> +
> +	cdev_init(&ctx->cdev, &sgx_fops);
> +	ctx->cdev.owner = THIS_MODULE;
> +
> +	dev_set_drvdata(parent, ctx);
> +
> +	return ctx;
> +}
> +

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [intel-sgx-kernel-dev] [PATCH RFC v3 07/12] intel_sgx: driver for Intel Software Guard Extensions
  2017-10-12 16:48   ` Sean Christopherson
@ 2017-10-13 19:16     ` Jarkko Sakkinen
  0 siblings, 0 replies; 40+ messages in thread
From: Jarkko Sakkinen @ 2017-10-13 19:16 UTC (permalink / raw)
  To: Sean Christopherson; +Cc: intel-sgx-kernel-dev, platform-driver-x86

On Thu, Oct 12, 2017 at 09:48:15AM -0700, Sean Christopherson wrote:
> On Tue, Oct 10, 2017 at 05:32:53PM +0300, Jarkko Sakkinen wrote:
> > diff --git a/drivers/platform/x86/intel_sgx/sgx_main.c b/drivers/platform/x86/intel_sgx/sgx_main.c
> > new file mode 100644
> > index 000000000000..2ad2dc88edff
> > --- /dev/null
> > +++ b/drivers/platform/x86/intel_sgx/sgx_main.c
> >
> > +static dev_t sgx_devt;
> > +
> > +static void sgx_dev_release(struct device *dev)
> > +{
> > +	struct sgx_context *ctx = container_of(dev, struct sgx_context, dev);
> > +	kfree(ctx);
> > +}
> > +
> > +static struct sgx_context *sgx_ctx_alloc(struct device *parent)
> > +{
> > +	struct sgx_context *ctx;
> > +
> > +	ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
> > +	if (!ctx)
> > +		return ERR_PTR(-ENOMEM);
> > +
> > +	device_initialize(&ctx->dev);
> > +
> > +	ctx->dev.bus = &sgx_subsys;
> > +	ctx->dev.parent = parent;
> > +	ctx->dev.devt = MKDEV(MAJOR(sgx_devt), 0);
> > +	ctx->dev.release = sgx_dev_release;
> > +
> > +	dev_set_name(&ctx->dev, "sgx");
> 
> /dev/sgx is created with 0600 permissions, does access to SGX really
> need to be restricted to root by default?

I personally am just a fan of whitelisting. It's only matter of a udev
rule.

/Jarkko

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [intel-sgx-kernel-dev] [PATCH RFC v3 07/12] intel_sgx: driver for Intel Software Guard Extensions
  2017-10-10 18:26   ` Sean Christopherson
@ 2017-10-13 19:58     ` Jarkko Sakkinen
  2017-10-13 20:02       ` Jarkko Sakkinen
  0 siblings, 1 reply; 40+ messages in thread
From: Jarkko Sakkinen @ 2017-10-13 19:58 UTC (permalink / raw)
  To: Sean Christopherson; +Cc: intel-sgx-kernel-dev, platform-driver-x86

On Tue, Oct 10, 2017 at 11:26:06AM -0700, Sean Christopherson wrote:
> On Tue, Oct 10, 2017 at 05:32:53PM +0300, Jarkko Sakkinen wrote:
> > diff --git a/drivers/platform/x86/intel_sgx/sgx_encl.c b/drivers/platform/x86/intel_sgx/sgx_encl.c
> > new file mode 100644
> > index 000000000000..aa0deed08cee
> > --- /dev/null
> > +++ b/drivers/platform/x86/intel_sgx/sgx_encl.c
> > @@ -0,0 +1,989 @@
> >
> > +/**
> > + * sgx_encl_find - find an enclave
> > + * @mm:		mm struct of the current process
> > + * @addr:	address in the ELRANGE
> > + * @created	is the enclave already created?
> > + * @vma:	the resulting VMA
> > + *
> > + * Finds an enclave identified by the given address. Gives back the VMA, that is
> > + * part of the enclave, located in that address.
> > + *
> > + * Return:
> > + * 0 on success,
> > + * -EINVAL if not found,
> > + */
> > +int sgx_encl_find(struct mm_struct *mm, unsigned long addr, bool created,
> > +		  struct vm_area_struct **vma)
> > +{
> > +	struct vm_area_struct *result;
> > +	struct sgx_encl *encl;
> > +
> > +	result = find_vma(mm, addr);
> > +	if (!result || result->vm_ops != &sgx_vm_ops || addr < result->vm_start)
> > +		return -EINVAL;
> > +
> > +	encl = result->vm_private_data;
> > +	if (created) {
> > +		if (!encl)
> > +			return -EINVAL;
> > +	} else {
> > +		if (encl)
> > +			return -EINVAL;
> > +	}
> 
> What about removing @created and returning -ENOENT (or -ENXIO?) if 
> result->vm_private_data is NULL?  Removing @created will eliminate
> any potential confusion for the common case of @created=true.  For
> @created=false, which should be limited to sgx_encl_create, I think
> that explicitly checking for "ret != -ENOENT" is more intuitive
> than checking whether or not sgx_encl_find succeeded, e.g. I knew
> the intent of the check in sgx_encl_create ahead of time and I still
> had to walk through sgx_encl_find to verify the behavior.

Would make sense. Thank you.

/Jarkko

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [intel-sgx-kernel-dev] [PATCH RFC v3 07/12] intel_sgx: driver for Intel Software Guard Extensions
  2017-10-13 19:58     ` Jarkko Sakkinen
@ 2017-10-13 20:02       ` Jarkko Sakkinen
  2017-10-13 20:08         ` Jarkko Sakkinen
  0 siblings, 1 reply; 40+ messages in thread
From: Jarkko Sakkinen @ 2017-10-13 20:02 UTC (permalink / raw)
  To: Sean Christopherson; +Cc: intel-sgx-kernel-dev, platform-driver-x86

On Fri, Oct 13, 2017 at 10:58:49PM +0300, Jarkko Sakkinen wrote:
> On Tue, Oct 10, 2017 at 11:26:06AM -0700, Sean Christopherson wrote:
> > On Tue, Oct 10, 2017 at 05:32:53PM +0300, Jarkko Sakkinen wrote:
> > > diff --git a/drivers/platform/x86/intel_sgx/sgx_encl.c b/drivers/platform/x86/intel_sgx/sgx_encl.c
> > > new file mode 100644
> > > index 000000000000..aa0deed08cee
> > > --- /dev/null
> > > +++ b/drivers/platform/x86/intel_sgx/sgx_encl.c
> > > @@ -0,0 +1,989 @@
> > >
> > > +/**
> > > + * sgx_encl_find - find an enclave
> > > + * @mm:		mm struct of the current process
> > > + * @addr:	address in the ELRANGE
> > > + * @created	is the enclave already created?
> > > + * @vma:	the resulting VMA
> > > + *
> > > + * Finds an enclave identified by the given address. Gives back the VMA, that is
> > > + * part of the enclave, located in that address.
> > > + *
> > > + * Return:
> > > + * 0 on success,
> > > + * -EINVAL if not found,
> > > + */
> > > +int sgx_encl_find(struct mm_struct *mm, unsigned long addr, bool created,
> > > +		  struct vm_area_struct **vma)
> > > +{
> > > +	struct vm_area_struct *result;
> > > +	struct sgx_encl *encl;
> > > +
> > > +	result = find_vma(mm, addr);
> > > +	if (!result || result->vm_ops != &sgx_vm_ops || addr < result->vm_start)
> > > +		return -EINVAL;
> > > +
> > > +	encl = result->vm_private_data;
> > > +	if (created) {
> > > +		if (!encl)
> > > +			return -EINVAL;
> > > +	} else {
> > > +		if (encl)
> > > +			return -EINVAL;
> > > +	}
> > 
> > What about removing @created and returning -ENOENT (or -ENXIO?) if 
> > result->vm_private_data is NULL?  Removing @created will eliminate
> > any potential confusion for the common case of @created=true.  For
> > @created=false, which should be limited to sgx_encl_create, I think
> > that explicitly checking for "ret != -ENOENT" is more intuitive
> > than checking whether or not sgx_encl_find succeeded, e.g. I knew
> > the intent of the check in sgx_encl_create ahead of time and I still
> > had to walk through sgx_encl_find to verify the behavior.
> 
> Would make sense. Thank you.
> 
> /Jarkko

And in the case of ioctls (sgx_encl_get()) it would probably make sense
to deliver -ENOENT back to the user space instead of -EINVAL, wouldn't it?

/Jarkko

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [intel-sgx-kernel-dev] [PATCH RFC v3 07/12] intel_sgx: driver for Intel Software Guard Extensions
  2017-10-13 20:02       ` Jarkko Sakkinen
@ 2017-10-13 20:08         ` Jarkko Sakkinen
  2017-10-13 20:13           ` Jarkko Sakkinen
  0 siblings, 1 reply; 40+ messages in thread
From: Jarkko Sakkinen @ 2017-10-13 20:08 UTC (permalink / raw)
  To: Sean Christopherson; +Cc: intel-sgx-kernel-dev, platform-driver-x86

On Fri, Oct 13, 2017 at 11:02:53PM +0300, Jarkko Sakkinen wrote:
> On Fri, Oct 13, 2017 at 10:58:49PM +0300, Jarkko Sakkinen wrote:
> > On Tue, Oct 10, 2017 at 11:26:06AM -0700, Sean Christopherson wrote:
> > > On Tue, Oct 10, 2017 at 05:32:53PM +0300, Jarkko Sakkinen wrote:
> > > > diff --git a/drivers/platform/x86/intel_sgx/sgx_encl.c b/drivers/platform/x86/intel_sgx/sgx_encl.c
> > > > new file mode 100644
> > > > index 000000000000..aa0deed08cee
> > > > --- /dev/null
> > > > +++ b/drivers/platform/x86/intel_sgx/sgx_encl.c
> > > > @@ -0,0 +1,989 @@
> > > >
> > > > +/**
> > > > + * sgx_encl_find - find an enclave
> > > > + * @mm:		mm struct of the current process
> > > > + * @addr:	address in the ELRANGE
> > > > + * @created	is the enclave already created?
> > > > + * @vma:	the resulting VMA
> > > > + *
> > > > + * Finds an enclave identified by the given address. Gives back the VMA, that is
> > > > + * part of the enclave, located in that address.
> > > > + *
> > > > + * Return:
> > > > + * 0 on success,
> > > > + * -EINVAL if not found,
> > > > + */
> > > > +int sgx_encl_find(struct mm_struct *mm, unsigned long addr, bool created,
> > > > +		  struct vm_area_struct **vma)
> > > > +{
> > > > +	struct vm_area_struct *result;
> > > > +	struct sgx_encl *encl;
> > > > +
> > > > +	result = find_vma(mm, addr);
> > > > +	if (!result || result->vm_ops != &sgx_vm_ops || addr < result->vm_start)
> > > > +		return -EINVAL;
> > > > +
> > > > +	encl = result->vm_private_data;
> > > > +	if (created) {
> > > > +		if (!encl)
> > > > +			return -EINVAL;
> > > > +	} else {
> > > > +		if (encl)
> > > > +			return -EINVAL;
> > > > +	}
> > > 
> > > What about removing @created and returning -ENOENT (or -ENXIO?) if 
> > > result->vm_private_data is NULL?  Removing @created will eliminate
> > > any potential confusion for the common case of @created=true.  For
> > > @created=false, which should be limited to sgx_encl_create, I think
> > > that explicitly checking for "ret != -ENOENT" is more intuitive
> > > than checking whether or not sgx_encl_find succeeded, e.g. I knew
> > > the intent of the check in sgx_encl_create ahead of time and I still
> > > had to walk through sgx_encl_find to verify the behavior.
> > 
> > Would make sense. Thank you.
> > 
> > /Jarkko
> 
> And in the case of ioctls (sgx_encl_get()) it would probably make sense
> to deliver -ENOENT back to the user space instead of -EINVAL, wouldn't it?
> 
> /Jarkko

Please ignore this response! :-)

/Jarkko

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [intel-sgx-kernel-dev] [PATCH RFC v3 07/12] intel_sgx: driver for Intel Software Guard Extensions
  2017-10-13 20:08         ` Jarkko Sakkinen
@ 2017-10-13 20:13           ` Jarkko Sakkinen
  0 siblings, 0 replies; 40+ messages in thread
From: Jarkko Sakkinen @ 2017-10-13 20:13 UTC (permalink / raw)
  To: Sean Christopherson; +Cc: intel-sgx-kernel-dev, platform-driver-x86

On Fri, Oct 13, 2017 at 11:08:24PM +0300, Jarkko Sakkinen wrote:
> On Fri, Oct 13, 2017 at 11:02:53PM +0300, Jarkko Sakkinen wrote:
> > On Fri, Oct 13, 2017 at 10:58:49PM +0300, Jarkko Sakkinen wrote:
> > > On Tue, Oct 10, 2017 at 11:26:06AM -0700, Sean Christopherson wrote:
> > > > On Tue, Oct 10, 2017 at 05:32:53PM +0300, Jarkko Sakkinen wrote:
> > > > > diff --git a/drivers/platform/x86/intel_sgx/sgx_encl.c b/drivers/platform/x86/intel_sgx/sgx_encl.c
> > > > > new file mode 100644
> > > > > index 000000000000..aa0deed08cee
> > > > > --- /dev/null
> > > > > +++ b/drivers/platform/x86/intel_sgx/sgx_encl.c
> > > > > @@ -0,0 +1,989 @@
> > > > >
> > > > > +/**
> > > > > + * sgx_encl_find - find an enclave
> > > > > + * @mm:		mm struct of the current process
> > > > > + * @addr:	address in the ELRANGE
> > > > > + * @created	is the enclave already created?
> > > > > + * @vma:	the resulting VMA
> > > > > + *
> > > > > + * Finds an enclave identified by the given address. Gives back the VMA, that is
> > > > > + * part of the enclave, located in that address.
> > > > > + *
> > > > > + * Return:
> > > > > + * 0 on success,
> > > > > + * -EINVAL if not found,
> > > > > + */
> > > > > +int sgx_encl_find(struct mm_struct *mm, unsigned long addr, bool created,
> > > > > +		  struct vm_area_struct **vma)
> > > > > +{
> > > > > +	struct vm_area_struct *result;
> > > > > +	struct sgx_encl *encl;
> > > > > +
> > > > > +	result = find_vma(mm, addr);
> > > > > +	if (!result || result->vm_ops != &sgx_vm_ops || addr < result->vm_start)
> > > > > +		return -EINVAL;
> > > > > +
> > > > > +	encl = result->vm_private_data;
> > > > > +	if (created) {
> > > > > +		if (!encl)
> > > > > +			return -EINVAL;
> > > > > +	} else {
> > > > > +		if (encl)
> > > > > +			return -EINVAL;
> > > > > +	}
> > > > 
> > > > What about removing @created and returning -ENOENT (or -ENXIO?) if 
> > > > result->vm_private_data is NULL?  Removing @created will eliminate
> > > > any potential confusion for the common case of @created=true.  For
> > > > @created=false, which should be limited to sgx_encl_create, I think
> > > > that explicitly checking for "ret != -ENOENT" is more intuitive
> > > > than checking whether or not sgx_encl_find succeeded, e.g. I knew
> > > > the intent of the check in sgx_encl_create ahead of time and I still
> > > > had to walk through sgx_encl_find to verify the behavior.
> > > 
> > > Would make sense. Thank you.
> > > 
> > > /Jarkko
> > 
> > And in the case of ioctls (sgx_encl_get()) it would probably make sense
> > to deliver -ENOENT back to the user space instead of -EINVAL, wouldn't it?
> > 
> > /Jarkko
> 
> Please ignore this response! :-)
> 
> /Jarkko

Or actually why not. Does not harm to tell user space that it is an
enclave VMA but not yet created.

/Jarkko

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [intel-sgx-kernel-dev] [PATCH RFC v3 07/12] intel_sgx: driver for Intel Software Guard Extensions
       [not found] ` <20171010143258.21623-8-jarkko.sakkinen@linux.intel.com>
                     ` (2 preceding siblings ...)
  2017-10-12 16:48   ` Sean Christopherson
@ 2017-11-02 19:48   ` Sean Christopherson
  2017-11-06  7:23     ` Jarkko Sakkinen
  2017-11-02 20:10   ` Sean Christopherson
  2017-11-06 15:54   ` Dave Hansen
  5 siblings, 1 reply; 40+ messages in thread
From: Sean Christopherson @ 2017-11-02 19:48 UTC (permalink / raw)
  To: Jarkko Sakkinen, intel-sgx-kernel-dev; +Cc: platform-driver-x86

On Tue, 2017-10-10 at 17:32 +0300, Jarkko Sakkinen wrote:
> +static int __init sgx_drv_init(void)
> +{
> +	int ret;
> +
> +	ret = sgx_drv_subsys_init();

The return value of sgx_drv_subsys_init is being ignored.

> +
> +	ret = platform_driver_register(&sgx_drv);
> +	if (ret)
> +		sgx_drv_subsys_exit();
> +
> +	return ret;
> +}
> +module_init(sgx_drv_init);
> +
> +static void __exit sgx_drv_exit(void)
> +{
> +	platform_driver_unregister(&sgx_drv);
> +	sgx_drv_subsys_exit();
> +}
> +module_exit(sgx_drv_exit);

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [intel-sgx-kernel-dev] [PATCH RFC v3 07/12] intel_sgx: driver for Intel Software Guard Extensions
       [not found] ` <20171010143258.21623-8-jarkko.sakkinen@linux.intel.com>
                     ` (3 preceding siblings ...)
  2017-11-02 19:48   ` Sean Christopherson
@ 2017-11-02 20:10   ` Sean Christopherson
  2017-11-06 11:08     ` Jarkko Sakkinen
  2017-11-06 11:39     ` Jarkko Sakkinen
  2017-11-06 15:54   ` Dave Hansen
  5 siblings, 2 replies; 40+ messages in thread
From: Sean Christopherson @ 2017-11-02 20:10 UTC (permalink / raw)
  To: Jarkko Sakkinen, intel-sgx-kernel-dev; +Cc: platform-driver-x86

On Tue, 2017-10-10 at 17:32 +0300, Jarkko Sakkinen wrote:
> +static int sgx_dev_init(struct device *parent, bool locked_msrs)
> +{
> +	struct sgx_context *sgx_dev;
> +	unsigned int eax, ebx, ecx, edx;
> +	unsigned long pa;
> +	unsigned long size;
> +	int ret;
> +	int i;
> +
> +	pr_info("intel_sgx: " DRV_DESCRIPTION " v" DRV_VERSION "\n");
> +
> +	sgx_dev = sgxm_ctx_alloc(parent);
> +
> +	sgx_locked_msrs = locked_msrs;
> +
> +	cpuid_count(SGX_CPUID, SGX_CPUID_CAPABILITIES, &eax, &ebx, &ecx,
> &edx);
> +	/* Only allow misc bits supported by the driver. */
> +	sgx_misc_reserved = ~ebx | SGX_MISC_RESERVED_MASK;
> +#ifdef CONFIG_X86_64
> +	sgx_encl_size_max_64 = 1ULL << ((edx >> 8) & 0xFF);
> +#endif
> +	sgx_encl_size_max_32 = 1ULL << (edx & 0xFF);
> +
> +	if (boot_cpu_has(X86_FEATURE_OSXSAVE)) {
> +		cpuid_count(SGX_CPUID, SGX_CPUID_ATTRIBUTES, &eax, &ebx,
> &ecx,
> +			    &edx);
> +		sgx_xfrm_mask = (((u64)edx) << 32) + (u64)ecx;
> +
> +		for (i = 2; i < 64; i++) {
> +			cpuid_count(0x0D, i, &eax, &ebx, &ecx, &edx);
> +			if ((1 << i) & sgx_xfrm_mask)
> +				sgx_xsave_size_tbl[i] = eax + ebx;
> +		}
> +	}
> +
> +	for (i = 0; i < SGX_MAX_EPC_BANKS; i++) {
> +		cpuid_count(SGX_CPUID, i + SGX_CPUID_EPC_BANKS, &eax, &ebx,
> +			    &ecx, &edx);
> +		if (!(eax & 0xf))
> +			break;
> +
> +		pa = ((u64)(ebx & 0xfffff) << 32) + (u64)(eax & 0xfffff000);
> +		size = ((u64)(edx & 0xfffff) << 32) + (u64)(ecx &
> 0xfffff000);
> +
> +		dev_info(parent, "EPC bank 0x%lx-0x%lx\n", pa, pa + size);
> +
> +		sgx_epc_banks[i].pa = pa;
> +		sgx_epc_banks[i].size = size;
> +	}
> +
> +	sgx_nr_epc_banks = i;
> +
> +	for (i = 0; i < sgx_nr_epc_banks; i++) {
> +#ifdef CONFIG_X86_64
> +		sgx_epc_banks[i].va = (unsigned long)
> +			ioremap_cache(sgx_epc_banks[i].pa,
> +				      sgx_epc_banks[i].size);
> +		if (!sgx_epc_banks[i].va) {
> +			sgx_nr_epc_banks = i;
> +			ret = -ENOMEM;
> +			goto out_iounmap;
> +		}
> +#endif
> +		ret = sgx_add_epc_bank(sgx_epc_banks[i].pa,
> +				       sgx_epc_banks[i].size, i);
> +		if (ret) {
> +			sgx_nr_epc_banks = i + 1;
> +			goto out_iounmap;
> +		}
> +	}
> +
> +	ret = sgx_page_cache_init();
> +	if (ret)
> +		goto out_iounmap;
> +
> +	sgx_add_page_wq = alloc_workqueue("intel_sgx-add-page-wq",
> +					  WQ_UNBOUND | WQ_FREEZABLE, 1);
> +	if (!sgx_add_page_wq) {
> +		pr_err("intel_sgx: alloc_workqueue() failed\n");
> +		ret = -ENOMEM;
> +		goto out_iounmap;
> +	}
> +
> +	ret = cdev_device_add(&sgx_dev->cdev, &sgx_dev->dev);
> +	if (ret)
> +		goto out_workqueue;
> +
> +	return 0;
> +out_workqueue:
> +	destroy_workqueue(sgx_add_page_wq);
> +out_iounmap:

sgx_page_cache_teardown() should be called here, else ksgxswapd and the list of
EPC pages will leak.

> +#ifdef CONFIG_X86_64
> +	for (i = 0; i < sgx_nr_epc_banks; i++)
> +		iounmap((void *)sgx_epc_banks[i].va);
> +#endif
> +	return ret;
> +}

... 

> +int sgx_add_epc_bank(resource_size_t start, unsigned long size, int bank)
> +{
> +	unsigned long i;
> +	struct sgx_epc_page *new_epc_page, *entry;
> +	struct list_head *parser, *temp;
> +
> +	for (i = 0; i < size; i += PAGE_SIZE) {
> +		new_epc_page = kzalloc(sizeof(*new_epc_page), GFP_KERNEL);
> +		if (!new_epc_page)
> +			goto err_freelist;
> +		new_epc_page->pa = (start + i) | bank;
> +
> +		spin_lock(&sgx_free_list_lock);
> +		list_add_tail(&new_epc_page->list, &sgx_free_list);
> +		sgx_nr_total_epc_pages++;
> +		sgx_nr_free_pages++;
> +		spin_unlock(&sgx_free_list_lock);
> +	}
> +
> +	return 0;
> +err_freelist:
> +	list_for_each_safe(parser, temp, &sgx_free_list) {
> +		spin_lock(&sgx_free_list_lock);
> +		entry = list_entry(parser, struct sgx_epc_page, list);
> +		list_del(&entry->list);
> +		spin_unlock(&sgx_free_list_lock);
> +		kfree(entry);
> +	}
> +	return -ENOMEM;
> +}

Freeing the entire list on failure does not seem like the appropriate behavior
for this helper func, e.g. the list should be purged by sgx_page_cache_teardown.
Buffering the new pages into a local list and only splicing said list into the
global list upon success is more inline with what I would expect from a helper
func, and also only requires a single lock/unlock.

diff --git drivers/platform/x86/intel_sgx/sgx_page_cache.c
drivers/platform/x86/intel_sgx/sgx_page_cache.c
index f8883d24692a..38496e6296f1 100644
--- drivers/platform/x86/intel_sgx/sgx_page_cache.c
+++ drivers/platform/x86/intel_sgx/sgx_page_cache.c
@@ -397,7 +397,8 @@ int sgx_add_epc_bank(resource_size_t start, unsigned long
size, int bank)
 {
        unsigned long i;
        struct sgx_epc_page *new_epc_page, *entry;
-       struct list_head *parser, *temp;
+       unsigned int nr_pages = 0;
+       LIST_HEAD(epc_pages);
 
        for (i = 0; i < size; i += PAGE_SIZE) {
                new_epc_page = kzalloc(sizeof(*new_epc_page), GFP_KERNEL);
@@ -405,22 +406,19 @@ int sgx_add_epc_bank(resource_size_t start, unsigned long
size, int bank)
                        goto err_freelist;
                new_epc_page->pa = (start + i) | bank;
 
-               spin_lock(&sgx_free_list_lock);
-               list_add_tail(&new_epc_page->list, &sgx_free_list);
-               sgx_nr_total_epc_pages++;
-               sgx_nr_free_pages++;
-               spin_unlock(&sgx_free_list_lock);
+               list_add_tail(&new_epc_page->list, &epc_pages);
+               nr_pages++;
        }
 
+       spin_lock(&sgx_free_list_lock);
+       list_splice_tail(&epc_pages, &sgx_free_list);
+       sgx_nr_total_epc_pages += nr_pages;
+       sgx_nr_free_pages += nr_pages;
+       spin_unlock(&sgx_free_list_lock);
        return 0;
 err_freelist:
-       list_for_each_safe(parser, temp, &sgx_free_list) {
-               spin_lock(&sgx_free_list_lock);
-               entry = list_entry(parser, struct sgx_epc_page, list);
-               list_del(&entry->list);
-               spin_unlock(&sgx_free_list_lock);
+       list_for_each_entry(entry, &sgx_free_list, list)
                kfree(entry);
-       }
        return -ENOMEM;
 }

^ permalink raw reply related	[flat|nested] 40+ messages in thread

* Re: [intel-sgx-kernel-dev] [PATCH RFC v3 07/12] intel_sgx: driver for Intel Software Guard Extensions
  2017-11-02 19:48   ` Sean Christopherson
@ 2017-11-06  7:23     ` Jarkko Sakkinen
  0 siblings, 0 replies; 40+ messages in thread
From: Jarkko Sakkinen @ 2017-11-06  7:23 UTC (permalink / raw)
  To: Sean Christopherson; +Cc: intel-sgx-kernel-dev, platform-driver-x86

On Thu, Nov 02, 2017 at 12:48:35PM -0700, Sean Christopherson wrote:
> On Tue, 2017-10-10 at 17:32 +0300, Jarkko Sakkinen wrote:
> > +static int __init sgx_drv_init(void)
> > +{
> > +	int ret;
> > +
> > +	ret = sgx_drv_subsys_init();
> 
> The return value of sgx_drv_subsys_init is being ignored.
> 
> > +
> > +	ret = platform_driver_register(&sgx_drv);
> > +	if (ret)
> > +		sgx_drv_subsys_exit();
> > +
> > +	return ret;
> > +}
> > +module_init(sgx_drv_init);
> > +
> > +static void __exit sgx_drv_exit(void)
> > +{
> > +	platform_driver_unregister(&sgx_drv);
> > +	sgx_drv_subsys_exit();
> > +}
> > +module_exit(sgx_drv_exit);

Holds still for v4. the latest version under review. Thanks.

/Jarkko

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [intel-sgx-kernel-dev] [PATCH RFC v3 07/12] intel_sgx: driver for Intel Software Guard Extensions
  2017-11-02 20:10   ` Sean Christopherson
@ 2017-11-06 11:08     ` Jarkko Sakkinen
  2017-11-06 11:33       ` Jarkko Sakkinen
  2017-11-06 11:39     ` Jarkko Sakkinen
  1 sibling, 1 reply; 40+ messages in thread
From: Jarkko Sakkinen @ 2017-11-06 11:08 UTC (permalink / raw)
  To: Sean Christopherson; +Cc: intel-sgx-kernel-dev, platform-driver-x86

On Thu, Nov 02, 2017 at 01:10:29PM -0700, Sean Christopherson wrote:
> On Tue, 2017-10-10 at 17:32 +0300, Jarkko Sakkinen wrote:
> > +static int sgx_dev_init(struct device *parent, bool locked_msrs)
> > +{
> > +	struct sgx_context *sgx_dev;
> > +	unsigned int eax, ebx, ecx, edx;
> > +	unsigned long pa;
> > +	unsigned long size;
> > +	int ret;
> > +	int i;
> > +
> > +	pr_info("intel_sgx: " DRV_DESCRIPTION " v" DRV_VERSION "\n");
> > +
> > +	sgx_dev = sgxm_ctx_alloc(parent);
> > +
> > +	sgx_locked_msrs = locked_msrs;
> > +
> > +	cpuid_count(SGX_CPUID, SGX_CPUID_CAPABILITIES, &eax, &ebx, &ecx,
> > &edx);
> > +	/* Only allow misc bits supported by the driver. */
> > +	sgx_misc_reserved = ~ebx | SGX_MISC_RESERVED_MASK;
> > +#ifdef CONFIG_X86_64
> > +	sgx_encl_size_max_64 = 1ULL << ((edx >> 8) & 0xFF);
> > +#endif
> > +	sgx_encl_size_max_32 = 1ULL << (edx & 0xFF);
> > +
> > +	if (boot_cpu_has(X86_FEATURE_OSXSAVE)) {
> > +		cpuid_count(SGX_CPUID, SGX_CPUID_ATTRIBUTES, &eax, &ebx,
> > &ecx,
> > +			    &edx);
> > +		sgx_xfrm_mask = (((u64)edx) << 32) + (u64)ecx;
> > +
> > +		for (i = 2; i < 64; i++) {
> > +			cpuid_count(0x0D, i, &eax, &ebx, &ecx, &edx);
> > +			if ((1 << i) & sgx_xfrm_mask)
> > +				sgx_xsave_size_tbl[i] = eax + ebx;
> > +		}
> > +	}
> > +
> > +	for (i = 0; i < SGX_MAX_EPC_BANKS; i++) {
> > +		cpuid_count(SGX_CPUID, i + SGX_CPUID_EPC_BANKS, &eax, &ebx,
> > +			    &ecx, &edx);
> > +		if (!(eax & 0xf))
> > +			break;
> > +
> > +		pa = ((u64)(ebx & 0xfffff) << 32) + (u64)(eax & 0xfffff000);
> > +		size = ((u64)(edx & 0xfffff) << 32) + (u64)(ecx &
> > 0xfffff000);
> > +
> > +		dev_info(parent, "EPC bank 0x%lx-0x%lx\n", pa, pa + size);
> > +
> > +		sgx_epc_banks[i].pa = pa;
> > +		sgx_epc_banks[i].size = size;
> > +	}
> > +
> > +	sgx_nr_epc_banks = i;
> > +
> > +	for (i = 0; i < sgx_nr_epc_banks; i++) {
> > +#ifdef CONFIG_X86_64
> > +		sgx_epc_banks[i].va = (unsigned long)
> > +			ioremap_cache(sgx_epc_banks[i].pa,
> > +				      sgx_epc_banks[i].size);
> > +		if (!sgx_epc_banks[i].va) {
> > +			sgx_nr_epc_banks = i;
> > +			ret = -ENOMEM;
> > +			goto out_iounmap;
> > +		}
> > +#endif
> > +		ret = sgx_add_epc_bank(sgx_epc_banks[i].pa,
> > +				       sgx_epc_banks[i].size, i);
> > +		if (ret) {
> > +			sgx_nr_epc_banks = i + 1;
> > +			goto out_iounmap;
> > +		}
> > +	}
> > +
> > +	ret = sgx_page_cache_init();
> > +	if (ret)
> > +		goto out_iounmap;
> > +
> > +	sgx_add_page_wq = alloc_workqueue("intel_sgx-add-page-wq",
> > +					  WQ_UNBOUND | WQ_FREEZABLE, 1);
> > +	if (!sgx_add_page_wq) {
> > +		pr_err("intel_sgx: alloc_workqueue() failed\n");
> > +		ret = -ENOMEM;
> > +		goto out_iounmap;
> > +	}
> > +
> > +	ret = cdev_device_add(&sgx_dev->cdev, &sgx_dev->dev);
> > +	if (ret)
> > +		goto out_workqueue;
> > +
> > +	return 0;
> > +out_workqueue:
> > +	destroy_workqueue(sgx_add_page_wq);
> > +out_iounmap:
> 
> sgx_page_cache_teardown() should be called here, else ksgxswapd and the list of
> EPC pages will leak.
> 

Thanks.

> > +#ifdef CONFIG_X86_64
> > +	for (i = 0; i < sgx_nr_epc_banks; i++)
> > +		iounmap((void *)sgx_epc_banks[i].va);
> > +#endif
> > +	return ret;
> > +}
> 
> ... 
> 
> > +int sgx_add_epc_bank(resource_size_t start, unsigned long size, int bank)
> > +{
> > +	unsigned long i;
> > +	struct sgx_epc_page *new_epc_page, *entry;
> > +	struct list_head *parser, *temp;
> > +
> > +	for (i = 0; i < size; i += PAGE_SIZE) {
> > +		new_epc_page = kzalloc(sizeof(*new_epc_page), GFP_KERNEL);
> > +		if (!new_epc_page)
> > +			goto err_freelist;
> > +		new_epc_page->pa = (start + i) | bank;
> > +
> > +		spin_lock(&sgx_free_list_lock);
> > +		list_add_tail(&new_epc_page->list, &sgx_free_list);
> > +		sgx_nr_total_epc_pages++;
> > +		sgx_nr_free_pages++;
> > +		spin_unlock(&sgx_free_list_lock);
> > +	}
> > +
> > +	return 0;
> > +err_freelist:
> > +	list_for_each_safe(parser, temp, &sgx_free_list) {
> > +		spin_lock(&sgx_free_list_lock);
> > +		entry = list_entry(parser, struct sgx_epc_page, list);
> > +		list_del(&entry->list);
> > +		spin_unlock(&sgx_free_list_lock);
> > +		kfree(entry);
> > +	}
> > +	return -ENOMEM;
> > +}
> 
> Freeing the entire list on failure does not seem like the appropriate behavior
> for this helper func, e.g. the list should be purged by sgx_page_cache_teardown.
> Buffering the new pages into a local list and only splicing said list into the
> global list upon success is more inline with what I would expect from a helper
> func, and also only requires a single lock/unlock.
> 
> diff --git drivers/platform/x86/intel_sgx/sgx_page_cache.c
> drivers/platform/x86/intel_sgx/sgx_page_cache.c
> index f8883d24692a..38496e6296f1 100644
> --- drivers/platform/x86/intel_sgx/sgx_page_cache.c
> +++ drivers/platform/x86/intel_sgx/sgx_page_cache.c
> @@ -397,7 +397,8 @@ int sgx_add_epc_bank(resource_size_t start, unsigned long
> size, int bank)
>  {
>         unsigned long i;
>         struct sgx_epc_page *new_epc_page, *entry;
> -       struct list_head *parser, *temp;
> +       LIST_HEAD(epc_pages);
>  
>         for (i = 0; i < size; i += PAGE_SIZE) {
>                 new_epc_page = kzalloc(sizeof(*new_epc_page), GFP_KERNEL);
> @@ -405,22 +406,19 @@ int sgx_add_epc_bank(resource_size_t start, unsigned long
> size, int bank)
>                         goto err_freelist;
>                 new_epc_page->pa = (start + i) | bank;
>  
> -               spin_lock(&sgx_free_list_lock);
> -               list_add_tail(&new_epc_page->list, &sgx_free_list);
> -               sgx_nr_total_epc_pages++;
> -               sgx_nr_free_pages++;
> -               spin_unlock(&sgx_free_list_lock);
> +               list_add_tail(&new_epc_page->list, &epc_pages);
> +               nr_pages++;
>         }
>  
> +       spin_lock(&sgx_free_list_lock);
> +       list_splice_tail(&epc_pages, &sgx_free_list);
> +       sgx_nr_total_epc_pages += nr_pages;
> +       sgx_nr_free_pages += nr_pages;
> +       spin_unlock(&sgx_free_list_lock);
>         return 0;
>  err_freelist:
> -       list_for_each_safe(parser, temp, &sgx_free_list) {
> -               spin_lock(&sgx_free_list_lock);
> -               entry = list_entry(parser, struct sgx_epc_page, list);
> -               list_del(&entry->list);
> -               spin_unlock(&sgx_free_list_lock);
> +       list_for_each_entry(entry, &sgx_free_list, list)
>                 kfree(entry);
> -       }
>         return -ENOMEM;
>  }

This makes sense to me and I think it makes also sense to move bunch of
stuff from sgx_dev_init() to sgx_page_cache_init().

/Jarkko

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [intel-sgx-kernel-dev] [PATCH RFC v3 07/12] intel_sgx: driver for Intel Software Guard Extensions
  2017-11-06 11:08     ` Jarkko Sakkinen
@ 2017-11-06 11:33       ` Jarkko Sakkinen
  2017-11-06 14:56         ` Sean Christopherson
  0 siblings, 1 reply; 40+ messages in thread
From: Jarkko Sakkinen @ 2017-11-06 11:33 UTC (permalink / raw)
  To: Sean Christopherson; +Cc: intel-sgx-kernel-dev, platform-driver-x86

On Mon, Nov 06, 2017 at 01:08:22PM +0200, Jarkko Sakkinen wrote:
> On Thu, Nov 02, 2017 at 01:10:29PM -0700, Sean Christopherson wrote:
> > On Tue, 2017-10-10 at 17:32 +0300, Jarkko Sakkinen wrote:
> > > +static int sgx_dev_init(struct device *parent, bool locked_msrs)
> > > +{
> > > +	struct sgx_context *sgx_dev;
> > > +	unsigned int eax, ebx, ecx, edx;
> > > +	unsigned long pa;
> > > +	unsigned long size;
> > > +	int ret;
> > > +	int i;
> > > +
> > > +	pr_info("intel_sgx: " DRV_DESCRIPTION " v" DRV_VERSION "\n");
> > > +
> > > +	sgx_dev = sgxm_ctx_alloc(parent);
> > > +
> > > +	sgx_locked_msrs = locked_msrs;
> > > +
> > > +	cpuid_count(SGX_CPUID, SGX_CPUID_CAPABILITIES, &eax, &ebx, &ecx,
> > > &edx);
> > > +	/* Only allow misc bits supported by the driver. */
> > > +	sgx_misc_reserved = ~ebx | SGX_MISC_RESERVED_MASK;
> > > +#ifdef CONFIG_X86_64
> > > +	sgx_encl_size_max_64 = 1ULL << ((edx >> 8) & 0xFF);
> > > +#endif
> > > +	sgx_encl_size_max_32 = 1ULL << (edx & 0xFF);
> > > +
> > > +	if (boot_cpu_has(X86_FEATURE_OSXSAVE)) {
> > > +		cpuid_count(SGX_CPUID, SGX_CPUID_ATTRIBUTES, &eax, &ebx,
> > > &ecx,
> > > +			    &edx);
> > > +		sgx_xfrm_mask = (((u64)edx) << 32) + (u64)ecx;
> > > +
> > > +		for (i = 2; i < 64; i++) {
> > > +			cpuid_count(0x0D, i, &eax, &ebx, &ecx, &edx);
> > > +			if ((1 << i) & sgx_xfrm_mask)
> > > +				sgx_xsave_size_tbl[i] = eax + ebx;
> > > +		}
> > > +	}
> > > +
> > > +	for (i = 0; i < SGX_MAX_EPC_BANKS; i++) {
> > > +		cpuid_count(SGX_CPUID, i + SGX_CPUID_EPC_BANKS, &eax, &ebx,
> > > +			    &ecx, &edx);
> > > +		if (!(eax & 0xf))
> > > +			break;
> > > +
> > > +		pa = ((u64)(ebx & 0xfffff) << 32) + (u64)(eax & 0xfffff000);
> > > +		size = ((u64)(edx & 0xfffff) << 32) + (u64)(ecx &
> > > 0xfffff000);
> > > +
> > > +		dev_info(parent, "EPC bank 0x%lx-0x%lx\n", pa, pa + size);
> > > +
> > > +		sgx_epc_banks[i].pa = pa;
> > > +		sgx_epc_banks[i].size = size;
> > > +	}
> > > +
> > > +	sgx_nr_epc_banks = i;
> > > +
> > > +	for (i = 0; i < sgx_nr_epc_banks; i++) {
> > > +#ifdef CONFIG_X86_64
> > > +		sgx_epc_banks[i].va = (unsigned long)
> > > +			ioremap_cache(sgx_epc_banks[i].pa,
> > > +				      sgx_epc_banks[i].size);
> > > +		if (!sgx_epc_banks[i].va) {
> > > +			sgx_nr_epc_banks = i;
> > > +			ret = -ENOMEM;
> > > +			goto out_iounmap;
> > > +		}
> > > +#endif
> > > +		ret = sgx_add_epc_bank(sgx_epc_banks[i].pa,
> > > +				       sgx_epc_banks[i].size, i);
> > > +		if (ret) {
> > > +			sgx_nr_epc_banks = i + 1;
> > > +			goto out_iounmap;
> > > +		}
> > > +	}
> > > +
> > > +	ret = sgx_page_cache_init();
> > > +	if (ret)
> > > +		goto out_iounmap;
> > > +
> > > +	sgx_add_page_wq = alloc_workqueue("intel_sgx-add-page-wq",
> > > +					  WQ_UNBOUND | WQ_FREEZABLE, 1);
> > > +	if (!sgx_add_page_wq) {
> > > +		pr_err("intel_sgx: alloc_workqueue() failed\n");
> > > +		ret = -ENOMEM;
> > > +		goto out_iounmap;
> > > +	}
> > > +
> > > +	ret = cdev_device_add(&sgx_dev->cdev, &sgx_dev->dev);
> > > +	if (ret)
> > > +		goto out_workqueue;
> > > +
> > > +	return 0;
> > > +out_workqueue:
> > > +	destroy_workqueue(sgx_add_page_wq);
> > > +out_iounmap:
> > 
> > sgx_page_cache_teardown() should be called here, else ksgxswapd and the list of
> > EPC pages will leak.
> > 
> 
> Thanks.
> 
> > > +#ifdef CONFIG_X86_64
> > > +	for (i = 0; i < sgx_nr_epc_banks; i++)
> > > +		iounmap((void *)sgx_epc_banks[i].va);
> > > +#endif
> > > +	return ret;
> > > +}
> > 
> > ... 
> > 
> > > +int sgx_add_epc_bank(resource_size_t start, unsigned long size, int bank)
> > > +{
> > > +	unsigned long i;
> > > +	struct sgx_epc_page *new_epc_page, *entry;
> > > +	struct list_head *parser, *temp;
> > > +
> > > +	for (i = 0; i < size; i += PAGE_SIZE) {
> > > +		new_epc_page = kzalloc(sizeof(*new_epc_page), GFP_KERNEL);
> > > +		if (!new_epc_page)
> > > +			goto err_freelist;
> > > +		new_epc_page->pa = (start + i) | bank;
> > > +
> > > +		spin_lock(&sgx_free_list_lock);
> > > +		list_add_tail(&new_epc_page->list, &sgx_free_list);
> > > +		sgx_nr_total_epc_pages++;
> > > +		sgx_nr_free_pages++;
> > > +		spin_unlock(&sgx_free_list_lock);
> > > +	}
> > > +
> > > +	return 0;
> > > +err_freelist:
> > > +	list_for_each_safe(parser, temp, &sgx_free_list) {
> > > +		spin_lock(&sgx_free_list_lock);
> > > +		entry = list_entry(parser, struct sgx_epc_page, list);
> > > +		list_del(&entry->list);
> > > +		spin_unlock(&sgx_free_list_lock);
> > > +		kfree(entry);
> > > +	}
> > > +	return -ENOMEM;
> > > +}
> > 
> > Freeing the entire list on failure does not seem like the appropriate behavior
> > for this helper func, e.g. the list should be purged by sgx_page_cache_teardown.
> > Buffering the new pages into a local list and only splicing said list into the
> > global list upon success is more inline with what I would expect from a helper
> > func, and also only requires a single lock/unlock.
> > 
> > diff --git drivers/platform/x86/intel_sgx/sgx_page_cache.c
> > drivers/platform/x86/intel_sgx/sgx_page_cache.c
> > index f8883d24692a..38496e6296f1 100644
> > --- drivers/platform/x86/intel_sgx/sgx_page_cache.c
> > +++ drivers/platform/x86/intel_sgx/sgx_page_cache.c
> > @@ -397,7 +397,8 @@ int sgx_add_epc_bank(resource_size_t start, unsigned long
> > size, int bank)
> >  {
> >         unsigned long i;
> >         struct sgx_epc_page *new_epc_page, *entry;
> > -       struct list_head *parser, *temp;
> > +       LIST_HEAD(epc_pages);
> >  
> >         for (i = 0; i < size; i += PAGE_SIZE) {
> >                 new_epc_page = kzalloc(sizeof(*new_epc_page), GFP_KERNEL);
> > @@ -405,22 +406,19 @@ int sgx_add_epc_bank(resource_size_t start, unsigned long
> > size, int bank)
> >                         goto err_freelist;
> >                 new_epc_page->pa = (start + i) | bank;
> >  
> > -               spin_lock(&sgx_free_list_lock);
> > -               list_add_tail(&new_epc_page->list, &sgx_free_list);
> > -               sgx_nr_total_epc_pages++;
> > -               sgx_nr_free_pages++;
> > -               spin_unlock(&sgx_free_list_lock);
> > +               list_add_tail(&new_epc_page->list, &epc_pages);
> > +               nr_pages++;
> >         }
> >  
> > +       spin_lock(&sgx_free_list_lock);
> > +       list_splice_tail(&epc_pages, &sgx_free_list);
> > +       sgx_nr_total_epc_pages += nr_pages;
> > +       sgx_nr_free_pages += nr_pages;
> > +       spin_unlock(&sgx_free_list_lock);
> >         return 0;
> >  err_freelist:
> > -       list_for_each_safe(parser, temp, &sgx_free_list) {
> > -               spin_lock(&sgx_free_list_lock);
> > -               entry = list_entry(parser, struct sgx_epc_page, list);
> > -               list_del(&entry->list);
> > -               spin_unlock(&sgx_free_list_lock);
> > +       list_for_each_entry(entry, &sgx_free_list, list)
> >                 kfree(entry);
> > -       }
> >         return -ENOMEM;
> >  }
> 
> This makes sense to me and I think it makes also sense to move bunch of
> stuff from sgx_dev_init() to sgx_page_cache_init().
> 
> /Jarkko

You can get away without nr_pages as you can get from i or am I
misobserving something?

/Jarkko

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [intel-sgx-kernel-dev] [PATCH RFC v3 07/12] intel_sgx: driver for Intel Software Guard Extensions
  2017-11-02 20:10   ` Sean Christopherson
  2017-11-06 11:08     ` Jarkko Sakkinen
@ 2017-11-06 11:39     ` Jarkko Sakkinen
  2017-11-06 14:54       ` Sean Christopherson
  1 sibling, 1 reply; 40+ messages in thread
From: Jarkko Sakkinen @ 2017-11-06 11:39 UTC (permalink / raw)
  To: Sean Christopherson; +Cc: intel-sgx-kernel-dev, platform-driver-x86

On Thu, Nov 02, 2017 at 01:10:29PM -0700, Sean Christopherson wrote:
> +       list_for_each_entry(entry, &sgx_free_list, list)
>                 kfree(entry);
> -       }

Shouldn't you iterate 'epc_pages' in the rollback now?

/Jarkko

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [intel-sgx-kernel-dev] [PATCH RFC v3 07/12] intel_sgx: driver for Intel Software Guard Extensions
  2017-11-06 11:39     ` Jarkko Sakkinen
@ 2017-11-06 14:54       ` Sean Christopherson
  2017-11-07 18:43         ` Jarkko Sakkinen
  0 siblings, 1 reply; 40+ messages in thread
From: Sean Christopherson @ 2017-11-06 14:54 UTC (permalink / raw)
  To: Jarkko Sakkinen; +Cc: intel-sgx-kernel-dev, platform-driver-x86

On Mon, 2017-11-06 at 13:39 +0200, Jarkko Sakkinen wrote:
> On Thu, Nov 02, 2017 at 01:10:29PM -0700, Sean Christopherson wrote:
> > 
> > +       list_for_each_entry(entry, &sgx_free_list, list)
> >                 kfree(entry);
> > -       }
> Shouldn't you iterate 'epc_pages' in the rollback now?

Yes, that's the intent, nice catch.

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [intel-sgx-kernel-dev] [PATCH RFC v3 07/12] intel_sgx: driver for Intel Software Guard Extensions
  2017-11-06 11:33       ` Jarkko Sakkinen
@ 2017-11-06 14:56         ` Sean Christopherson
  2017-11-08  6:25           ` Jarkko Sakkinen
  0 siblings, 1 reply; 40+ messages in thread
From: Sean Christopherson @ 2017-11-06 14:56 UTC (permalink / raw)
  To: Jarkko Sakkinen; +Cc: intel-sgx-kernel-dev, platform-driver-x86

On Mon, 2017-11-06 at 13:33 +0200, Jarkko Sakkinen wrote:
> On Mon, Nov 06, 2017 at 01:08:22PM +0200, Jarkko Sakkinen wrote:
> > 
> > On Thu, Nov 02, 2017 at 01:10:29PM -0700, Sean Christopherson wrote:
> > > 
> > > On Tue, 2017-10-10 at 17:32 +0300, Jarkko Sakkinen wrote:
> > > > 
> > > > +static int sgx_dev_init(struct device *parent, bool locked_msrs)
> > > > +{
> > > > +	struct sgx_context *sgx_dev;
> > > > +	unsigned int eax, ebx, ecx, edx;
> > > > +	unsigned long pa;
> > > > +	unsigned long size;
> > > > +	int ret;
> > > > +	int i;
> > > > +
> > > > +	pr_info("intel_sgx: " DRV_DESCRIPTION " v" DRV_VERSION "\n");
> > > > +
> > > > +	sgx_dev = sgxm_ctx_alloc(parent);
> > > > +
> > > > +	sgx_locked_msrs = locked_msrs;
> > > > +
> > > > +	cpuid_count(SGX_CPUID, SGX_CPUID_CAPABILITIES, &eax, &ebx,
> > > > &ecx,
> > > > &edx);
> > > > +	/* Only allow misc bits supported by the driver. */
> > > > +	sgx_misc_reserved = ~ebx | SGX_MISC_RESERVED_MASK;
> > > > +#ifdef CONFIG_X86_64
> > > > +	sgx_encl_size_max_64 = 1ULL << ((edx >> 8) & 0xFF);
> > > > +#endif
> > > > +	sgx_encl_size_max_32 = 1ULL << (edx & 0xFF);
> > > > +
> > > > +	if (boot_cpu_has(X86_FEATURE_OSXSAVE)) {
> > > > +		cpuid_count(SGX_CPUID, SGX_CPUID_ATTRIBUTES, &eax,
> > > > &ebx,
> > > > &ecx,
> > > > +			    &edx);
> > > > +		sgx_xfrm_mask = (((u64)edx) << 32) + (u64)ecx;
> > > > +
> > > > +		for (i = 2; i < 64; i++) {
> > > > +			cpuid_count(0x0D, i, &eax, &ebx, &ecx, &edx);
> > > > +			if ((1 << i) & sgx_xfrm_mask)
> > > > +				sgx_xsave_size_tbl[i] = eax + ebx;
> > > > +		}
> > > > +	}
> > > > +
> > > > +	for (i = 0; i < SGX_MAX_EPC_BANKS; i++) {
> > > > +		cpuid_count(SGX_CPUID, i + SGX_CPUID_EPC_BANKS, &eax,
> > > > &ebx,
> > > > +			    &ecx, &edx);
> > > > +		if (!(eax & 0xf))
> > > > +			break;
> > > > +
> > > > +		pa = ((u64)(ebx & 0xfffff) << 32) + (u64)(eax &
> > > > 0xfffff000);
> > > > +		size = ((u64)(edx & 0xfffff) << 32) + (u64)(ecx &
> > > > 0xfffff000);
> > > > +
> > > > +		dev_info(parent, "EPC bank 0x%lx-0x%lx\n", pa, pa +
> > > > size);
> > > > +
> > > > +		sgx_epc_banks[i].pa = pa;
> > > > +		sgx_epc_banks[i].size = size;
> > > > +	}
> > > > +
> > > > +	sgx_nr_epc_banks = i;
> > > > +
> > > > +	for (i = 0; i < sgx_nr_epc_banks; i++) {
> > > > +#ifdef CONFIG_X86_64
> > > > +		sgx_epc_banks[i].va = (unsigned long)
> > > > +			ioremap_cache(sgx_epc_banks[i].pa,
> > > > +				      sgx_epc_banks[i].size);
> > > > +		if (!sgx_epc_banks[i].va) {
> > > > +			sgx_nr_epc_banks = i;
> > > > +			ret = -ENOMEM;
> > > > +			goto out_iounmap;
> > > > +		}
> > > > +#endif
> > > > +		ret = sgx_add_epc_bank(sgx_epc_banks[i].pa,
> > > > +				       sgx_epc_banks[i].size, i);
> > > > +		if (ret) {
> > > > +			sgx_nr_epc_banks = i + 1;
> > > > +			goto out_iounmap;
> > > > +		}
> > > > +	}
> > > > +
> > > > +	ret = sgx_page_cache_init();
> > > > +	if (ret)
> > > > +		goto out_iounmap;
> > > > +
> > > > +	sgx_add_page_wq = alloc_workqueue("intel_sgx-add-page-wq",
> > > > +					  WQ_UNBOUND | WQ_FREEZABLE,
> > > > 1);
> > > > +	if (!sgx_add_page_wq) {
> > > > +		pr_err("intel_sgx: alloc_workqueue() failed\n");
> > > > +		ret = -ENOMEM;
> > > > +		goto out_iounmap;
> > > > +	}
> > > > +
> > > > +	ret = cdev_device_add(&sgx_dev->cdev, &sgx_dev->dev);
> > > > +	if (ret)
> > > > +		goto out_workqueue;
> > > > +
> > > > +	return 0;
> > > > +out_workqueue:
> > > > +	destroy_workqueue(sgx_add_page_wq);
> > > > +out_iounmap:
> > > sgx_page_cache_teardown() should be called here, else ksgxswapd and the
> > > list of
> > > EPC pages will leak.
> > > 
> > Thanks.
> > 
> > > 
> > > > 
> > > > +#ifdef CONFIG_X86_64
> > > > +	for (i = 0; i < sgx_nr_epc_banks; i++)
> > > > +		iounmap((void *)sgx_epc_banks[i].va);
> > > > +#endif
> > > > +	return ret;
> > > > +}
> > > ... 
> > > 
> > > > 
> > > > +int sgx_add_epc_bank(resource_size_t start, unsigned long size, int
> > > > bank)
> > > > +{
> > > > +	unsigned long i;
> > > > +	struct sgx_epc_page *new_epc_page, *entry;
> > > > +	struct list_head *parser, *temp;
> > > > +
> > > > +	for (i = 0; i < size; i += PAGE_SIZE) {
> > > > +		new_epc_page = kzalloc(sizeof(*new_epc_page),
> > > > GFP_KERNEL);
> > > > +		if (!new_epc_page)
> > > > +			goto err_freelist;
> > > > +		new_epc_page->pa = (start + i) | bank;
> > > > +
> > > > +		spin_lock(&sgx_free_list_lock);
> > > > +		list_add_tail(&new_epc_page->list, &sgx_free_list);
> > > > +		sgx_nr_total_epc_pages++;
> > > > +		sgx_nr_free_pages++;
> > > > +		spin_unlock(&sgx_free_list_lock);
> > > > +	}
> > > > +
> > > > +	return 0;
> > > > +err_freelist:
> > > > +	list_for_each_safe(parser, temp, &sgx_free_list) {
> > > > +		spin_lock(&sgx_free_list_lock);
> > > > +		entry = list_entry(parser, struct sgx_epc_page, list);
> > > > +		list_del(&entry->list);
> > > > +		spin_unlock(&sgx_free_list_lock);
> > > > +		kfree(entry);
> > > > +	}
> > > > +	return -ENOMEM;
> > > > +}
> > > Freeing the entire list on failure does not seem like the appropriate
> > > behavior
> > > for this helper func, e.g. the list should be purged by
> > > sgx_page_cache_teardown.
> > > Buffering the new pages into a local list and only splicing said list into
> > > the
> > > global list upon success is more inline with what I would expect from a
> > > helper
> > > func, and also only requires a single lock/unlock.
> > > 
> > > diff --git drivers/platform/x86/intel_sgx/sgx_page_cache.c
> > > drivers/platform/x86/intel_sgx/sgx_page_cache.c
> > > index f8883d24692a..38496e6296f1 100644
> > > --- drivers/platform/x86/intel_sgx/sgx_page_cache.c
> > > +++ drivers/platform/x86/intel_sgx/sgx_page_cache.c
> > > @@ -397,7 +397,8 @@ int sgx_add_epc_bank(resource_size_t start, unsigned
> > > long
> > > size, int bank)
> > >  {
> > >         unsigned long i;
> > >         struct sgx_epc_page *new_epc_page, *entry;
> > > -       struct list_head *parser, *temp;
> > > +       LIST_HEAD(epc_pages);
> > >  
> > >         for (i = 0; i < size; i += PAGE_SIZE) {
> > >                 new_epc_page = kzalloc(sizeof(*new_epc_page), GFP_KERNEL);
> > > @@ -405,22 +406,19 @@ int sgx_add_epc_bank(resource_size_t start, unsigned
> > > long
> > > size, int bank)
> > >                         goto err_freelist;
> > >                 new_epc_page->pa = (start + i) | bank;
> > >  
> > > -               spin_lock(&sgx_free_list_lock);
> > > -               list_add_tail(&new_epc_page->list, &sgx_free_list);
> > > -               sgx_nr_total_epc_pages++;
> > > -               sgx_nr_free_pages++;
> > > -               spin_unlock(&sgx_free_list_lock);
> > > +               list_add_tail(&new_epc_page->list, &epc_pages);
> > > +               nr_pages++;
> > >         }
> > >  
> > > +       spin_lock(&sgx_free_list_lock);
> > > +       list_splice_tail(&epc_pages, &sgx_free_list);
> > > +       sgx_nr_total_epc_pages += nr_pages;
> > > +       sgx_nr_free_pages += nr_pages;
> > > +       spin_unlock(&sgx_free_list_lock);
> > >         return 0;
> > >  err_freelist:
> > > -       list_for_each_safe(parser, temp, &sgx_free_list) {
> > > -               spin_lock(&sgx_free_list_lock);
> > > -               entry = list_entry(parser, struct sgx_epc_page, list);
> > > -               list_del(&entry->list);
> > > -               spin_unlock(&sgx_free_list_lock);
> > > +       list_for_each_entry(entry, &sgx_free_list, list)
> > >                 kfree(entry);
> > > -       }
> > >         return -ENOMEM;
> > >  }
> > This makes sense to me and I think it makes also sense to move bunch of
> > stuff from sgx_dev_init() to sgx_page_cache_init().
> > /Jarkko
> You can get away without nr_pages as you can get from i or am I
> misobserving something?

i is incremented by PAGE_SIZE.  I suppose you could do "+= i / PAGE_SIZE", but I
would opt for clarity in this case.

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [intel-sgx-kernel-dev] [PATCH RFC v3 07/12] intel_sgx: driver for Intel Software Guard Extensions
       [not found] ` <20171010143258.21623-8-jarkko.sakkinen@linux.intel.com>
                     ` (4 preceding siblings ...)
  2017-11-02 20:10   ` Sean Christopherson
@ 2017-11-06 15:54   ` Dave Hansen
  2017-11-07 18:47     ` Jarkko Sakkinen
  5 siblings, 1 reply; 40+ messages in thread
From: Dave Hansen @ 2017-11-06 15:54 UTC (permalink / raw)
  To: Jarkko Sakkinen, intel-sgx-kernel-dev; +Cc: platform-driver-x86

On 10/10/2017 07:32 AM, Jarkko Sakkinen wrote:
> +static LIST_HEAD(sgx_free_list);
> +static DEFINE_SPINLOCK(sgx_free_list_lock);

Is this a global list?  Will this be a scalability problem on larger
systems?

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [intel-sgx-kernel-dev] [PATCH RFC v3 07/12] intel_sgx: driver for Intel Software Guard Extensions
  2017-11-06 14:54       ` Sean Christopherson
@ 2017-11-07 18:43         ` Jarkko Sakkinen
  0 siblings, 0 replies; 40+ messages in thread
From: Jarkko Sakkinen @ 2017-11-07 18:43 UTC (permalink / raw)
  To: Sean Christopherson; +Cc: intel-sgx-kernel-dev, platform-driver-x86

On Mon, Nov 06, 2017 at 06:54:29AM -0800, Sean Christopherson wrote:
> On Mon, 2017-11-06 at 13:39 +0200, Jarkko Sakkinen wrote:
> > On Thu, Nov 02, 2017 at 01:10:29PM -0700, Sean Christopherson wrote:
> > > 
> > > +       list_for_each_entry(entry, &sgx_free_list, list)
> > >                 kfree(entry);
> > > -       }
> > Shouldn't you iterate 'epc_pages' in the rollback now?
> 
> Yes, that's the intent, nice catch.

Yeah, just a sanity check that I'm misinterpreting what I'm seeing :-)
Thanks.

/Jarkko

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [intel-sgx-kernel-dev] [PATCH RFC v3 07/12] intel_sgx: driver for Intel Software Guard Extensions
  2017-11-06 15:54   ` Dave Hansen
@ 2017-11-07 18:47     ` Jarkko Sakkinen
  2017-11-07 19:05       ` Dave Hansen
  0 siblings, 1 reply; 40+ messages in thread
From: Jarkko Sakkinen @ 2017-11-07 18:47 UTC (permalink / raw)
  To: Dave Hansen; +Cc: intel-sgx-kernel-dev, platform-driver-x86

On Mon, Nov 06, 2017 at 07:54:00AM -0800, Dave Hansen wrote:
> On 10/10/2017 07:32 AM, Jarkko Sakkinen wrote:
> > +static LIST_HEAD(sgx_free_list);
> > +static DEFINE_SPINLOCK(sgx_free_list_lock);
> 
> Is this a global list?  Will this be a scalability problem on larger
> systems?

It will be need to be refined for NUMA.

In addition, per-CPU caches would probably make sense.

For simplicity, I would keep it as it is up until the driver is in the
mainline.

/Jarkko

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [intel-sgx-kernel-dev] [PATCH RFC v3 07/12] intel_sgx: driver for Intel Software Guard Extensions
  2017-11-07 18:47     ` Jarkko Sakkinen
@ 2017-11-07 19:05       ` Dave Hansen
  2017-11-14 19:33         ` Jarkko Sakkinen
  0 siblings, 1 reply; 40+ messages in thread
From: Dave Hansen @ 2017-11-07 19:05 UTC (permalink / raw)
  To: Jarkko Sakkinen; +Cc: intel-sgx-kernel-dev, platform-driver-x86

On 11/07/2017 10:47 AM, Jarkko Sakkinen wrote:
> On Mon, Nov 06, 2017 at 07:54:00AM -0800, Dave Hansen wrote:
>> On 10/10/2017 07:32 AM, Jarkko Sakkinen wrote:
>>> +static LIST_HEAD(sgx_free_list);
>>> +static DEFINE_SPINLOCK(sgx_free_list_lock);
>>
>> Is this a global list?  Will this be a scalability problem on larger
>> systems?
> 
> It will be need to be refined for NUMA.
> 
> In addition, per-CPU caches would probably make sense.
> 
> For simplicity, I would keep it as it is up until the driver is in the
> mainline.

FWIW, I don't think we should merge things that aren't performant.
Global locks like this are just intolerable.  You can add this as a
later patch, but please don't merge stuff like this.

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [intel-sgx-kernel-dev] [PATCH RFC v3 07/12] intel_sgx: driver for Intel Software Guard Extensions
  2017-11-06 14:56         ` Sean Christopherson
@ 2017-11-08  6:25           ` Jarkko Sakkinen
  0 siblings, 0 replies; 40+ messages in thread
From: Jarkko Sakkinen @ 2017-11-08  6:25 UTC (permalink / raw)
  To: Sean Christopherson; +Cc: intel-sgx-kernel-dev, platform-driver-x86

On Mon, Nov 06, 2017 at 06:56:56AM -0800, Sean Christopherson wrote:
> On Mon, 2017-11-06 at 13:33 +0200, Jarkko Sakkinen wrote:
> > On Mon, Nov 06, 2017 at 01:08:22PM +0200, Jarkko Sakkinen wrote:
> > > 
> > > On Thu, Nov 02, 2017 at 01:10:29PM -0700, Sean Christopherson wrote:
> > > > 
> > > > On Tue, 2017-10-10 at 17:32 +0300, Jarkko Sakkinen wrote:
> > > > > 
> > > > > +static int sgx_dev_init(struct device *parent, bool locked_msrs)
> > > > > +{
> > > > > +	struct sgx_context *sgx_dev;
> > > > > +	unsigned int eax, ebx, ecx, edx;
> > > > > +	unsigned long pa;
> > > > > +	unsigned long size;
> > > > > +	int ret;
> > > > > +	int i;
> > > > > +
> > > > > +	pr_info("intel_sgx: " DRV_DESCRIPTION " v" DRV_VERSION "\n");
> > > > > +
> > > > > +	sgx_dev = sgxm_ctx_alloc(parent);
> > > > > +
> > > > > +	sgx_locked_msrs = locked_msrs;
> > > > > +
> > > > > +	cpuid_count(SGX_CPUID, SGX_CPUID_CAPABILITIES, &eax, &ebx,
> > > > > &ecx,
> > > > > &edx);
> > > > > +	/* Only allow misc bits supported by the driver. */
> > > > > +	sgx_misc_reserved = ~ebx | SGX_MISC_RESERVED_MASK;
> > > > > +#ifdef CONFIG_X86_64
> > > > > +	sgx_encl_size_max_64 = 1ULL << ((edx >> 8) & 0xFF);
> > > > > +#endif
> > > > > +	sgx_encl_size_max_32 = 1ULL << (edx & 0xFF);
> > > > > +
> > > > > +	if (boot_cpu_has(X86_FEATURE_OSXSAVE)) {
> > > > > +		cpuid_count(SGX_CPUID, SGX_CPUID_ATTRIBUTES, &eax,
> > > > > &ebx,
> > > > > &ecx,
> > > > > +			    &edx);
> > > > > +		sgx_xfrm_mask = (((u64)edx) << 32) + (u64)ecx;
> > > > > +
> > > > > +		for (i = 2; i < 64; i++) {
> > > > > +			cpuid_count(0x0D, i, &eax, &ebx, &ecx, &edx);
> > > > > +			if ((1 << i) & sgx_xfrm_mask)
> > > > > +				sgx_xsave_size_tbl[i] = eax + ebx;
> > > > > +		}
> > > > > +	}
> > > > > +
> > > > > +	for (i = 0; i < SGX_MAX_EPC_BANKS; i++) {
> > > > > +		cpuid_count(SGX_CPUID, i + SGX_CPUID_EPC_BANKS, &eax,
> > > > > &ebx,
> > > > > +			    &ecx, &edx);
> > > > > +		if (!(eax & 0xf))
> > > > > +			break;
> > > > > +
> > > > > +		pa = ((u64)(ebx & 0xfffff) << 32) + (u64)(eax &
> > > > > 0xfffff000);
> > > > > +		size = ((u64)(edx & 0xfffff) << 32) + (u64)(ecx &
> > > > > 0xfffff000);
> > > > > +
> > > > > +		dev_info(parent, "EPC bank 0x%lx-0x%lx\n", pa, pa +
> > > > > size);
> > > > > +
> > > > > +		sgx_epc_banks[i].pa = pa;
> > > > > +		sgx_epc_banks[i].size = size;
> > > > > +	}
> > > > > +
> > > > > +	sgx_nr_epc_banks = i;
> > > > > +
> > > > > +	for (i = 0; i < sgx_nr_epc_banks; i++) {
> > > > > +#ifdef CONFIG_X86_64
> > > > > +		sgx_epc_banks[i].va = (unsigned long)
> > > > > +			ioremap_cache(sgx_epc_banks[i].pa,
> > > > > +				      sgx_epc_banks[i].size);
> > > > > +		if (!sgx_epc_banks[i].va) {
> > > > > +			sgx_nr_epc_banks = i;
> > > > > +			ret = -ENOMEM;
> > > > > +			goto out_iounmap;
> > > > > +		}
> > > > > +#endif
> > > > > +		ret = sgx_add_epc_bank(sgx_epc_banks[i].pa,
> > > > > +				       sgx_epc_banks[i].size, i);
> > > > > +		if (ret) {
> > > > > +			sgx_nr_epc_banks = i + 1;
> > > > > +			goto out_iounmap;
> > > > > +		}
> > > > > +	}
> > > > > +
> > > > > +	ret = sgx_page_cache_init();
> > > > > +	if (ret)
> > > > > +		goto out_iounmap;
> > > > > +
> > > > > +	sgx_add_page_wq = alloc_workqueue("intel_sgx-add-page-wq",
> > > > > +					  WQ_UNBOUND | WQ_FREEZABLE,
> > > > > 1);
> > > > > +	if (!sgx_add_page_wq) {
> > > > > +		pr_err("intel_sgx: alloc_workqueue() failed\n");
> > > > > +		ret = -ENOMEM;
> > > > > +		goto out_iounmap;
> > > > > +	}
> > > > > +
> > > > > +	ret = cdev_device_add(&sgx_dev->cdev, &sgx_dev->dev);
> > > > > +	if (ret)
> > > > > +		goto out_workqueue;
> > > > > +
> > > > > +	return 0;
> > > > > +out_workqueue:
> > > > > +	destroy_workqueue(sgx_add_page_wq);
> > > > > +out_iounmap:
> > > > sgx_page_cache_teardown() should be called here, else ksgxswapd and the
> > > > list of
> > > > EPC pages will leak.
> > > > 
> > > Thanks.
> > > 
> > > > 
> > > > > 
> > > > > +#ifdef CONFIG_X86_64
> > > > > +	for (i = 0; i < sgx_nr_epc_banks; i++)
> > > > > +		iounmap((void *)sgx_epc_banks[i].va);
> > > > > +#endif
> > > > > +	return ret;
> > > > > +}
> > > > ... 
> > > > 
> > > > > 
> > > > > +int sgx_add_epc_bank(resource_size_t start, unsigned long size, int
> > > > > bank)
> > > > > +{
> > > > > +	unsigned long i;
> > > > > +	struct sgx_epc_page *new_epc_page, *entry;
> > > > > +	struct list_head *parser, *temp;
> > > > > +
> > > > > +	for (i = 0; i < size; i += PAGE_SIZE) {
> > > > > +		new_epc_page = kzalloc(sizeof(*new_epc_page),
> > > > > GFP_KERNEL);
> > > > > +		if (!new_epc_page)
> > > > > +			goto err_freelist;
> > > > > +		new_epc_page->pa = (start + i) | bank;
> > > > > +
> > > > > +		spin_lock(&sgx_free_list_lock);
> > > > > +		list_add_tail(&new_epc_page->list, &sgx_free_list);
> > > > > +		sgx_nr_total_epc_pages++;
> > > > > +		sgx_nr_free_pages++;
> > > > > +		spin_unlock(&sgx_free_list_lock);
> > > > > +	}
> > > > > +
> > > > > +	return 0;
> > > > > +err_freelist:
> > > > > +	list_for_each_safe(parser, temp, &sgx_free_list) {
> > > > > +		spin_lock(&sgx_free_list_lock);
> > > > > +		entry = list_entry(parser, struct sgx_epc_page, list);
> > > > > +		list_del(&entry->list);
> > > > > +		spin_unlock(&sgx_free_list_lock);
> > > > > +		kfree(entry);
> > > > > +	}
> > > > > +	return -ENOMEM;
> > > > > +}
> > > > Freeing the entire list on failure does not seem like the appropriate
> > > > behavior
> > > > for this helper func, e.g. the list should be purged by
> > > > sgx_page_cache_teardown.
> > > > Buffering the new pages into a local list and only splicing said list into
> > > > the
> > > > global list upon success is more inline with what I would expect from a
> > > > helper
> > > > func, and also only requires a single lock/unlock.
> > > > 
> > > > diff --git drivers/platform/x86/intel_sgx/sgx_page_cache.c
> > > > drivers/platform/x86/intel_sgx/sgx_page_cache.c
> > > > index f8883d24692a..38496e6296f1 100644
> > > > --- drivers/platform/x86/intel_sgx/sgx_page_cache.c
> > > > +++ drivers/platform/x86/intel_sgx/sgx_page_cache.c
> > > > @@ -397,7 +397,8 @@ int sgx_add_epc_bank(resource_size_t start, unsigned
> > > > long
> > > > size, int bank)
> > > >  {
> > > >         unsigned long i;
> > > >         struct sgx_epc_page *new_epc_page, *entry;
> > > > -       struct list_head *parser, *temp;
> > > > +       LIST_HEAD(epc_pages);
> > > >  
> > > >         for (i = 0; i < size; i += PAGE_SIZE) {
> > > >                 new_epc_page = kzalloc(sizeof(*new_epc_page), GFP_KERNEL);
> > > > @@ -405,22 +406,19 @@ int sgx_add_epc_bank(resource_size_t start, unsigned
> > > > long
> > > > size, int bank)
> > > >                         goto err_freelist;
> > > >                 new_epc_page->pa = (start + i) | bank;
> > > >  
> > > > -               spin_lock(&sgx_free_list_lock);
> > > > -               list_add_tail(&new_epc_page->list, &sgx_free_list);
> > > > -               sgx_nr_total_epc_pages++;
> > > > -               sgx_nr_free_pages++;
> > > > -               spin_unlock(&sgx_free_list_lock);
> > > > +               list_add_tail(&new_epc_page->list, &epc_pages);
> > > > +               nr_pages++;
> > > >         }
> > > >  
> > > > +       spin_lock(&sgx_free_list_lock);
> > > > +       list_splice_tail(&epc_pages, &sgx_free_list);
> > > > +       sgx_nr_total_epc_pages += nr_pages;
> > > > +       sgx_nr_free_pages += nr_pages;
> > > > +       spin_unlock(&sgx_free_list_lock);
> > > >         return 0;
> > > >  err_freelist:
> > > > -       list_for_each_safe(parser, temp, &sgx_free_list) {
> > > > -               spin_lock(&sgx_free_list_lock);
> > > > -               entry = list_entry(parser, struct sgx_epc_page, list);
> > > > -               list_del(&entry->list);
> > > > -               spin_unlock(&sgx_free_list_lock);
> > > > +       list_for_each_entry(entry, &sgx_free_list, list)
> > > >                 kfree(entry);
> > > > -       }
> > > >         return -ENOMEM;
> > > >  }
> > > This makes sense to me and I think it makes also sense to move bunch of
> > > stuff from sgx_dev_init() to sgx_page_cache_init().
> > > /Jarkko
> > You can get away without nr_pages as you can get from i or am I
> > misobserving something?
> 
> i is incremented by PAGE_SIZE.  I suppose you could do "+= i / PAGE_SIZE", but I
> would opt for clarity in this case.

Redundant calculations do not improve clarity.

/Jarkko

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [intel-sgx-kernel-dev] [PATCH RFC v3 10/12] intel_sgx: in-kernel launch enclave
  2017-10-10 14:32 ` [PATCH RFC v3 10/12] intel_sgx: in-kernel launch enclave Jarkko Sakkinen
@ 2017-11-08 20:07   ` Sean Christopherson
  2017-11-14 14:22     ` Jarkko Sakkinen
  0 siblings, 1 reply; 40+ messages in thread
From: Sean Christopherson @ 2017-11-08 20:07 UTC (permalink / raw)
  To: Jarkko Sakkinen, intel-sgx-kernel-dev; +Cc: platform-driver-x86

On Tue, 2017-10-10 at 17:32 +0300, Jarkko Sakkinen wrote:
> +static RSA *load_sign_key(const char *path)
> +{
> +	FILE *f;
> +	RSA *key;
> +
> +	f = fopen(path, "rb");
> +	if (!f) {
> +		fprintf(stderr, "Unable to open %s\n", path);
> +		return NULL;
> +	}
> +	key = RSA_new();
> +	if (!PEM_read_RSAPrivateKey(f, &key, pem_passwd_cb, NULL))
> +		return NULL;
> +	fclose(f);
> +
> +	if (BN_num_bytes(key->n) != SGX_MODULUS_SIZE) {

Dereferencing the RSA pointer (key) breaks on OpenSSL 1.1.0 as RSA is now an
opaque object.  It's relatively easy to fudge around the issue, patch below.

https://github.com/openssl/openssl/issues/1491
https://wiki.openssl.org/index.php/OpenSSL_1.1.0_Changes

> +		fprintf(stderr, "Invalid key size %d\n", BN_num_bytes(key-
> >n));
> +		RSA_free(key);
> +		return NULL;
> +	}
> +
> +	return key;
> +}
> +

diff --git drivers/platform/x86/intel_sgx/le/enclave/sgxsign.c
drivers/platform/x86/intel_sgx/le/enclave/sgxsign.c
index 27e8c61d033c..e454dc95f438 100644
--- drivers/platform/x86/intel_sgx/le/enclave/sgxsign.c
+++ drivers/platform/x86/intel_sgx/le/enclave/sgxsign.c
@@ -110,6 +110,17 @@ static int pem_passwd_cb(char *buf, int size, int rwflag,
void *u)
        return strlen(buf) >= size ? size - 1 : strlen(buf);
 }
 
+static inline const BIGNUM *get_modulus(RSA *key)
+{
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+       return key->n;
+#else
+       const BIGNUM *n;
+       RSA_get0_key(key, &n, NULL, NULL);
+       return n;
+#endif
+}
+
 static RSA *load_sign_key(const char *path)
 {
        FILE *f;
@@ -125,8 +136,9 @@ static RSA *load_sign_key(const char *path)
                return NULL;
        fclose(f);
 
-       if (BN_num_bytes(key->n) != SGX_MODULUS_SIZE) {
-               fprintf(stderr, "Invalid key size %d\n", BN_num_bytes(key->n));
+       if (BN_num_bytes(get_modulus(key)) != SGX_MODULUS_SIZE) {
+               fprintf(stderr, "Invalid key size %d\n",
+                       BN_num_bytes(get_modulus(key)));
                RSA_free(key);
                return NULL;
        }
@@ -511,7 +523,7 @@ int main(int argc, char **argv)
        if (!sign_key)
                goto out;
 
-       BN_bn2bin(sign_key->n, ss.modulus);
+       BN_bn2bin(get_modulus(sign_key), ss.modulus);
 
        if (!measure_encl(argv[1], ss.body.mrenclave))
                goto out;

^ permalink raw reply related	[flat|nested] 40+ messages in thread

* Re: [intel-sgx-kernel-dev] [PATCH RFC v3 10/12] intel_sgx: in-kernel launch enclave
  2017-11-08 20:07   ` [intel-sgx-kernel-dev] " Sean Christopherson
@ 2017-11-14 14:22     ` Jarkko Sakkinen
  0 siblings, 0 replies; 40+ messages in thread
From: Jarkko Sakkinen @ 2017-11-14 14:22 UTC (permalink / raw)
  To: Sean Christopherson; +Cc: intel-sgx-kernel-dev, platform-driver-x86

On Wed, Nov 08, 2017 at 12:07:26PM -0800, Sean Christopherson wrote:
> On Tue, 2017-10-10 at 17:32 +0300, Jarkko Sakkinen wrote:
> > +static RSA *load_sign_key(const char *path)
> > +{
> > +	FILE *f;
> > +	RSA *key;
> > +
> > +	f = fopen(path, "rb");
> > +	if (!f) {
> > +		fprintf(stderr, "Unable to open %s\n", path);
> > +		return NULL;
> > +	}
> > +	key = RSA_new();
> > +	if (!PEM_read_RSAPrivateKey(f, &key, pem_passwd_cb, NULL))
> > +		return NULL;
> > +	fclose(f);
> > +
> > +	if (BN_num_bytes(key->n) != SGX_MODULUS_SIZE) {
> 
> Dereferencing the RSA pointer (key) breaks on OpenSSL 1.1.0 as RSA is now an
> opaque object.  It's relatively easy to fudge around the issue, patch below.
> 
> https://github.com/openssl/openssl/issues/1491
> https://wiki.openssl.org/index.php/OpenSSL_1.1.0_Changes
> 
> > +		fprintf(stderr, "Invalid key size %d\n", BN_num_bytes(key-
> > >n));
> > +		RSA_free(key);
> > +		return NULL;
> > +	}
> > +
> > +	return key;
> > +}
> > +
> 
> diff --git drivers/platform/x86/intel_sgx/le/enclave/sgxsign.c
> drivers/platform/x86/intel_sgx/le/enclave/sgxsign.c
> index 27e8c61d033c..e454dc95f438 100644
> --- drivers/platform/x86/intel_sgx/le/enclave/sgxsign.c
> +++ drivers/platform/x86/intel_sgx/le/enclave/sgxsign.c
> @@ -110,6 +110,17 @@ static int pem_passwd_cb(char *buf, int size, int rwflag,
> void *u)
>         return strlen(buf) >= size ? size - 1 : strlen(buf);
>  }
>  
> +static inline const BIGNUM *get_modulus(RSA *key)
> +{
> +#if OPENSSL_VERSION_NUMBER < 0x10100000L
> +       return key->n;
> +#else
> +       const BIGNUM *n;
> +       RSA_get0_key(key, &n, NULL, NULL);
> +       return n;
> +#endif
> +}
> +
>  static RSA *load_sign_key(const char *path)
>  {
>         FILE *f;
> @@ -125,8 +136,9 @@ static RSA *load_sign_key(const char *path)
>                 return NULL;
>         fclose(f);
>  
> -       if (BN_num_bytes(key->n) != SGX_MODULUS_SIZE) {
> -               fprintf(stderr, "Invalid key size %d\n", BN_num_bytes(key->n));
> +       if (BN_num_bytes(get_modulus(key)) != SGX_MODULUS_SIZE) {
> +               fprintf(stderr, "Invalid key size %d\n",
> +                       BN_num_bytes(get_modulus(key)));
>                 RSA_free(key);
>                 return NULL;
>         }
> @@ -511,7 +523,7 @@ int main(int argc, char **argv)
>         if (!sign_key)
>                 goto out;
>  
> -       BN_bn2bin(sign_key->n, ss.modulus);
> +       BN_bn2bin(get_modulus(sign_key), ss.modulus);
>  
>         if (!measure_encl(argv[1], ss.body.mrenclave))
>                 goto out;
> 

Already sent v5 but I'll put this to v6. Thanks.

/Jarkko

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [intel-sgx-kernel-dev] [PATCH RFC v3 07/12] intel_sgx: driver for Intel Software Guard Extensions
  2017-11-07 19:05       ` Dave Hansen
@ 2017-11-14 19:33         ` Jarkko Sakkinen
  2017-11-14 21:05           ` Jarkko Sakkinen
  0 siblings, 1 reply; 40+ messages in thread
From: Jarkko Sakkinen @ 2017-11-14 19:33 UTC (permalink / raw)
  To: Dave Hansen; +Cc: intel-sgx-kernel-dev, platform-driver-x86, linux-kernel

On Tue, Nov 07, 2017 at 11:05:08AM -0800, Dave Hansen wrote:
> On 11/07/2017 10:47 AM, Jarkko Sakkinen wrote:
> > On Mon, Nov 06, 2017 at 07:54:00AM -0800, Dave Hansen wrote:
> >> On 10/10/2017 07:32 AM, Jarkko Sakkinen wrote:
> >>> +static LIST_HEAD(sgx_free_list);
> >>> +static DEFINE_SPINLOCK(sgx_free_list_lock);
> >>
> >> Is this a global list?  Will this be a scalability problem on larger
> >> systems?
> > 
> > It will be need to be refined for NUMA.
> > 
> > In addition, per-CPU caches would probably make sense.
> > 
> > For simplicity, I would keep it as it is up until the driver is in the
> > mainline.
> 
> FWIW, I don't think we should merge things that aren't performant.
> Global locks like this are just intolerable.  You can add this as a
> later patch, but please don't merge stuff like this.

The back pointer to struct sgx_encl_page from struct sgx_epc_page is
useless. I've had this in backlog already long time ago but had forgot
it as I've been mostly working with the launch infrastructure lately.

Your comment worked as kind of a reminder of that. Thank you.

Once that field is removed the whole struct is useless and EPC bank
converges to an array. With an array the driver should be able reserve
pages without a global lock.

I've started writing a patch to make all this happen and it is
progressing really well. I'm planning to include this change to v6.
As it simplifies code I'm going to squash it as part of the initial
driver patch.

How does this sound?

/Jarkko

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [intel-sgx-kernel-dev] [PATCH RFC v3 07/12] intel_sgx: driver for Intel Software Guard Extensions
  2017-11-14 19:33         ` Jarkko Sakkinen
@ 2017-11-14 21:05           ` Jarkko Sakkinen
  2017-11-14 21:12             ` Dave Hansen
  0 siblings, 1 reply; 40+ messages in thread
From: Jarkko Sakkinen @ 2017-11-14 21:05 UTC (permalink / raw)
  To: Dave Hansen; +Cc: linux-kernel, intel-sgx-kernel-dev, platform-driver-x86

On Tue, Nov 14, 2017 at 09:33:34PM +0200, Jarkko Sakkinen wrote:
> On Tue, Nov 07, 2017 at 11:05:08AM -0800, Dave Hansen wrote:
> > On 11/07/2017 10:47 AM, Jarkko Sakkinen wrote:
> > > On Mon, Nov 06, 2017 at 07:54:00AM -0800, Dave Hansen wrote:
> > >> On 10/10/2017 07:32 AM, Jarkko Sakkinen wrote:
> > >>> +static LIST_HEAD(sgx_free_list);
> > >>> +static DEFINE_SPINLOCK(sgx_free_list_lock);
> > >>
> > >> Is this a global list?  Will this be a scalability problem on larger
> > >> systems?
> > > 
> > > It will be need to be refined for NUMA.
> > > 
> > > In addition, per-CPU caches would probably make sense.
> > > 
> > > For simplicity, I would keep it as it is up until the driver is in the
> > > mainline.
> > 
> > FWIW, I don't think we should merge things that aren't performant.
> > Global locks like this are just intolerable.  You can add this as a
> > later patch, but please don't merge stuff like this.
> 
> The back pointer to struct sgx_encl_page from struct sgx_epc_page is
> useless. I've had this in backlog already long time ago but had forgot
> it as I've been mostly working with the launch infrastructure lately.
> 
> Your comment worked as kind of a reminder of that. Thank you.
> 
> Once that field is removed the whole struct is useless and EPC bank
> converges to an array. With an array the driver should be able reserve
> pages without a global lock.
> 
> I've started writing a patch to make all this happen and it is
> progressing really well. I'm planning to include this change to v6.
> As it simplifies code I'm going to squash it as part of the initial
> driver patch.
> 
> How does this sound?

Every sgx_epc_bank will have a bitmap array for reserved EPC.

Every unswapped sgx_encl_page will have a pointer containing physical
address of the EPC page in the upper bits and bank number in the lower
bits (like sgx_epc_page has now in the 'pa' field).

This layout does not require a global lock.

/Jarkko

^ permalink raw reply	[flat|nested] 40+ messages in thread

* Re: [intel-sgx-kernel-dev] [PATCH RFC v3 07/12] intel_sgx: driver for Intel Software Guard Extensions
  2017-11-14 21:05           ` Jarkko Sakkinen
@ 2017-11-14 21:12             ` Dave Hansen
  0 siblings, 0 replies; 40+ messages in thread
From: Dave Hansen @ 2017-11-14 21:12 UTC (permalink / raw)
  To: Jarkko Sakkinen; +Cc: linux-kernel, intel-sgx-kernel-dev, platform-driver-x86

On 11/14/2017 01:05 PM, Jarkko Sakkinen wrote:
> I've started writing a patch to make all this happen and it is
> progressing really well. I'm planning to include this change to v6.
> As it simplifies code I'm going to squash it as part of the initial
> driver patch.
> 
> How does this sound?

Sounds sane to me.

^ permalink raw reply	[flat|nested] 40+ messages in thread

end of thread, other threads:[~2017-11-14 21:13 UTC | newest]

Thread overview: 40+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-10-10 14:32 [PATCH RFC v3 00/12] Intel(R) SGX Driver Jarkko Sakkinen
2017-10-10 14:32 ` [PATCH RFC v3 01/12] intel_sgx: updated MAINTAINERS Jarkko Sakkinen
2017-10-10 14:32 ` [PATCH RFC v3 02/12] x86: add SGX definition to cpufeature Jarkko Sakkinen
2017-10-10 14:32 ` [PATCH RFC v3 03/12] x86: define the feature control MSR's SGX enable bit Jarkko Sakkinen
2017-10-10 14:32 ` [PATCH RFC v3 04/12] x86: define the feature control MSR's SGX launch control bit Jarkko Sakkinen
2017-10-10 14:32 ` [PATCH RFC v3 05/12] x86: add SGX MSRs to msr-index.h Jarkko Sakkinen
2017-10-10 14:32 ` [PATCH RFC v3 06/12] fs/pipe.c: export create_pipe_files() and replace_fd() Jarkko Sakkinen
2017-10-10 14:32 ` [PATCH RFC v3 08/12] intel_sgx: ptrace() support Jarkko Sakkinen
2017-10-10 14:32 ` [PATCH RFC v3 09/12] intel_sgx: driver documentation Jarkko Sakkinen
2017-10-10 14:32 ` [PATCH RFC v3 10/12] intel_sgx: in-kernel launch enclave Jarkko Sakkinen
2017-11-08 20:07   ` [intel-sgx-kernel-dev] " Sean Christopherson
2017-11-14 14:22     ` Jarkko Sakkinen
2017-10-10 14:32 ` [PATCH RFC v3 11/12] intel_sgx: glue code for in-kernel LE Jarkko Sakkinen
2017-10-10 14:32 ` [PATCH RFC v3 12/12] intel_sgx: update IA32_SGXLEPUBKEYHASH* MSRs Jarkko Sakkinen
     [not found] ` <20171010143258.21623-8-jarkko.sakkinen@linux.intel.com>
2017-10-10 15:41   ` [intel-sgx-kernel-dev] [PATCH RFC v3 07/12] intel_sgx: driver for Intel Software Guard Extensions Sean Christopherson
2017-10-11 11:46     ` Jarkko Sakkinen
2017-10-11 15:56       ` Sean Christopherson
2017-10-10 18:26   ` Sean Christopherson
2017-10-13 19:58     ` Jarkko Sakkinen
2017-10-13 20:02       ` Jarkko Sakkinen
2017-10-13 20:08         ` Jarkko Sakkinen
2017-10-13 20:13           ` Jarkko Sakkinen
2017-10-12 16:48   ` Sean Christopherson
2017-10-13 19:16     ` Jarkko Sakkinen
2017-11-02 19:48   ` Sean Christopherson
2017-11-06  7:23     ` Jarkko Sakkinen
2017-11-02 20:10   ` Sean Christopherson
2017-11-06 11:08     ` Jarkko Sakkinen
2017-11-06 11:33       ` Jarkko Sakkinen
2017-11-06 14:56         ` Sean Christopherson
2017-11-08  6:25           ` Jarkko Sakkinen
2017-11-06 11:39     ` Jarkko Sakkinen
2017-11-06 14:54       ` Sean Christopherson
2017-11-07 18:43         ` Jarkko Sakkinen
2017-11-06 15:54   ` Dave Hansen
2017-11-07 18:47     ` Jarkko Sakkinen
2017-11-07 19:05       ` Dave Hansen
2017-11-14 19:33         ` Jarkko Sakkinen
2017-11-14 21:05           ` Jarkko Sakkinen
2017-11-14 21:12             ` Dave Hansen

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.