From bbe285c305e26d2944c38ea17c44c605b3289e25 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Thu, 20 Oct 2022 18:23:04 -0600 Subject: [PATCH] image: Allow loading a FIT image for a particular phase Add support for filtering out FIT images by phase. Rather than adding yet another argument to this already overloaded function, use a composite value, where the phase is only added in if needed. The FIT config is still selected (and verified) as normal, but the images are selected based on the phase. Tests for this come in a little later, as part of the updated VPL test. Signed-off-by: Simon Glass --- boot/image-fit.c | 83 +++++++++++++++++++++++++++++++++++----- doc/uImage.FIT/howto.txt | 6 +++ include/image.h | 12 +++--- 3 files changed, 86 insertions(+), 15 deletions(-) diff --git a/boot/image-fit.c b/boot/image-fit.c index 02f1d28c77..3cc556b727 100644 --- a/boot/image-fit.c +++ b/boot/image-fit.c @@ -802,6 +802,40 @@ int fit_image_get_comp(const void *fit, int noffset, uint8_t *comp) return 0; } +/** + * fit_image_get_phase() - get the phase for a configuration node + * @fit: pointer to the FIT format image header + * @offset: configuration-node offset + * @phasep: returns the phase + * + * Finds the phase property in a given configuration node. If the property is + * found, its (string) value is translated to the numeric id which is returned + * to the caller. + * + * Returns: 0 on success, -ENOENT if missing, -EINVAL for invalid value + */ +int fit_image_get_phase(const void *fit, int offset, enum image_phase_t *phasep) +{ + const void *data; + int len, ret; + + /* Get phase name from property data */ + data = fdt_getprop(fit, offset, FIT_PHASE_PROP, &len); + if (!data) { + fit_get_debug(fit, offset, FIT_PHASE_PROP, len); + *phasep = 0; + return -ENOENT; + } + + /* Translate phase name to id */ + ret = genimg_get_phase_id(data); + if (ret < 0) + return ret; + *phasep = ret; + + return 0; +} + static int fit_image_get_address(const void *fit, int noffset, char *name, ulong *load) { @@ -1867,10 +1901,37 @@ int fit_conf_get_prop_node_index(const void *fit, int noffset, return fit_image_get_node(fit, uname); } -int fit_conf_get_prop_node(const void *fit, int noffset, - const char *prop_name) +int fit_conf_get_prop_node(const void *fit, int noffset, const char *prop_name, + enum image_phase_t sel_phase) { - return fit_conf_get_prop_node_index(fit, noffset, prop_name, 0); + int i, count; + + if (sel_phase == IH_PHASE_NONE) + return fit_conf_get_prop_node_index(fit, noffset, prop_name, 0); + + count = fit_conf_get_prop_node_count(fit, noffset, prop_name); + if (count < 0) + return count; + + /* check each image in the list */ + for (i = 0; i < count; i++) { + enum image_phase_t phase; + int ret, node; + + node = fit_conf_get_prop_node_index(fit, noffset, prop_name, i); + ret = fit_image_get_phase(fit, node, &phase); + + /* if the image is for any phase, let's use it */ + if (ret == -ENOENT) + return node; + else if (ret < 0) + return ret; + + if (phase == sel_phase) + return node; + } + + return -ENOENT; } static int fit_get_data_tail(const void *fit, int noffset, @@ -1906,7 +1967,8 @@ int fit_get_data_conf_prop(const void *fit, const char *prop_name, { int noffset = fit_conf_get_node(fit, NULL); - noffset = fit_conf_get_prop_node(fit, noffset, prop_name); + noffset = fit_conf_get_prop_node(fit, noffset, prop_name, + IH_PHASE_NONE); return fit_get_data_tail(fit, noffset, data, size); } @@ -1944,7 +2006,8 @@ int fit_get_node_from_config(struct bootm_headers *images, return -EINVAL; } - noffset = fit_conf_get_prop_node(fit_hdr, cfg_noffset, prop_name); + noffset = fit_conf_get_prop_node(fit_hdr, cfg_noffset, prop_name, + IH_PHASE_NONE); if (noffset < 0) { debug("* %s: no '%s' in config\n", prop_name, prop_name); return -ENOENT; @@ -1990,9 +2053,10 @@ static const char *fit_get_image_type_property(int type) int fit_image_load(struct bootm_headers *images, ulong addr, const char **fit_unamep, const char **fit_uname_configp, - int arch, int image_type, int bootstage_id, + int arch, int ph_type, int bootstage_id, enum fit_load_op load_op, ulong *datap, ulong *lenp) { + int image_type = image_ph_type(ph_type); int cfg_noffset, noffset; const char *fit_uname; const char *fit_uname_config; @@ -2038,8 +2102,7 @@ int fit_image_load(struct bootm_headers *images, ulong addr, if (IS_ENABLED(CONFIG_FIT_BEST_MATCH) && !fit_uname_config) { cfg_noffset = fit_conf_find_compat(fit, gd_fdt_blob()); } else { - cfg_noffset = fit_conf_get_node(fit, - fit_uname_config); + cfg_noffset = fit_conf_get_node(fit, fit_uname_config); } if (cfg_noffset < 0) { puts("Could not find configuration node\n"); @@ -2067,8 +2130,8 @@ int fit_image_load(struct bootm_headers *images, ulong addr, bootstage_mark(BOOTSTAGE_ID_FIT_CONFIG); - noffset = fit_conf_get_prop_node(fit, cfg_noffset, - prop_name); + noffset = fit_conf_get_prop_node(fit, cfg_noffset, prop_name, + image_ph_phase(ph_type)); fit_uname = fit_get_name(fit, noffset, NULL); } if (noffset < 0) { diff --git a/doc/uImage.FIT/howto.txt b/doc/uImage.FIT/howto.txt index 019dda24a0..6dbd17dc8c 100644 --- a/doc/uImage.FIT/howto.txt +++ b/doc/uImage.FIT/howto.txt @@ -70,6 +70,12 @@ The SPL also records to a DT all additional images (called loadables) which are loaded. The information about loadables locations is passed via the DT node with fit-images name. +Finally, if there are multiple xPL phases (e.g. SPL, VPL), images can be marked +as intended for a particular phase using the 'phase' property. For example, if +fit_image_load() is called with image_ph(IH_PHASE_SPL, IH_TYPE_FIRMWARE), then +only the image listed into the "firmware" property where phase is set to "spl" +will be loaded. + Loadables Example ----------------- Consider the following case for an ARM64 platform where U-Boot runs in EL2 diff --git a/include/image.h b/include/image.h index 7c3dcc407c..65d0d4f438 100644 --- a/include/image.h +++ b/include/image.h @@ -691,9 +691,10 @@ int boot_get_fdt_fit(struct bootm_headers *images, ulong addr, * name (e.g. "conf-1") or NULL to use the default. On * exit points to the selected configuration name. * @param arch Expected architecture (IH_ARCH_...) - * @param image_type Required image type (IH_TYPE_...). If this is + * @param image_ph_type Required image type (IH_TYPE_...). If this is * IH_TYPE_KERNEL then we allow IH_TYPE_KERNEL_NOLOAD - * also. + * also. If a phase is required, this is included also, + * see image_phase_and_type() * @param bootstage_id ID of starting bootstage to use for progress updates. * This will be added to the BOOTSTAGE_SUB values when * calling bootstage_mark() @@ -704,7 +705,7 @@ int boot_get_fdt_fit(struct bootm_headers *images, ulong addr, */ int fit_image_load(struct bootm_headers *images, ulong addr, const char **fit_unamep, const char **fit_uname_configp, - int arch, int image_type, int bootstage_id, + int arch, int image_ph_type, int bootstage_id, enum fit_load_op load_op, ulong *datap, ulong *lenp); /** @@ -1349,14 +1350,15 @@ int fit_conf_get_prop_node_index(const void *fit, int noffset, * @fit: FIT to check * @noffset: Offset of conf@xxx node to check * @prop_name: Property to read from the conf node + * @phase: Image phase to use, IH_PHASE_NONE for any * * The conf- nodes contain references to other nodes, using properties * like 'kernel = "kernel"'. Given such a property name (e.g. "kernel"), * return the offset of the node referred to (e.g. offset of node * "/images/kernel". */ -int fit_conf_get_prop_node(const void *fit, int noffset, - const char *prop_name); +int fit_conf_get_prop_node(const void *fit, int noffset, const char *prop_name, + enum image_phase_t phase); int fit_check_ramdisk(const void *fit, int os_noffset, uint8_t arch, int verify); -- 2.39.5