diff --git a/Documentation/admin-guide/kernel-parameters.txt b/Documentation/admin-guide/kernel-parameters.txt
index 9725c546a0d4..9d23c05a833b 100644
--- a/Documentation/admin-guide/kernel-parameters.txt
+++ b/Documentation/admin-guide/kernel-parameters.txt
@@ -5165,6 +5165,13 @@
 
 	serialnumber	[BUGS=X86-32]
 
+	sgx.overcommit_percent=	[X86-64,SGX]
+			Limits the amount of normal RAM used for backing
+			storage that may be allocate, expressed as a
+			percentage of the total number of EPC pages in the
+			system.
+			See Documentation/x86/sgx.rst for more information.
+
 	shapers=	[NET]
 			Maximal number of shapers.
 
diff --git a/Documentation/x86/sgx.rst b/Documentation/x86/sgx.rst
index 265568a9292c..4f9a1c68be94 100644
--- a/Documentation/x86/sgx.rst
+++ b/Documentation/x86/sgx.rst
@@ -147,7 +147,21 @@ Page reclaimer
 
 Similar to the core kswapd, ksgxd, is responsible for managing the
 overcommitment of enclave memory.  If the system runs out of enclave memory,
-*ksgxd* “swaps” enclave memory to normal memory.
+*ksgxd* “swaps” enclave memory to normal RAM. This normal RAM is allocated
+via per enclave shared memory. The shared memory area is not mapped into the
+enclave or the task mapping it, which makes its memory use opaque - including
+to the system out of memory killer (OOM). This can be problematic when there
+are no limits in place on the amount an enclave can allocate.
+
+At boot time, the module parameter "sgx.overcommit_percent" can be used to
+place a limit on the number of shared memory backing pages that may be
+allocated, expressed as a percentage of the total number of EPC pages in the
+system.  A value of 100 is the default, and represents a limit equal to the
+number of EPC pages in the system. To disable the limit, set
+sgx.overcommit_percent to -1. The number of backing pages available to
+enclaves is a global resource. If the system exceeds the number of allowed
+backing pages in use, the reclaimer will be unable to swap EPC pages to
+shared memory.
 
 Launch Control
 ==============
diff --git a/arch/x86/kernel/cpu/sgx/Makefile b/arch/x86/kernel/cpu/sgx/Makefile
index 9c1656779b2a..72f9192a43fe 100644
--- a/arch/x86/kernel/cpu/sgx/Makefile
+++ b/arch/x86/kernel/cpu/sgx/Makefile
@@ -1,6 +1,10 @@
-obj-y += \
+# This allows sgx to have module namespace
+obj-y += sgx.o
+
+sgx-y += \
 	driver.o \
 	encl.o \
 	ioctl.o \
 	main.o
+
 obj-$(CONFIG_X86_SGX_KVM)	+= virt.o
diff --git a/arch/x86/kernel/cpu/sgx/main.c b/arch/x86/kernel/cpu/sgx/main.c
index 2857a49f2335..c58ce9d9fd56 100644
--- a/arch/x86/kernel/cpu/sgx/main.c
+++ b/arch/x86/kernel/cpu/sgx/main.c
@@ -1,6 +1,7 @@
 // SPDX-License-Identifier: GPL-2.0
 /*  Copyright(c) 2016-20 Intel Corporation. */
 
+#include <linux/moduleparam.h>
 #include <linux/file.h>
 #include <linux/freezer.h>
 #include <linux/highmem.h>
@@ -43,6 +44,54 @@ static struct sgx_numa_node *sgx_numa_nodes;
 
 static LIST_HEAD(sgx_dirty_page_list);
 
+/*
+ * Limits the amount of normal RAM that SGX can consume for EPC
+ * overcommit to the total EPC pages * sgx_overcommit_percent / 100
+ */
+static int sgx_overcommit_percent = 100;
+module_param_named(overcommit_percent, sgx_overcommit_percent, int, 0440);
+MODULE_PARM_DESC(overcommit_percent, "Percentage of overcommit of EPC pages.");
+
+/* The number of pages that can be allocated globally for backing storage. */
+static atomic_long_t sgx_nr_available_backing_pages;
+static bool sgx_disable_overcommit_tracking;
+
+/**
+ * sgx_charge_mem() - charge for a page used for backing storage
+ *
+ * Backing storage usage is capped by the sgx_nr_available_backing_pages.
+ * If the backing storage usage is over the overcommit limit,
+ * return an error.
+ *
+ * Return:
+ * 0:		The page requested does not exceed the limit
+ * -ENOMEM:	The page requested exceeds the overcommit limit
+ */
+int sgx_charge_mem(void)
+{
+	if (sgx_disable_overcommit_tracking)
+		return 0;
+
+	if (!atomic_long_add_unless(&sgx_nr_available_backing_pages, -1, 0))
+		return -ENOMEM;
+
+	return 0;
+}
+
+/**
+ * sgx_uncharge_mem() - uncharge a page previously used for backing storage
+ *
+ * When backing storage is no longer in use, increment the
+ * sgx_nr_available_backing_pages counter.
+ */
+void sgx_uncharge_mem(void)
+{
+	if (sgx_disable_overcommit_tracking)
+		return;
+
+	atomic_long_inc(&sgx_nr_available_backing_pages);
+}
+
 /*
  * Reset post-kexec EPC pages to the uninitialized state. The pages are removed
  * from the input list, and made available for the page allocator. SECS pages
@@ -786,6 +835,7 @@ static bool __init sgx_page_cache_init(void)
 	u64 pa, size;
 	int nid;
 	int i;
+	u64 total_epc_bytes = 0;
 
 	sgx_numa_nodes = kmalloc_array(num_possible_nodes(), sizeof(*sgx_numa_nodes), GFP_KERNEL);
 	if (!sgx_numa_nodes)
@@ -830,6 +880,7 @@ static bool __init sgx_page_cache_init(void)
 
 		sgx_epc_sections[i].node =  &sgx_numa_nodes[nid];
 		sgx_numa_nodes[nid].size += size;
+		total_epc_bytes += size;
 
 		sgx_nr_epc_sections++;
 	}
@@ -839,6 +890,19 @@ static bool __init sgx_page_cache_init(void)
 		return false;
 	}
 
+	if (sgx_overcommit_percent >= 0) {
+		u64 available_backing_bytes;
+
+		available_backing_bytes =
+			total_epc_bytes * (sgx_overcommit_percent / 100);
+
+		atomic_long_set(&sgx_nr_available_backing_pages,
+				available_backing_bytes >> PAGE_SHIFT);
+	} else {
+		pr_info("Disabling overcommit limit.\n");
+		sgx_disable_overcommit_tracking = true;
+	}
+
 	return true;
 }
 
diff --git a/arch/x86/kernel/cpu/sgx/sgx.h b/arch/x86/kernel/cpu/sgx/sgx.h
index 0f17def9fe6f..3507a9983fc1 100644
--- a/arch/x86/kernel/cpu/sgx/sgx.h
+++ b/arch/x86/kernel/cpu/sgx/sgx.h
@@ -89,6 +89,8 @@ void sgx_free_epc_page(struct sgx_epc_page *page);
 void sgx_mark_page_reclaimable(struct sgx_epc_page *page);
 int sgx_unmark_page_reclaimable(struct sgx_epc_page *page);
 struct sgx_epc_page *sgx_alloc_epc_page(void *owner, bool reclaim);
+int sgx_charge_mem(void);
+void sgx_uncharge_mem(void);
 
 #ifdef CONFIG_X86_SGX_KVM
 int __init sgx_vepc_init(void);
