[U-Boot,v3,3/4] image: fdt: copy possible optee nodes to a loaded devicetree
diff mbox series

Message ID 20191023144641.5710-3-heiko@sntech.de
State Accepted
Commit 6ccb05eae01b660b0585accf338302af1069f419
Delegated to: Simon Glass
Headers show
Series
  • [U-Boot,v3,1/4] fdtdec: protect against another NULL phandlep in fdtdec_add_reserved_memory()
Related show

Commit Message

Heiko Stuebner Oct. 23, 2019, 2:46 p.m. UTC
From: Heiko Stuebner <heiko.stuebner@theobroma-systems.com>

The loading convention for optee or any other tee on arm64 is as bl32
parameter to the trusted-firmware. So TF-A gets invoked with the TEE as
bl32 and main u-boot as bl33. Once it has done its startup TF-A jumps
into the bl32 for the TEE startup, returns to TF-A and then jumps to bl33.

All of them get passed a devicetree as parameter and all components often
get loaded from a FIT image.

OP-TEE will create additional nodes in that devicetree namely a firmware
node and possibly multiple reserved-memory nodes.

While this devicetree is used in main u-boot, in most cases it won't be
the one passed to the actual kernel. Instead most boot commands will load
a new devicetree from somewhere like mass storage of the network, so if
that happens u-boot should transfer the optee nodes to that new devicetree.

To make that happen introduce optee_copy_fdt_nodes() called from the dt
setup function in image-fdt which after checking for the optee presence
in the u-boot dt will make sure a optee node is present in the kernel dt
and transfer any reserved-memory regions it can find.

Signed-off-by: Heiko Stuebner <heiko.stuebner@theobroma-systems.com>
Reviewed-by: Jens Wiklander <jens.wiklander@linaro.org>
---
changes in v2:
- don't create a new optee firmware-node, but instead copy the
  compatible+method properties from the old fdt blob.
changes in v3:
- move check for pre-existing optee node into main function
  If the kernel-dts already contains optee nodes, we probably
  want to leave it _completely_ alone

 common/image-fdt.c  |   8 +++
 include/tee/optee.h |   9 +++
 lib/optee/optee.c   | 140 ++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 157 insertions(+)

Comments

Simon Glass Nov. 14, 2019, 1:43 p.m. UTC | #1
On Wed, 23 Oct 2019 at 09:47, Heiko Stuebner <heiko@sntech.de> wrote:
>
> From: Heiko Stuebner <heiko.stuebner@theobroma-systems.com>
>
> The loading convention for optee or any other tee on arm64 is as bl32
> parameter to the trusted-firmware. So TF-A gets invoked with the TEE as
> bl32 and main u-boot as bl33. Once it has done its startup TF-A jumps
> into the bl32 for the TEE startup, returns to TF-A and then jumps to bl33.
>
> All of them get passed a devicetree as parameter and all components often
> get loaded from a FIT image.
>
> OP-TEE will create additional nodes in that devicetree namely a firmware
> node and possibly multiple reserved-memory nodes.
>
> While this devicetree is used in main u-boot, in most cases it won't be
> the one passed to the actual kernel. Instead most boot commands will load
> a new devicetree from somewhere like mass storage of the network, so if
> that happens u-boot should transfer the optee nodes to that new devicetree.
>
> To make that happen introduce optee_copy_fdt_nodes() called from the dt
> setup function in image-fdt which after checking for the optee presence
> in the u-boot dt will make sure a optee node is present in the kernel dt
> and transfer any reserved-memory regions it can find.
>
> Signed-off-by: Heiko Stuebner <heiko.stuebner@theobroma-systems.com>
> Reviewed-by: Jens Wiklander <jens.wiklander@linaro.org>
> ---
> changes in v2:
> - don't create a new optee firmware-node, but instead copy the
>   compatible+method properties from the old fdt blob.
> changes in v3:
> - move check for pre-existing optee node into main function
>   If the kernel-dts already contains optee nodes, we probably
>   want to leave it _completely_ alone
>
>  common/image-fdt.c  |   8 +++
>  include/tee/optee.h |   9 +++
>  lib/optee/optee.c   | 140 ++++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 157 insertions(+)
>

Applied to u-boot-dm, thanks!

Patch
diff mbox series

diff --git a/common/image-fdt.c b/common/image-fdt.c
index 4247dcee0c..48388488d9 100644
--- a/common/image-fdt.c
+++ b/common/image-fdt.c
@@ -17,6 +17,7 @@ 
 #include <linux/libfdt.h>
 #include <mapmem.h>
 #include <asm/io.h>
+#include <tee/optee.h>
 
 #ifndef CONFIG_SYS_FDT_PAD
 #define CONFIG_SYS_FDT_PAD 0x3000
@@ -561,6 +562,13 @@  int image_setup_libfdt(bootm_headers_t *images, void *blob,
 		}
 	}
 
+	fdt_ret = optee_copy_fdt_nodes(gd->fdt_blob, blob);
+	if (fdt_ret) {
+		printf("ERROR: transfer of optee nodes to new fdt failed: %s\n",
+		       fdt_strerror(fdt_ret));
+		goto err;
+	}
+
 	/* Delete the old LMB reservation */
 	if (lmb)
 		lmb_free(lmb, (phys_addr_t)(u32)(uintptr_t)blob,
diff --git a/include/tee/optee.h b/include/tee/optee.h
index 9446928fd4..121b30a303 100644
--- a/include/tee/optee.h
+++ b/include/tee/optee.h
@@ -67,4 +67,13 @@  static inline int optee_verify_bootm_image(unsigned long image_addr,
 }
 #endif
 
+#if defined(CONFIG_OPTEE) && defined(CONFIG_OF_LIBFDT)
+int optee_copy_fdt_nodes(const void *old_blob, void *new_blob);
+#else
+static inline int optee_copy_fdt_nodes(const void *old_blob, void *new_blob)
+{
+	return 0;
+}
+#endif
+
 #endif /* _OPTEE_H */
diff --git a/lib/optee/optee.c b/lib/optee/optee.c
index db92cd9af2..c883c498e1 100644
--- a/lib/optee/optee.c
+++ b/lib/optee/optee.c
@@ -5,6 +5,8 @@ 
  */
 
 #include <common.h>
+#include <malloc.h>
+#include <linux/libfdt.h>
 #include <tee/optee.h>
 
 #define optee_hdr_err_msg \
@@ -63,3 +65,141 @@  error:
 
 	return ret;
 }
+
+#if defined(CONFIG_OF_LIBFDT)
+static int optee_copy_firmware_node(const void *old_blob, void *fdt_blob)
+{
+	int old_offs, offs, ret, len;
+	const void *prop;
+
+	old_offs = fdt_path_offset(old_blob, "/firmware/optee");
+	if (old_offs < 0) {
+		debug("Original OP-TEE Device Tree node not found");
+		return old_offs;
+	}
+
+	offs = fdt_path_offset(fdt_blob, "/firmware");
+	if (offs < 0) {
+		offs = fdt_path_offset(fdt_blob, "/");
+		if (offs < 0)
+			return offs;
+
+		offs = fdt_add_subnode(fdt_blob, offs, "firmware");
+		if (offs < 0)
+			return offs;
+	}
+
+	offs = fdt_add_subnode(fdt_blob, offs, "optee");
+	if (offs < 0)
+		return ret;
+
+	/* copy the compatible property */
+	prop = fdt_getprop(old_blob, old_offs, "compatible", &len);
+	if (!prop) {
+		debug("missing OP-TEE compatible property");
+		return -EINVAL;
+	}
+
+	ret = fdt_setprop(fdt_blob, offs, "compatible", prop, len);
+	if (ret < 0)
+		return ret;
+
+	/* copy the method property */
+	prop = fdt_getprop(old_blob, old_offs, "method", &len);
+	if (!prop) {
+		debug("missing OP-TEE method property");
+		return -EINVAL;
+	}
+
+	ret = fdt_setprop(fdt_blob, offs, "method", prop, len);
+	if (ret < 0)
+		return ret;
+
+	return 0;
+}
+
+int optee_copy_fdt_nodes(const void *old_blob, void *new_blob)
+{
+	int nodeoffset, subnode, ret;
+	struct fdt_resource res;
+
+	if (fdt_check_header(old_blob))
+		return -EINVAL;
+
+	if (fdt_check_header(new_blob))
+		return -EINVAL;
+
+	/* only proceed if there is an /firmware/optee node */
+	if (fdt_path_offset(old_blob, "/firmware/optee") < 0) {
+		debug("No OP-TEE firmware node in old fdt, nothing to do");
+		return 0;
+	}
+
+	/*
+	 * Do not proceed if the target dt already has an OP-TEE node.
+	 * In this case assume that the system knows better somehow,
+	 * so do not interfere.
+	 */
+	if (fdt_path_offset(new_blob, "/firmware/optee") >= 0) {
+		debug("OP-TEE Device Tree node already exists in target");
+		return 0;
+	}
+
+	ret = optee_copy_firmware_node(old_blob, new_blob);
+	if (ret < 0) {
+		printf("Failed to add OP-TEE firmware node\n");
+		return ret;
+	}
+
+	/* optee inserts its memory regions as reserved-memory nodes */
+	nodeoffset = fdt_subnode_offset(old_blob, 0, "reserved-memory");
+	if (nodeoffset >= 0) {
+		subnode = fdt_first_subnode(old_blob, nodeoffset);
+		while (subnode >= 0) {
+			const char *name = fdt_get_name(old_blob,
+							subnode, NULL);
+			if (!name)
+				return -EINVAL;
+
+			/* only handle optee reservations */
+			if (strncmp(name, "optee", 5))
+				continue;
+
+			/* check if this subnode has a reg property */
+			ret = fdt_get_resource(old_blob, subnode, "reg", 0,
+					       &res);
+			if (!ret) {
+				struct fdt_memory carveout = {
+					.start = res.start,
+					.end = res.end,
+				};
+				char *oldname, *nodename, *tmp;
+
+				oldname = strdup(name);
+				if (!oldname)
+					return -ENOMEM;
+
+				tmp = oldname;
+				nodename = strsep(&tmp, "@");
+				if (!nodename) {
+					free(oldname);
+					return -EINVAL;
+				}
+
+				ret = fdtdec_add_reserved_memory(new_blob,
+								 nodename,
+								 &carveout,
+								 NULL);
+				free(oldname);
+
+				if (ret < 0)
+					return ret;
+			}
+
+			subnode = fdt_next_subnode(old_blob, subnode);
+		}
+	}
+
+	return 0;
+}
+#endif