diff --git a/include/efi_api.h b/include/efi_api.h
index 48e48a6263..f4a88603e9 100644
--- a/include/efi_api.h
+++ b/include/efi_api.h
@@ -1722,6 +1722,23 @@ struct efi_load_file_protocol {
 					 void *buffer);
 };
 
+struct efi_system_resource_entry {
+	efi_guid_t fw_class;
+	uint32_t fw_type;
+	uint32_t fw_version;
+	uint32_t lowest_supported_fw_version;
+	uint32_t capsule_flags;
+	uint32_t last_attempt_version;
+	uint32_t last_attempt_status;
+} __attribute__((__packed__));
+
+struct efi_system_resource_table {
+	uint32_t fw_resource_count;
+	uint32_t fw_resource_count_max;
+	uint64_t fw_resource_version;
+	struct efi_system_resource_entry entries[];
+} __attribute__((__packed__));
+
 /* Boot manager load options */
 #define LOAD_OPTION_ACTIVE		0x00000001
 #define LOAD_OPTION_FORCE_RECONNECT	0x00000002
@@ -1740,6 +1757,10 @@ struct efi_load_file_protocol {
 #define ESRT_FW_TYPE_DEVICEFIRMWARE	0x00000002
 #define ESRT_FW_TYPE_UEFIDRIVER		0x00000003
 
+#define EFI_SYSTEM_RESOURCE_TABLE_GUID\
+	EFI_GUID(0xb122a263, 0x3661, 0x4f68,\
+		0x99, 0x29, 0x78, 0xf8, 0xb0, 0xd6, 0x21, 0x80 )
+
 /* Last Attempt Status Values */
 #define LAST_ATTEMPT_STATUS_SUCCESS			0x00000000
 #define LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL		0x00000001
diff --git a/include/efi_loader.h b/include/efi_loader.h
index f470bbd636..7b20ec1ad2 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -884,4 +884,26 @@ static inline efi_status_t efi_launch_capsules(void)
 
 #endif /* CONFIG_IS_ENABLED(EFI_LOADER) */
 
+/*
+ * Install the ESRT system table.
+ *
+ * @return	status code
+ */
+efi_status_t efi_esrt_register(void);
+
+/**
+ * esrt_add_from_fmp() - Populates a sequence of ESRT entries from the FW
+ * images in the FMP.
+ *
+ * @fmp:        the fmp from which fw images are added to the ESRT
+ * @image_type: the type of the FW image in the ESRT entry
+ * @flags:      the capsule flags to be set in the ESRT entry
+ *
+ * Return:
+ * - EFI_SUCCESS if all the FW images in the FMP are added to the ESRT
+ * - Error status otherwise
+ */
+efi_status_t esrt_add_from_fmp(struct efi_firmware_management_protocol *fmp,
+	u32 image_type, u32 flags);
+
 #endif /* _EFI_LOADER_H */
diff --git a/lib/efi_loader/Makefile b/lib/efi_loader/Makefile
index 10b42e8847..dec791b310 100644
--- a/lib/efi_loader/Makefile
+++ b/lib/efi_loader/Makefile
@@ -52,6 +52,7 @@ obj-y += efi_variable.o
 obj-$(CONFIG_EFI_VARIABLES_PRESEED) += efi_var_seed.o
 endif
 obj-y += efi_watchdog.o
+obj-y += efi_esrt.o
 obj-$(CONFIG_LCD) += efi_gop.o
 obj-$(CONFIG_DM_VIDEO) += efi_gop.o
 obj-$(CONFIG_PARTITIONS) += efi_disk.o
diff --git a/lib/efi_loader/efi_boottime.c b/lib/efi_loader/efi_boottime.c
index ce658a8e73..8077b467c7 100644
--- a/lib/efi_loader/efi_boottime.c
+++ b/lib/efi_loader/efi_boottime.c
@@ -1150,6 +1150,18 @@ efi_status_t efi_add_protocol(const efi_handle_t handle,
 
 	if (!guidcmp(&efi_guid_device_path, protocol))
 		EFI_PRINT("installed device path '%pD'\n", protocol_interface);
+
+	if (!guidcmp(&efi_guid_firmware_management_protocol, protocol)) {
+		EFI_PRINT("installed FMP, updating ESRT entries\n");
+
+		ret = esrt_add_from_fmp((struct efi_firmware_management_protocol *)
+			protocol_interface, ESRT_FW_TYPE_UNKNOWN, 0);
+		if (ret != EFI_SUCCESS) {
+			EFI_PRINT("Failed to update FMP ESRT entries\n");
+			return ret;
+		}
+	}
+
 	return EFI_SUCCESS;
 }
 
diff --git a/lib/efi_loader/efi_esrt.c b/lib/efi_loader/efi_esrt.c
new file mode 100644
index 0000000000..c651ce6c73
--- /dev/null
+++ b/lib/efi_loader/efi_esrt.c
@@ -0,0 +1,294 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ *  EFI application ESRT tables support
+ *
+ *  Copyright (C) 2021 Arm Ltd.
+ */
+
+#include <common.h>
+#include <efi_loader.h>
+#include <log.h>
+#include <efi_api.h>
+#include <malloc.h>
+
+static const efi_guid_t esrt_guid = EFI_SYSTEM_RESOURCE_TABLE_GUID;
+static bool esrt_initialized;
+static struct efi_system_resource_table *esrt;
+
+#define EFI_ESRT_NUM_PAGES 1
+
+#define EFI_ESRT_SIZE (EFI_ESRT_NUM_PAGES * EFI_PAGE_SIZE)
+
+#define EFI_ESRT_ENTRIES_MAX ((EFI_ESRT_SIZE -             \
+	sizeof(struct efi_system_resource_table)) /    \
+	sizeof(struct efi_system_resource_entry))
+
+#define EFI_ESRT_VERSION 1
+
+/**
+ * esrt_image_info_to_entry() - copy the information present in a fw image
+ * descriptor to a ESRT entry.
+ *
+ * @img_info:     the source image info descriptor
+ * @entry:        pointer to the ESRT entry to be filled
+ * @desc_version: the version of the elements in img_info
+ * @image_type:   the image type value to be set in the ESRT entry
+ * @flags:        the capsule flags value to be set in the ESRT entry
+ *
+ */
+void
+esrt_image_info_to_entry(struct efi_firmware_image_descriptor *img_info,
+			 struct efi_system_resource_entry *entry,
+			 u32 desc_version, u32 image_type, u32 flags)
+{
+	guidcpy(&entry->fw_class, &img_info->image_type_id);
+	entry->fw_version = img_info->version;
+
+	entry->fw_type = image_type;
+	entry->capsule_flags = flags;
+
+	/*
+	 * The field lowest_supported_image_version is only present
+	 * on image info structure of version 2 or greater.
+	 * See the EFI_FIRMWARE_IMAGE_DESCRIPTOR definition in UEFI.
+	 */
+	if (desc_version >= 2) {
+		entry->lowest_supported_fw_version =
+			img_info->lowest_supported_image_version;
+	} else {
+		entry->lowest_supported_fw_version = 0;
+	}
+
+	/*
+	 * The fields last_attempt_version and last_attempt_status
+	 * are only present on image info structure of version 3 or
+	 * greater.
+	 * See the EFI_FIRMWARE_IMAGE_DESCRIPTOR definition in UEFI.
+	 */
+	if (desc_version >= 3) {
+		entry->last_attempt_version =
+			img_info->last_attempt_version;
+
+		entry->last_attempt_status =
+			img_info->last_attempt_status;
+	} else {
+		entry->last_attempt_version = 0;
+		entry->last_attempt_status = EFI_SUCCESS;
+	}
+}
+
+/**
+ * esrt_find_entry() - Obtain the ESRT entry for the image with guid
+ * img_fw_class.
+ *
+ * If the img_fw_class is not yet present in the ESRT, this function
+ * reserves the tail element of the current ESRT as the entry for that fw_clas.
+ * The number of elements in the ESRT is updated in that case.
+ *
+ * @fw_img_class: the guid of the fw image which ESRT entry we want to obtain.
+ *
+ * Return:
+ *  - a pointer to the ESRT entry for the image with guid img_fw_class,
+ *  - NULL if there is no more space in the ESRT.
+ */
+static
+struct efi_system_resource_entry *esrt_find_entry(efi_guid_t *img_fw_class)
+{
+	// if this function is called before the esrt init then it is erroneous
+	// behaviour.
+	assert(esrt_initialized);
+
+	const u32 filled_entries = esrt->fw_resource_count;
+	const u32 max_entries = esrt->fw_resource_count_max;
+	struct efi_system_resource_entry *entry = esrt->entries;
+
+	for (u32 idx; idx < filled_entries; idx++) {
+		if (!guidcmp(&entry[idx].fw_class, img_fw_class)) {
+			log_debug("EFI ESRT: found entry for image %pUl\n",
+				  img_fw_class);
+			return &entry[idx];
+		}
+	}
+
+	if (filled_entries == max_entries) {
+		log_warning("EFI ESRT: table is full\n");
+		return NULL;
+
+	} else {
+		/*
+		 * This is a new entry for a fw image, increment the element
+		 * number in the table and set the fw_class field.
+		 */
+		esrt->fw_resource_count++;
+		entry[filled_entries].fw_class = *img_fw_class;
+		return &entry[filled_entries];
+	}
+}
+
+/**
+ * esrt_add_from_fmp() - Populates a sequence of ESRT entries from the FW
+ * images in the FMP.
+ *
+ * @fmp:        the fmp from which fw images are added to the ESRT
+ * @image_type: the type of the FW image in the ESRT entry
+ * @flags:      the capsule flags to be set in the ESRT entry
+ *
+ * Return:
+ * - EFI_SUCCESS if all the FW images in the FMP are added to the ESRT
+ * - Error status otherwise
+ */
+efi_status_t esrt_add_from_fmp(struct efi_firmware_management_protocol *fmp,
+			       u32 image_type, u32 flags)
+{
+	struct efi_system_resource_entry *entry = NULL;
+	size_t info_size = 0;
+	struct efi_firmware_image_descriptor *img_info = NULL;
+	u32 desc_version;
+	u8 desc_count;
+	size_t desc_size;
+	efi_status_t ret = EFI_SUCCESS;
+
+	if (!esrt_initialized)
+		return EFI_NOT_READY;
+
+	ret = fmp->get_image_info(fmp, &info_size, img_info,
+			&desc_version, &desc_count,
+			&desc_size, NULL, NULL);
+
+	/*
+	 * An input of info_size=0 should always lead to BUFFER_TO_SMALL return
+	 * if this is not the case then the get_image_info implementation is
+	 * anoumalous, hence the assert.
+	 */
+	assert_noisy(ret == EFI_BUFFER_TOO_SMALL);
+
+	img_info = malloc(info_size);
+
+	ret = fmp->get_image_info(fmp, &info_size, img_info,
+			&desc_version, &desc_count,
+			&desc_size, NULL, NULL);
+	if (ret != EFI_SUCCESS) {
+		log_err("EFI ESRT: failed to obtain the FMP image info\n");
+		goto out;
+	}
+
+	/*
+	 * Iterate over all the FW images in the FMP.
+	 */
+	for (u32 desc_idx = 0; desc_idx < desc_count; desc_idx++) {
+		struct efi_firmware_image_descriptor *cur_img_info =
+			(struct efi_firmware_image_descriptor *)
+			((uintptr_t)img_info) + desc_idx * desc_size;
+
+		/*
+		 * Obtain the ESRT entry for the FW image with fw_class
+		 * equal to cur_img_info->image_type_id.
+		 */
+		entry = esrt_find_entry(&cur_img_info->image_type_id);
+
+		if (entry) {
+			esrt_image_info_to_entry(cur_img_info, entry,
+						 desc_version, image_type,
+						 flags);
+		} else {
+			log_err("EFI ESRT: failed to add esrt entry for %pUl\n",
+				&cur_img_info->image_type_id);
+			continue;
+		}
+	}
+
+out:
+	free(img_info);
+	return true;
+}
+
+/**
+ * esrt_populate() - Populates the ESRT entries from the FMP instances
+ * registered so far and performs basic initialization of the ESRT fields.
+ *
+ * Return:
+ * - true if ESRT initialized successfully.
+ * - false otherwise.
+ */
+static bool esrt_populate(void)
+{
+	efi_handle_t *handle = NULL;
+	size_t no_handles = 0;
+	struct efi_firmware_management_protocol *fmp;
+	efi_status_t ret;
+
+	esrt->fw_resource_count_max = EFI_ESRT_ENTRIES_MAX;
+	esrt->fw_resource_version = EFI_ESRT_VERSION;
+
+	esrt_initialized = true;
+
+	/*
+	 * Obtain the number of registered FMP handles.
+	 */
+	ret = EFI_CALL(efi_locate_handle_buffer(BY_PROTOCOL, &efi_guid_firmware_management_protocol,
+						NULL, &no_handles,
+						(efi_handle_t **)&handle));
+
+	if (ret != EFI_SUCCESS) {
+		log_warning("EFI ESRT: failed to obtain FMP handles (%lx)\n",
+			    ret);
+		return esrt_initialized;
+	}
+
+	log_debug("EFI ESRT: populate esrt from (%ld) avaialble FMP handles\n",
+		  no_handles);
+	/*
+	 * Populate the ESRT entries with any already existing FMP.
+	 */
+	for (u32 idx = 0; idx < no_handles; idx++, handle++) {
+		ret = EFI_CALL(efi_handle_protocol(*handle, &efi_guid_firmware_management_protocol,
+						   (void **)&fmp));
+		if (ret != EFI_SUCCESS) {
+			log_err("EFI ESRT: Unable to find FMP handle (%d)\n",
+				idx);
+			continue;
+		}
+
+		ret = esrt_add_from_fmp(fmp, ESRT_FW_TYPE_UNKNOWN, 0);
+		if (ret != EFI_SUCCESS) {
+			log_err("EFI ESRT: failed to add from FMP (%d)\n", idx);
+			continue;
+		}
+	}
+	return esrt_initialized;
+}
+
+/**
+ * efi_esrt_register() - Install the ESRT system table.
+ *
+ * @return	status code
+ */
+efi_status_t efi_esrt_register(void)
+{
+	esrt = (struct efi_system_resource_table *)(uintptr_t)U32_MAX;
+	efi_status_t ret;
+
+	log_debug("EFI ESRT: ESRT creation start\n");
+
+	/* Reserve pages for ESRT */
+	ret = efi_allocate_pages(EFI_ALLOCATE_MAX_ADDRESS,
+				 EFI_RUNTIME_SERVICES_DATA, EFI_ESRT_NUM_PAGES,
+		(uint64_t *)&esrt);
+
+	if (ret != EFI_SUCCESS)
+		return ret;
+
+	if (!esrt_populate())
+		log_warning("EFI ESRT: failed to initialize ESRT\n");
+
+	/* And expose them to our EFI payload */
+	ret = efi_install_configuration_table(&esrt_guid, (void *)esrt);
+	if (ret != EFI_SUCCESS) {
+		log_err("EFI ESRT: failed to create ESRT\n");
+		return ret;
+	}
+
+	log_debug("EFI ESRT: table created\n");
+
+	return ret;
+}
diff --git a/lib/efi_loader/efi_setup.c b/lib/efi_loader/efi_setup.c
index 5800cbf6d4..7660a20822 100644
--- a/lib/efi_loader/efi_setup.c
+++ b/lib/efi_loader/efi_setup.c
@@ -231,6 +231,10 @@ efi_status_t efi_init_obj_list(void)
 	if (ret != EFI_SUCCESS)
 		goto out;
 
+	ret = efi_esrt_register();
+	if (ret != EFI_SUCCESS)
+		goto out;
+
 	if (IS_ENABLED(CONFIG_EFI_TCG2_PROTOCOL)) {
 		ret = efi_tcg2_register();
 		if (ret != EFI_SUCCESS)
