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
					
				|  | @ -17,6 +17,7 @@ | ||||||
| #include <linux/libfdt.h> | #include <linux/libfdt.h> | ||||||
| #include <mapmem.h> | #include <mapmem.h> | ||||||
| #include <asm/io.h> | #include <asm/io.h> | ||||||
|  | #include <tee/optee.h> | ||||||
| 
 | 
 | ||||||
| #ifndef CONFIG_SYS_FDT_PAD | #ifndef CONFIG_SYS_FDT_PAD | ||||||
| #define CONFIG_SYS_FDT_PAD 0x3000 | #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 */ | 	/* Delete the old LMB reservation */ | ||||||
| 	if (lmb) | 	if (lmb) | ||||||
| 		lmb_free(lmb, (phys_addr_t)(u32)(uintptr_t)blob, | 		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 | #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 */ | #endif /* _OPTEE_H */ | ||||||
|  |  | ||||||
|  | @ -5,6 +5,8 @@ | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| #include <common.h> | #include <common.h> | ||||||
|  | #include <malloc.h> | ||||||
|  | #include <linux/libfdt.h> | ||||||
| #include <tee/optee.h> | #include <tee/optee.h> | ||||||
| 
 | 
 | ||||||
| #define optee_hdr_err_msg \ | #define optee_hdr_err_msg \ | ||||||
|  | @ -63,3 +65,141 @@ error: | ||||||
| 
 | 
 | ||||||
| 	return ret; | 	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 New Issue