mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-24 13:43:28 +00:00
image: fdt: copy possible optee nodes to a loaded devicetree
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>
This commit is contained in:
parent
357d2ceba0
commit
6ccb05eae0
3 changed files with 157 additions and 0 deletions
|
@ -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,
|
||||
|
|
|
@ -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 */
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue