diff --git a/cmd/bootefi.c b/cmd/bootefi.c
index 2a7d42925d..6618335ddf 100644
--- a/cmd/bootefi.c
+++ b/cmd/bootefi.c
@@ -332,6 +332,14 @@ efi_status_t efi_install_fdt(void *fdt)
 
 	efi_try_purge_kaslr_seed(fdt);
 
+	if (CONFIG_IS_ENABLED(EFI_TCG2_PROTOCOL_MEASURE_DTB)) {
+		ret = efi_tcg2_measure_dtb(fdt);
+		if (ret == EFI_SECURITY_VIOLATION) {
+			log_err("ERROR: failed to measure DTB\n");
+			return ret;
+		}
+	}
+
 	/* Install device tree as UEFI table */
 	ret = efi_install_configuration_table(&efi_guid_fdt, fdt);
 	if (ret != EFI_SUCCESS) {
diff --git a/include/efi_loader.h b/include/efi_loader.h
index 4560b0d04c..4ecfdf919b 100644
--- a/include/efi_loader.h
+++ b/include/efi_loader.h
@@ -531,6 +531,8 @@ efi_status_t efi_tcg2_notify_exit_boot_services_failed(void);
 efi_status_t efi_tcg2_measure_efi_app_invocation(struct efi_loaded_image_obj *handle);
 /* Measure efi application exit */
 efi_status_t efi_tcg2_measure_efi_app_exit(void);
+/* Measure DTB */
+efi_status_t efi_tcg2_measure_dtb(void *dtb);
 /* Called by bootefi to initialize root node */
 efi_status_t efi_root_node_register(void);
 /* Called by bootefi to initialize runtime */
diff --git a/include/efi_tcg2.h b/include/efi_tcg2.h
index 874306dc11..b1c3abd097 100644
--- a/include/efi_tcg2.h
+++ b/include/efi_tcg2.h
@@ -233,6 +233,16 @@ struct efi_gpt_data {
 	gpt_entry partitions[];
 } __packed;
 
+/**
+ * struct tdUEFI_PLATFORM_FIRMWARE_BLOB2
+ * @blob_description_size:	Byte size of @data
+ * @data:			Description data
+ */
+struct uefi_platform_firmware_blob2 {
+	u8 blob_description_size;
+	u8 data[];
+} __packed;
+
 struct efi_tcg2_protocol {
 	efi_status_t (EFIAPI * get_capability)(struct efi_tcg2_protocol *this,
 					       struct efi_tcg2_boot_service_capability *capability);
diff --git a/include/tpm-v2.h b/include/tpm-v2.h
index 737e57551d..2df3dad553 100644
--- a/include/tpm-v2.h
+++ b/include/tpm-v2.h
@@ -105,6 +105,8 @@ struct udevice;
 	"Exit Boot Services Returned with Failure"
 #define EFI_EXIT_BOOT_SERVICES_SUCCEEDED    \
 	"Exit Boot Services Returned with Success"
+#define EFI_DTB_EVENT_STRING \
+	"DTB DATA"
 
 /* TPMS_TAGGED_PROPERTY Structure */
 struct tpms_tagged_property {
diff --git a/lib/efi_loader/Kconfig b/lib/efi_loader/Kconfig
index c56904afc2..c05a54df16 100644
--- a/lib/efi_loader/Kconfig
+++ b/lib/efi_loader/Kconfig
@@ -346,6 +346,17 @@ config EFI_TCG2_PROTOCOL_EVENTLOG_SIZE
 		this is going to be allocated twice. One for the eventlog it self
 		and one for the configuration table that is required from the spec
 
+config EFI_TCG2_PROTOCOL_MEASURE_DTB
+	bool "Measure DTB with EFI_TCG2_PROTOCOL"
+	depends on EFI_TCG2_PROTOCOL
+	help
+	  When enabled, the DTB image passed to the booted EFI image is
+	  measured using the EFI TCG2 protocol. Do not enable this feature if
+	  the passed DTB contains data that change across platform reboots
+	  and cannot be used has a predictable measurement. Otherwise
+	  this feature allows better measurement of the system boot
+	  sequence.
+
 config EFI_LOAD_FILE2_INITRD
 	bool "EFI_FILE_LOAD2_PROTOCOL for Linux initial ramdisk"
 	default y
diff --git a/lib/efi_loader/efi_tcg2.c b/lib/efi_loader/efi_tcg2.c
index 918e9a2686..2dcc317157 100644
--- a/lib/efi_loader/efi_tcg2.c
+++ b/lib/efi_loader/efi_tcg2.c
@@ -2175,6 +2175,79 @@ out1:
 	return ret;
 }
 
+/* Return the byte size of reserved map area in DTB or -1 upon error */
+static ssize_t size_of_rsvmap(void *dtb)
+{
+	struct fdt_reserve_entry e;
+	ssize_t size_max;
+	ssize_t size;
+	u8 *rsvmap_base;
+
+	rsvmap_base = (u8 *)dtb + fdt_off_mem_rsvmap(dtb);
+	size_max = fdt_totalsize(dtb) - fdt_off_mem_rsvmap(dtb);
+	size = 0;
+
+	do {
+		memcpy(&e, rsvmap_base + size, sizeof(e));
+		size += sizeof(e);
+		if (size > size_max)
+			return -1;
+	} while (e.size);
+
+	return size;
+}
+
+/**
+ * efi_tcg2_measure_dtb() - measure DTB passed to the OS
+ *
+ * @dtb: pointer to the device tree blob
+ *
+ * Return:	status code
+ */
+efi_status_t efi_tcg2_measure_dtb(void *dtb)
+{
+	struct uefi_platform_firmware_blob2 *blob;
+	struct fdt_header *header;
+	sha256_context hash_ctx;
+	struct udevice *dev;
+	ssize_t rsvmap_size;
+	efi_status_t ret;
+	u32 event_size;
+
+	if (!is_tcg2_protocol_installed())
+		return EFI_SUCCESS;
+
+	ret = platform_get_tpm2_device(&dev);
+	if (ret != EFI_SUCCESS)
+		return EFI_SECURITY_VIOLATION;
+
+	rsvmap_size = size_of_rsvmap(dtb);
+	if (rsvmap_size < 0)
+		return EFI_SECURITY_VIOLATION;
+
+	event_size = sizeof(*blob) + sizeof(EFI_DTB_EVENT_STRING) + SHA256_SUM_LEN;
+	blob = calloc(1, event_size);
+	if (!blob)
+		return EFI_OUT_OF_RESOURCES;
+
+	blob->blob_description_size = sizeof(EFI_DTB_EVENT_STRING);
+	memcpy(blob->data, EFI_DTB_EVENT_STRING, blob->blob_description_size);
+
+	/* Measure populated areas of the DTB */
+	header = dtb;
+	sha256_starts(&hash_ctx);
+	sha256_update(&hash_ctx, (u8 *)header, sizeof(struct fdt_header));
+	sha256_update(&hash_ctx, (u8 *)dtb + fdt_off_dt_struct(dtb), fdt_size_dt_strings(dtb));
+	sha256_update(&hash_ctx, (u8 *)dtb + fdt_off_dt_strings(dtb), fdt_size_dt_struct(dtb));
+	sha256_update(&hash_ctx, (u8 *)dtb + fdt_off_mem_rsvmap(dtb), rsvmap_size);
+	sha256_finish(&hash_ctx, blob->data + blob->blob_description_size);
+
+	ret = tcg2_measure_event(dev, 0, EV_POST_CODE, event_size, (u8 *)blob);
+
+	free(blob);
+	return ret;
+}
+
 /**
  * efi_tcg2_measure_efi_app_invocation() - measure efi app invocation
  *
