image: fdt: copy possible optee nodes to a loaded

A patch from »fdtdec: protect against another NULL phandlep in« in state Mainline for u-boot

From: Heiko Stuebner <heiko@...> Date: Tue, 8 Oct 2019 01:10:02 +0200

Commit-Message

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@...>

Patch-Comment

This goes together with my bl32 work for the spl_atf loader in https://patchwork.ozlabs.org/patch/1172565/ common/image-fdt.c | 8 ++++ include/tee/optee.h | 9 ++++ lib/optee/optee.c | 112 ++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 129 insertions(+)

Statistics

  • 129 lines added
  • 0 lines removed

Changes

------------------------------ common/image-fdt.c ------------------------------
index 4247dcee0c..48388488d9 100644
@@ -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,
----------------------------- include/tee/optee.h ------------------------------
index 9446928fd4..121b30a303 100644
@@ -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 */
------------------------------ lib/optee/optee.c -------------------------------
index db92cd9af2..f484b12e67 100644
@@ -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,113 @@ error:
return ret;
}
+
+#if defined(CONFIG_OF_LIBFDT)
+static int optee_add_firmware_node(void *fdt_blob)
+{
+ int offs, ret;
+
+ if (fdt_path_offset(fdt_blob, "/firmware/optee") >= 0) {
+ debug("OP-TEE Device Tree node already exists");
+ return 0;
+ }
+
+ 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;
+
+ ret = fdt_setprop_string(fdt_blob, offs, "compatible",
+ "linaro,optee-tz");
+ if (ret < 0)
+ return ret;
+
+ ret = fdt_setprop_string(fdt_blob, offs, "method", "smc");
+ 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;
+
+ /* 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;
+ }
+
+ ret = optee_add_firmware_node(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
 
 

Recent Patches

About Us

Sed lacus. Donec lectus. Nullam pretium nibh ut turpis. Nam bibendum. In nulla tortor, elementum vel, tempor at, varius non, purus. Mauris vitae nisl nec metus placerat consectetuer.

Read More...