diff --git a/arch/x86/entry/vdso/Makefile b/arch/x86/entry/vdso/Makefile
index b8f7c301b88f..5e28f838d8aa 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..0e4cd8a9549a
--- /dev/null
+++ b/arch/x86/entry/vdso/vsgx_enter_enclave.S
@@ -0,0 +1,136 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+
+#include <linux/linkage.h>
+#include <asm/export.h>
+#include <asm/errno.h>
+
+#include "extable.h"
+
+#define RDI		0*8
+#define RSI		1*8
+#define RDX		2*8
+#define R8		3*8
+#define R9		4*8
+#define R10		5*8
+
+#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"
+
+/*
+ * long __vdso_sgx_enter_enclave(__u32 leaf, void *tcs
+ *				 struct sgx_enclave_regs *regs
+ *				 struct sgx_enclave_exception *e)
+ * {
+ *	if (leaf != SGX_EENTER && leaf != SGX_ERESUME)
+ *		return -EINVAL;
+ *
+ *	if (!tcs)
+ *		return -EINVAL;
+ *
+ *	if (regs)
+ *		copy_regs_to_cpu(regs);
+ *
+ *	try {
+ *		ENCLU[leaf];
+ *	} catch (exception) {
+ *		if (e)
+ *	 		*e = exception;
+ *		return -EFAULT;
+ *	}
+ *
+ *	if (regs)
+ *		copy_cpu_to_regs(regs);
+ *	return 0;
+ * }
+ */
+ENTRY(__vdso_sgx_enter_enclave)
+	/* EENTER <= leaf <= ERESUME */
+	lea	-0x2(%edi), %eax
+	cmp	$0x1, %eax
+	ja	bad_input
+
+	/* TCS must be non-NULL */
+	test	%rsi, %rsi
+	je	bad_input
+
+	/* save non-volatile registers */
+	push	%rbp
+	mov	%rsp, %rbp
+	push	%r15
+	push	%r14
+	push	%r13
+	push	%r12
+	push	%rbx
+
+	/* save @regs and @e to the red zone */
+	mov	%rdx, -0x8(%rsp)
+	mov	%rcx, -0x10(%rsp)
+
+	/* load leaf, TCS and AEP for ENCLU */
+	mov	%edi,      %eax
+	mov	%rsi,      %rbx
+	lea	1f(%rip),  %rcx
+
+	/* optionally copy @regs to registers */
+	test	%rdx, %rdx
+	je	1f
+
+	mov	%rdx, %r11
+	mov	RDI(%r11), %rdi
+	mov	RSI(%r11), %rsi
+	mov	RDX(%r11), %rdx
+	mov	R8(%r11),  %r8
+	mov	R9(%r11),  %r9
+	mov	R10(%r11), %r10
+
+1:      enclu
+
+	/* ret = 0 */
+	xor	%eax, %eax
+
+	/* optionally copy registers to @regs */
+	mov	-0x8(%rsp), %r11
+	test	%r11, %r11
+	je	2f
+
+	mov	%rdi, RDI(%r11)
+	mov	%rsi, RSI(%r11)
+	mov	%rdx, RDX(%r11)
+	mov	%r8,  R8(%r11)
+	mov	%r9,  R9(%r11)
+	mov	%r10, R10(%r11)
+
+	/* restore non-volatile registers and return */
+2:	pop	%rbx
+	pop	%r12
+	pop	%r13
+	pop	%r14
+	pop	%r15
+	pop	%rbp
+	ret
+
+bad_input:
+	mov     $(-EINVAL), %rax
+	ret
+
+.pushsection .fixup, "ax"
+3:	mov	-0x10(%rsp), %r11
+	test	%r11, %r11
+	je	4f
+
+	mov	%eax, EX_LEAF(%r11)
+	mov	%di,  EX_TRAPNR(%r11)
+	mov	%si,  EX_ERROR_CODE(%r11)
+	mov	%rdx, EX_ADDRESS(%r11)
+4:	mov     $(-EFAULT), %rax
+	jmp     2b
+.popsection
+
+_ASM_VDSO_EXTABLE_HANDLE(1b, 3b)
+
+ENDPROC(__vdso_sgx_enter_enclave)
diff --git a/arch/x86/include/uapi/asm/sgx.h b/arch/x86/include/uapi/asm/sgx.h
index 266b813eefa1..4f840b334369 100644
--- a/arch/x86/include/uapi/asm/sgx.h
+++ b/arch/x86/include/uapi/asm/sgx.h
@@ -96,4 +96,48 @@ struct sgx_enclave_modify_pages {
 	__u8	op;
 } __attribute__((__packed__));
 
+/**
+ * struct sgx_enclave_exception - structure to pass register in/out of enclave
+ *				  by way of __vdso_sgx_enter_enclave
+ *
+ * @rdi:	value of %rdi, loaded/saved on enter/exit
+ * @rsi:	value of %rsi, loaded/saved on enter/exit
+ * @rdx:	value of %rdx, loaded/saved on enter/exit
+ * @r8:		value of %r8, loaded/saved on enter/exit
+ * @r9:		value of %r9, loaded/saved on enter/exit
+ * @r10:	value of %r10, loaded/saved on enter/exit
+ */
+struct sgx_enclave_regs {
+	__u64 rdi;
+	__u64 rsi;
+	__u64 rdx;
+	__u64 r8;
+	__u64 r9;
+	__u64 r10;
+};
+
+/**
+ * struct sgx_enclave_exception - structure to report exceptions encountered in
+ *				  __vdso_sgx_enter_enclave
+ *
+ * @leaf:	ENCLU leaf from %rax at time of exception
+ * @trapnr:	exception trap number, a.k.a. fault vector
+ * @error_cdde:	exception error code
+ * @address:	exception address, e.g. CR2 on a #PF
+ */
+struct sgx_enclave_exception {
+	__u32 leaf;
+	__u16 trapnr;
+	__u16 error_code;
+	__u64 address;
+};
+
+/**
+ * typedef __vsgx_enter_enclave_t - Function pointer prototype for
+ *				    __vdso_sgx_enter_enclave
+ */
+typedef long (*__vsgx_enter_enclave_t)(__u32 leaf, void *tcs,
+				       struct sgx_enclave_regs *regs,
+				       struct sgx_enclave_exception *e);
+
 #endif /* _UAPI_ASM_X86_SGX_H */
