diff --git a/arch/x86/entry/vdso/Makefile b/arch/x86/entry/vdso/Makefile
index 34bcf87d358c..fb5b9960b192 100644
--- a/arch/x86/entry/vdso/Makefile
+++ b/arch/x86/entry/vdso/Makefile
@@ -18,6 +18,7 @@ VDSO32-$(CONFIG_IA32_EMULATION)	:= y
 
 # files to link into the vdso
 vobjs-y := vdso-note.o vclock_gettime.o vgetcpu.o
+vobjs-$(VDSO64-y)		+= vsgx_enter_enclave.o
 
 # files to link into kernel
 obj-y				+= vma.o extable.o
@@ -85,6 +86,7 @@ CFLAGS_REMOVE_vdso-note.o = -pg
 CFLAGS_REMOVE_vclock_gettime.o = -pg
 CFLAGS_REMOVE_vgetcpu.o = -pg
 CFLAGS_REMOVE_vvar.o = -pg
+CFLAGS_REMOVE_vsgx_enter_enclave.o = -pg
 
 #
 # X32 processes use x32 vDSO to access 64bit kernel data.
diff --git a/arch/x86/entry/vdso/vdso.lds.S b/arch/x86/entry/vdso/vdso.lds.S
index d3a2dce4cfa9..50952a995a6c 100644
--- a/arch/x86/entry/vdso/vdso.lds.S
+++ b/arch/x86/entry/vdso/vdso.lds.S
@@ -25,6 +25,7 @@ VERSION {
 		__vdso_getcpu;
 		time;
 		__vdso_time;
+		__vdso_sgx_enter_enclave;
 	local: *;
 	};
 }
diff --git a/arch/x86/entry/vdso/vsgx_enter_enclave.S b/arch/x86/entry/vdso/vsgx_enter_enclave.S
new file mode 100644
index 000000000000..fe0bf6671d6d
--- /dev/null
+++ b/arch/x86/entry/vdso/vsgx_enter_enclave.S
@@ -0,0 +1,101 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#include <linux/linkage.h>
+#include <asm/export.h>
+#include <asm/errno.h>
+
+#include "extable.h"
+
+#define EX_LEAF		0*8
+#define EX_TRAPNR	0*8+4
+#define EX_ERROR_CODE	0*8+6
+#define EX_ADDRESS	1*8
+
+.code64
+.section .text, "ax"
+
+#ifdef SGX_KERNEL_DOC
+/**
+ * __vdso_sgx_enter_enclave() - Enter an SGX enclave
+ *
+ * @leaf:	**IN \%eax** - ENCLU leaf, must be EENTER or ERESUME
+ * @tcs:	**IN \%rbx** - TCS, must be non-NULL
+ * @ex_info:	**IN \%rcx** - Optional 'struct sgx_enclave_exception' pointer
+ *
+ * Return:
+ *  **OUT \%eax** -
+ *  %0 on a clean entry/exit to/from the enclave, %-EINVAL if ENCLU leaf is
+ *  not allowed or if TCS is NULL, %-EFAULT if ENCLU or the enclave faults
+ *
+ * **Important!**  __vdso_sgx_enter_enclave() is **NOT** compliant with the
+ * x86-64 ABI, i.e. cannot be called from standard C code.   As noted above,
+ * input parameters must be passed via ``%eax``, ``%rbx`` and ``%rcx``, with
+ * the return value passed via ``%eax``.  All registers except ``%rsp`` must
+ * be treated as volatile from the caller's perspective, including but not
+ * limited to GPRs, EFLAGS.DF, MXCSR, FCW, etc...  Conversely, the enclave
+ * being run **must** preserve the untrusted ``%rsp`` and stack.
+ */
+__vdso_sgx_enter_enclave(u32 leaf, void *tcs,
+			 struct sgx_enclave_exception *ex_info)
+{
+	if (leaf != SGX_EENTER && leaf != SGX_ERESUME)
+		return -EINVAL;
+
+	if (!tcs)
+		return -EINVAL;
+
+	try {
+		ENCLU[leaf];
+	} catch (exception) {
+		if (e)
+			*e = exception;
+		return -EFAULT;
+	}
+
+	return 0;
+}
+#endif
+ENTRY(__vdso_sgx_enter_enclave)
+	/* EENTER <= leaf <= ERESUME */
+	cmp	$0x2, %eax
+	jb	bad_input
+
+	cmp	$0x3, %eax
+	ja	bad_input
+
+	/* TCS must be non-NULL */
+	test	%rbx, %rbx
+	je	bad_input
+
+	/* Save @exception_info */
+	push	%rcx
+
+	/* Load AEP for ENCLU */
+	lea	1f(%rip),  %rcx
+1:	enclu
+
+	add	$0x8, %rsp
+	xor	%eax, %eax
+	ret
+
+bad_input:
+	mov     $(-EINVAL), %rax
+	ret
+
+.pushsection .fixup, "ax"
+	/* Re-load @exception_info and fill it (if it's non-NULL) */
+2:	pop	%rcx
+	test    %rcx, %rcx
+	je      3f
+
+	mov	%eax, EX_LEAF(%rcx)
+	mov	%di,  EX_TRAPNR(%rcx)
+	mov	%si,  EX_ERROR_CODE(%rcx)
+	mov	%rdx, EX_ADDRESS(%rcx)
+3:	mov	$(-EFAULT), %rax
+	ret
+.popsection
+
+_ASM_VDSO_EXTABLE_HANDLE(1b, 2b)
+
+ENDPROC(__vdso_sgx_enter_enclave)
diff --git a/arch/x86/include/uapi/asm/sgx.h b/arch/x86/include/uapi/asm/sgx.h
index 3b80acde8671..9ed690a38c70 100644
--- a/arch/x86/include/uapi/asm/sgx.h
+++ b/arch/x86/include/uapi/asm/sgx.h
@@ -65,4 +65,22 @@ struct sgx_enclave_set_attribute {
 	__u64	attribute_fd;
 };
 
+/**
+ * struct sgx_enclave_exception - structure to report exceptions encountered in
+ *				  __vdso_sgx_enter_enclave()
+ *
+ * @leaf:	ENCLU leaf from \%eax at time of exception
+ * @trapnr:	exception trap number, a.k.a. fault vector
+ * @error_code:	exception error code
+ * @address:	exception address, e.g. CR2 on a #PF
+ * @reserved:	reserved for future use
+ */
+struct sgx_enclave_exception {
+	__u32 leaf;
+	__u16 trapnr;
+	__u16 error_code;
+	__u64 address;
+	__u64 reserved[2];
+};
+
 #endif /* _UAPI_ASM_X86_SGX_H */
