aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTom Rini <trini@konsulko.com>2025-02-03 16:01:44 -0600
committerTom Rini <trini@konsulko.com>2025-02-03 16:01:44 -0600
commit3e69c75e86e1c32c8c0fd6153bcc10aa00fb3616 (patch)
tree676898552baf386cc0c4119ee4bf7edc1ba8aee0
parent752321b62530dcbd6e8b5872aff4cf761809d76b (diff)
parentf1eb367d76c9b28053b3adcb6bdeb865c6eda5fd (diff)
downloadu-boot-3e69c75e86e1c32c8c0fd6153bcc10aa00fb3616.tar.gz
Merge patch series "vbe: Series part G"WIP/03Feb2025
Simon Glass <sjg@chromium.org> says: This includes the VBE ABrec (A/B/recovery) implementation as well as a number of patches needed to make it work: - marking some code as used by SPL_RELOC - selection of images from a FIT based on the boot phase - removal of unwanted hash code which increases code-size too much - a few Kconfig-related additions for VPL Note: The goal for the next series (part H) is to enable VBE on rk3399-generic, i.e. able to boot on multiple rk3399-based boards with only the TPL phase being different for each board. Link: https://lore.kernel.org/r/20250126184333.4058848-1-sjg@chromium.org/
-rw-r--r--MAINTAINERS7
-rw-r--r--boot/Kconfig73
-rw-r--r--boot/Makefile4
-rw-r--r--boot/image-fit.c29
-rw-r--r--boot/vbe_abrec.c83
-rw-r--r--boot/vbe_abrec.h115
-rw-r--r--boot/vbe_abrec_fw.c276
-rw-r--r--boot/vbe_common.c24
-rw-r--r--boot/vbe_common.h43
-rw-r--r--common/hash.c17
-rw-r--r--common/spl/Kconfig.vpl13
-rw-r--r--common/spl/spl.c26
-rw-r--r--common/spl/spl_fit.c40
-rw-r--r--common/spl/spl_reloc.c2
-rw-r--r--configs/sandbox_vpl_defconfig2
-rw-r--r--drivers/mmc/dw_mmc.c4
-rw-r--r--include/asm-generic/sections.h16
-rw-r--r--include/spl.h19
-rw-r--r--include/spl_load.h9
-rw-r--r--include/vbe.h21
-rw-r--r--lib/Kconfig10
-rw-r--r--lib/Makefile13
-rw-r--r--lib/crc8.c5
-rw-r--r--lib/gunzip.c9
-rw-r--r--lib/lz4.c37
-rw-r--r--lib/lz4_wrapper.c2
-rw-r--r--lib/mbedtls/Kconfig40
-rw-r--r--lib/string.c5
-rw-r--r--lib/zlib/inflate.c18
-rw-r--r--tools/Kconfig5
30 files changed, 880 insertions, 87 deletions
diff --git a/MAINTAINERS b/MAINTAINERS
index 247f525847e..10f7f1fd180 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -1806,6 +1806,13 @@ M: Abdellatif El Khlifi <abdellatif.elkhlifi@arm.com>
S: Maintained
F: test/lib/uuid.c
+VBE
+M: Simon Glass <sjg@chromium.org>
+S: Maintained
+F: boot/vbe*
+F: common/spl_reloc.c
+F: include/vbe.h
+
VIDEO
M: Anatolij Gustschin <agust@denx.de>
S: Maintained
diff --git a/boot/Kconfig b/boot/Kconfig
index 20935a269c6..c09a98c3233 100644
--- a/boot/Kconfig
+++ b/boot/Kconfig
@@ -711,6 +711,20 @@ config BOOTMETH_VBE_SIMPLE
firmware image in boot media such as MMC. It does not support any sort
of rollback, recovery or A/B boot.
+config BOOTMETH_VBE_ABREC
+ bool "Bootdev support for VBE 'a/b/recovery' method"
+ imply SPL_CRC8
+ imply VPL_CRC8
+ help
+ Enables support for VBE 'abrec' boot. This allows updating one of an
+ A or B firmware image in boot media such as MMC. The new firmware is
+ tried and if it boots, it is copied to the other image, so that both
+ A and B have the same version. If neither firmware image passes the
+ verification step, a recovery image is booted. This method will
+ eventually provide rollback protection as well.
+
+if BOOTMETH_VBE_SIMPLE
+
config BOOTMETH_VBE_SIMPLE_OS
bool "Bootdev support for VBE 'simple' method OS phase"
default y
@@ -769,6 +783,65 @@ config TPL_BOOTMETH_VBE_SIMPLE_FW
endif # BOOTMETH_VBE_SIMPLE
+if BOOTMETH_VBE_ABREC
+
+config SPL_BOOTMETH_VBE_ABREC
+ bool "Bootdev support for VBE 'abrec' method (SPL)"
+ depends on SPL
+ default y if VPL
+ help
+ Enables support for VBE 'abrec' boot. The SPL part of this
+ implementation simply loads U-Boot from the image selected by the
+ VPL phase.
+
+config TPL_BOOTMETH_VBE_ABREC
+ bool "Bootdev support for VBE 'abrec' method (TPL)"
+ depends on TPL
+ select TPL_FIT
+ default y
+ help
+ Enables support for VBE 'abrec' boot. The TPL part of this
+ implementation simply jumps to VPL after device init is completed.
+
+config VPL_BOOTMETH_VBE_ABREC
+ bool "Bootdev support for VBE 'abrec' method (VPL)"
+ depends on VPL
+ default y
+ help
+ Enables support for VBE 'abrec' boot. The VPL part of this
+ implementation selects which SPL to use (A, B or recovery) and then
+ boots into SPL.
+
+config SPL_BOOTMETH_VBE_ABREC_FW
+ bool "Bootdev support for VBE 'abrec' method firmware phase (SPL)"
+ depends on SPL
+ default y if VPL
+ help
+ Enables support for VBE 'abrec' boot. The SPL part of this
+ implementation simply loads U-Boot from the image selected by the
+ VPL phase.
+
+config TPL_BOOTMETH_VBE_ABREC_FW
+ bool "Bootdev support for VBE 'abrec' method firmware phase (TPL)"
+ depends on TPL
+ default y if VPL
+ help
+ Enables support for VBE 'abrec' boot. The TPL part of this
+ implementation simply jumps to VPL after device init is completed.
+
+config VPL_BOOTMETH_VBE_ABREC_FW
+ bool "Bootdev support for VBE 'abrec' method firmware phase (VPL)"
+ depends on VPL
+ default y
+ help
+ Enables support for VBE 'abrec' boot. The VPL part of this
+ implementation selects which SPL to use (A, B or recovery) and then
+ boots into SPL.
+
+endif # BOOTMETH_VBE_ABREC
+
+endif # BOOTMETH_VBE
+
config EXPO
bool "Support for expos - groups of scenes displaying a UI"
depends on VIDEO
diff --git a/boot/Makefile b/boot/Makefile
index c2753de8163..34bac26c4e2 100644
--- a/boot/Makefile
+++ b/boot/Makefile
@@ -70,3 +70,7 @@ obj-$(CONFIG_$(PHASE_)BOOTMETH_VBE_SIMPLE_FW) += vbe_simple_fw.o
obj-$(CONFIG_$(PHASE_)BOOTMETH_VBE_SIMPLE_OS) += vbe_simple_os.o
obj-$(CONFIG_$(PHASE_)BOOTMETH_ANDROID) += bootmeth_android.o
+
+obj-$(CONFIG_$(PHASE_)BOOTMETH_VBE_ABREC) += vbe_abrec.o vbe_common.o
+obj-$(CONFIG_$(PHASE_)BOOTMETH_VBE_ABREC_FW) += vbe_abrec_fw.o
+obj-$(CONFIG_$(PHASE_)BOOTMETH_VBE_ABREC_OS) += vbe_abrec_os.o
diff --git a/boot/image-fit.c b/boot/image-fit.c
index 70080d1a6c0..e119c48ef6c 100644
--- a/boot/image-fit.c
+++ b/boot/image-fit.c
@@ -1907,24 +1907,30 @@ int fit_conf_get_prop_node(const void *fit, int noffset, const char *prop_name,
count = fit_conf_get_prop_node_count(fit, noffset, prop_name);
if (count < 0)
return count;
+ log_debug("looking for %s (%s, image-count %d):\n", prop_name,
+ genimg_get_phase_name(image_ph_phase(sel_phase)), count);
/* check each image in the list */
for (i = 0; i < count; i++) {
- enum image_phase_t phase;
+ enum image_phase_t phase = IH_PHASE_NONE;
int ret, node;
node = fit_conf_get_prop_node_index(fit, noffset, prop_name, i);
ret = fit_image_get_phase(fit, node, &phase);
+ log_debug("- %s (%s): ", fdt_get_name(fit, node, NULL),
+ genimg_get_phase_name(phase));
/* if the image is for any phase, let's use it */
- if (ret == -ENOENT)
+ if (ret == -ENOENT || phase == sel_phase) {
+ log_debug("found\n");
return node;
- else if (ret < 0)
+ } else if (ret < 0) {
+ log_debug("err=%d\n", ret);
return ret;
-
- if (phase == sel_phase)
- return node;
+ }
+ log_debug("no match\n");
}
+ log_debug("- not found\n");
return -ENOENT;
}
@@ -2012,13 +2018,15 @@ int fit_get_node_from_config(struct bootm_headers *images,
}
/**
- * fit_get_image_type_property() - get property name for IH_TYPE_...
+ * fit_get_image_type_property() - get property name for sel_phase
*
* Return: the properly name where we expect to find the image in the
* config node
*/
-static const char *fit_get_image_type_property(int type)
+static const char *fit_get_image_type_property(int ph_type)
{
+ int type = image_ph_type(ph_type);
+
/*
* This is sort-of available in the uimage_type[] table in image.c
* but we don't have access to the short name, and "fdt" is different
@@ -2070,8 +2078,9 @@ int fit_image_load(struct bootm_headers *images, ulong addr,
fit_uname = fit_unamep ? *fit_unamep : NULL;
fit_uname_config = fit_uname_configp ? *fit_uname_configp : NULL;
fit_base_uname_config = NULL;
- prop_name = fit_get_image_type_property(image_type);
- printf("## Loading %s from FIT Image at %08lx ...\n", prop_name, addr);
+ prop_name = fit_get_image_type_property(ph_type);
+ printf("## Loading %s (%s) from FIT Image at %08lx ...\n",
+ prop_name, genimg_get_phase_name(image_ph_phase(ph_type)), addr);
bootstage_mark(bootstage_id + BOOTSTAGE_SUB_FORMAT);
ret = fit_check_format(fit, IMAGE_SIZE_INVAL);
diff --git a/boot/vbe_abrec.c b/boot/vbe_abrec.c
new file mode 100644
index 00000000000..6d0f622262d
--- /dev/null
+++ b/boot/vbe_abrec.c
@@ -0,0 +1,83 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Verified Boot for Embedded (VBE) 'simple' method
+ *
+ * Copyright 2024 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#define LOG_CATEGORY LOGC_BOOT
+
+#include <dm.h>
+#include <memalign.h>
+#include <mmc.h>
+#include <dm/ofnode.h>
+#include "vbe_abrec.h"
+
+int abrec_read_priv(ofnode node, struct abrec_priv *priv)
+{
+ memset(priv, '\0', sizeof(*priv));
+ if (ofnode_read_u32(node, "area-start", &priv->area_start) ||
+ ofnode_read_u32(node, "area-size", &priv->area_size) ||
+ ofnode_read_u32(node, "version-offset", &priv->version_offset) ||
+ ofnode_read_u32(node, "version-size", &priv->version_size) ||
+ ofnode_read_u32(node, "state-offset", &priv->state_offset) ||
+ ofnode_read_u32(node, "state-size", &priv->state_size))
+ return log_msg_ret("read", -EINVAL);
+ ofnode_read_u32(node, "skip-offset", &priv->skip_offset);
+ priv->storage = strdup(ofnode_read_string(node, "storage"));
+ if (!priv->storage)
+ return log_msg_ret("str", -EINVAL);
+
+ return 0;
+}
+
+int abrec_read_nvdata(struct abrec_priv *priv, struct udevice *blk,
+ struct abrec_state *state)
+{
+ ALLOC_CACHE_ALIGN_BUFFER(u8, buf, MMC_MAX_BLOCK_LEN);
+ const struct vbe_nvdata *nvd = (struct vbe_nvdata *)buf;
+ uint flags;
+ int ret;
+
+ ret = vbe_read_nvdata(blk, priv->area_start + priv->state_offset,
+ priv->state_size, buf);
+ if (ret == -EPERM) {
+ memset(buf, '\0', MMC_MAX_BLOCK_LEN);
+ log_warning("Starting with empty state\n");
+ } else if (ret) {
+ return log_msg_ret("nv", ret);
+ }
+
+ state->fw_vernum = nvd->fw_vernum;
+ flags = nvd->flags;
+ state->try_count = flags & VBEF_TRY_COUNT_MASK;
+ state->try_b = flags & VBEF_TRY_B;
+ state->recovery = flags & VBEF_RECOVERY;
+ state->pick = (flags & VBEF_PICK_MASK) >> VBEF_PICK_SHIFT;
+
+ return 0;
+}
+
+int abrec_read_state(struct udevice *dev, struct abrec_state *state)
+{
+ struct abrec_priv *priv = dev_get_priv(dev);
+ struct udevice *blk;
+ int ret;
+
+ ret = vbe_get_blk(priv->storage, &blk);
+ if (ret)
+ return log_msg_ret("blk", ret);
+
+ ret = vbe_read_version(blk, priv->area_start + priv->version_offset,
+ state->fw_version, MAX_VERSION_LEN);
+ if (ret)
+ return log_msg_ret("ver", ret);
+ log_debug("version=%s\n", state->fw_version);
+
+ ret = abrec_read_nvdata(priv, blk, state);
+ if (ret)
+ return log_msg_ret("nvd", ret);
+
+ return 0;
+}
diff --git a/boot/vbe_abrec.h b/boot/vbe_abrec.h
new file mode 100644
index 00000000000..63c73297351
--- /dev/null
+++ b/boot/vbe_abrec.h
@@ -0,0 +1,115 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Verified Boot for Embedded (VBE) vbe-abrec common file
+ *
+ * Copyright 2024 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#ifndef __VBE_ABREC_H
+#define __VBE_ABREC_H
+
+#include <vbe.h>
+#include <dm/ofnode_decl.h>
+
+#include "vbe_common.h"
+
+struct bootflow;
+struct udevice;
+
+/**
+ * struct abrec_priv - information read from the device tree
+ *
+ * @area_start: Start offset of the VBE area in the device, in bytes
+ * @area_size: Total size of the VBE area
+ * @skip_offset: Size of an initial part of the device to skip, when using
+ * area_start. This is effectively added to area_start to calculate the
+ * actual start position on the device
+ * @state_offset: Offset from area_start of the VBE state, in bytes
+ * @state_size: Size of the state information
+ * @version_offset: Offset from from area_start of the VBE version info
+ * @version_size: Size of the version info
+ * @storage: Storage device to use, in the form <uclass><devnum>, e.g. "mmc1"
+ */
+struct abrec_priv {
+ u32 area_start;
+ u32 area_size;
+ u32 skip_offset;
+ u32 state_offset;
+ u32 state_size;
+ u32 version_offset;
+ u32 version_size;
+ const char *storage;
+};
+
+/** struct abrec_state - state information read from media
+ *
+ * The state on the media is converted into this more code-friendly structure.
+ *
+ * @fw_version: Firmware version string
+ * @fw_vernum: Firmware version number
+ * @try_count: Number of times the B firmware has been tried
+ * @try_b: true to try B firmware on the next boot
+ * @recovery: true to enter recovery firmware on the next boot
+ * @try_result: Result of trying to boot with the last firmware
+ * @pick: Firmware which was chosen in this boot
+ */
+struct abrec_state {
+ char fw_version[MAX_VERSION_LEN];
+ u32 fw_vernum;
+ u8 try_count;
+ bool try_b;
+ bool recovery;
+ enum vbe_try_result try_result;
+ enum vbe_pick_t pick;
+};
+
+/**
+ * abrec_read_fw_bootflow() - Read a bootflow for firmware
+ *
+ * Locates and loads the firmware image (FIT) needed for the next phase. The FIT
+ * should ideally use external data, to reduce the amount of it that needs to be
+ * read.
+ *
+ * @bdev: bootdev device containing the firmwre
+ * @bflow: Place to put the created bootflow, on success
+ * @return 0 if OK, -ve on error
+ */
+int abrec_read_bootflow_fw(struct udevice *dev, struct bootflow *bflow);
+
+/**
+ * vbe_simple_read_state() - Read the VBE simple state information
+ *
+ * @dev: VBE bootmeth
+ * @state: Place to put the state
+ * @return 0 if OK, -ve on error
+ */
+int abrec_read_state(struct udevice *dev, struct abrec_state *state);
+
+/**
+ * abrec_read_nvdata() - Read non-volatile data from a block device
+ *
+ * Reads the ABrec VBE nvdata from a device. This function reads a single block
+ * from the device, so the nvdata cannot be larger than that.
+ *
+ * @blk: Device to read from
+ * @offset: Offset to read, in bytes
+ * @size: Number of bytes to read
+ * @buf: Buffer to hold the data
+ * Return: 0 if OK, -E2BIG if @size > block size, -EBADF if the offset is not
+ * block-aligned, -EIO if an I/O error occurred, -EPERM if the header version is
+ * incorrect, the header size is invalid or the data fails its CRC check
+ */
+int abrec_read_nvdata(struct abrec_priv *priv, struct udevice *blk,
+ struct abrec_state *state);
+
+/**
+ * abrec_read_priv() - Read info from the devicetree
+ *
+ * @node: Node to read from
+ * @priv: Information to fill in
+ * Return 0 if OK, -EINVAL if something is wrong with the devicetree node
+ */
+int abrec_read_priv(ofnode node, struct abrec_priv *priv);
+
+#endif /* __VBE_ABREC_H */
diff --git a/boot/vbe_abrec_fw.c b/boot/vbe_abrec_fw.c
new file mode 100644
index 00000000000..d52bd9ddff0
--- /dev/null
+++ b/boot/vbe_abrec_fw.c
@@ -0,0 +1,276 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Verified Boot for Embedded (VBE) loading firmware phases
+ *
+ * Copyright 2022 Google LLC
+ * Written by Simon Glass <sjg@chromium.org>
+ */
+
+#define LOG_CATEGORY LOGC_BOOT
+
+#include <binman_sym.h>
+#include <bloblist.h>
+#include <bootdev.h>
+#include <bootflow.h>
+#include <bootmeth.h>
+#include <bootstage.h>
+#include <display_options.h>
+#include <dm.h>
+#include <image.h>
+#include <log.h>
+#include <mapmem.h>
+#include <memalign.h>
+#include <mmc.h>
+#include <spl.h>
+#include <vbe.h>
+#include <dm/device-internal.h>
+#include "vbe_abrec.h"
+#include "vbe_common.h"
+
+binman_sym_declare(ulong, spl_a, image_pos);
+binman_sym_declare(ulong, spl_b, image_pos);
+binman_sym_declare(ulong, spl_recovery, image_pos);
+
+binman_sym_declare(ulong, spl_a, size);
+binman_sym_declare(ulong, spl_b, size);
+binman_sym_declare(ulong, spl_recovery, size);
+
+binman_sym_declare(ulong, u_boot_a, image_pos);
+binman_sym_declare(ulong, u_boot_b, image_pos);
+binman_sym_declare(ulong, u_boot_recovery, image_pos);
+
+binman_sym_declare(ulong, u_boot_a, size);
+binman_sym_declare(ulong, u_boot_b, size);
+binman_sym_declare(ulong, u_boot_recovery, size);
+
+binman_sym_declare(ulong, vpl, image_pos);
+binman_sym_declare(ulong, vpl, size);
+
+static const char *const pick_names[] = {"A", "B", "Recovery"};
+
+/**
+ * abrec_read_bootflow_fw() - Create a bootflow for firmware
+ *
+ * Locates and loads the firmware image (FIT) needed for the next phase. The FIT
+ * should ideally use external data, to reduce the amount of it that needs to be
+ * read.
+ *
+ * @bdev: bootdev device containing the firmwre
+ * @meth: VBE abrec bootmeth
+ * @blow: Place to put the created bootflow, on success
+ * @return 0 if OK, -ve on error
+ */
+int abrec_read_bootflow_fw(struct udevice *dev, struct bootflow *bflow)
+{
+ struct udevice *media = dev_get_parent(bflow->dev);
+ struct udevice *meth = bflow->method;
+ struct abrec_priv *priv = dev_get_priv(meth);
+ ulong len, load_addr;
+ struct udevice *blk;
+ int ret;
+
+ log_debug("media=%s\n", media->name);
+ ret = blk_get_from_parent(media, &blk);
+ if (ret)
+ return log_msg_ret("med", ret);
+
+ ret = vbe_read_fit(blk, priv->area_start + priv->skip_offset,
+ priv->area_size, NULL, &load_addr, &len, &bflow->name);
+ if (ret)
+ return log_msg_ret("vbe", ret);
+
+ /* set up the bootflow with the info we obtained */
+ bflow->blk = blk;
+ bflow->buf = map_sysmem(load_addr, len);
+ bflow->size = len;
+
+ return 0;
+}
+
+static int abrec_run_vpl(struct udevice *blk, struct spl_image_info *image,
+ struct vbe_handoff *handoff)
+{
+ uint flags, tries, prev_result;
+ struct abrec_priv priv;
+ struct abrec_state state;
+ enum vbe_pick_t pick;
+ uint try_count;
+ ulong offset, size;
+ ulong ub_offset, ub_size;
+ ofnode node;
+ int ret;
+
+ node = vbe_get_node();
+ if (!ofnode_valid(node))
+ return log_msg_ret("nod", -EINVAL);
+
+ ret = abrec_read_priv(node, &priv);
+ if (ret)
+ return log_msg_ret("pri", ret);
+
+ ret = abrec_read_nvdata(&priv, blk, &state);
+ if (ret)
+ return log_msg_ret("sta", ret);
+
+ prev_result = state.try_result;
+ try_count = state.try_count;
+
+ if (state.recovery) {
+ pick = VBEP_RECOVERY;
+
+ /* if we are trying B but ran out of tries, use A */
+ } else if ((prev_result == VBETR_TRYING) && !tries) {
+ pick = VBEP_A;
+ state.try_result = VBETR_BAD;
+
+ /* if requested, try B */
+ } else if (flags & VBEF_TRY_B) {
+ pick = VBEP_B;
+
+ /* decrement the try count if not already zero */
+ if (try_count)
+ try_count--;
+ state.try_result = VBETR_TRYING;
+ } else {
+ pick = VBEP_A;
+ }
+ state.try_count = try_count;
+
+ switch (pick) {
+ case VBEP_A:
+ offset = binman_sym(ulong, spl_a, image_pos);
+ size = binman_sym(ulong, spl_a, size);
+ ub_offset = binman_sym(ulong, u_boot_a, image_pos);
+ ub_size = binman_sym(ulong, u_boot_a, size);
+ break;
+ case VBEP_B:
+ offset = binman_sym(ulong, spl_b, image_pos);
+ size = binman_sym(ulong, spl_b, size);
+ ub_offset = binman_sym(ulong, u_boot_b, image_pos);
+ ub_size = binman_sym(ulong, u_boot_b, size);
+ break;
+ case VBEP_RECOVERY:
+ offset = binman_sym(ulong, spl_recovery, image_pos);
+ size = binman_sym(ulong, spl_recovery, size);
+ ub_offset = binman_sym(ulong, u_boot_recovery, image_pos);
+ ub_size = binman_sym(ulong, u_boot_recovery, size);
+ break;
+ }
+ log_debug("pick=%d, offset=%lx size=%lx\n", pick, offset, size);
+ log_info("VBE: Firmware pick %s at %lx\n", pick_names[pick], offset);
+
+ ret = vbe_read_fit(blk, offset, size, image, NULL, NULL, NULL);
+ if (ret)
+ return log_msg_ret("vbe", ret);
+ handoff->offset = ub_offset;
+ handoff->size = ub_size;
+ handoff->pick = pick;
+ image->load_addr = spl_get_image_text_base();
+ image->entry_point = image->load_addr;
+
+ return 0;
+}
+
+static int abrec_run_spl(struct udevice *blk, struct spl_image_info *image,
+ struct vbe_handoff *handoff)
+{
+ int ret;
+
+ log_info("VBE: Firmware pick %s at %lx\n", pick_names[handoff->pick],
+ handoff->offset);
+ ret = vbe_read_fit(blk, handoff->offset, handoff->size, image, NULL,
+ NULL, NULL);
+ if (ret)
+ return log_msg_ret("vbe", ret);
+ image->load_addr = spl_get_image_text_base();
+ image->entry_point = image->load_addr;
+
+ return 0;
+}
+
+static int abrec_load_from_image(struct spl_image_info *image,
+ struct spl_boot_device *bootdev)
+{
+ struct vbe_handoff *handoff;
+ int ret;
+
+ printf("load: %s\n", ofnode_read_string(ofnode_root(), "model"));
+ if (xpl_phase() != PHASE_VPL && xpl_phase() != PHASE_SPL &&
+ xpl_phase() != PHASE_TPL)
+ return -ENOENT;
+
+ ret = bloblist_ensure_size(BLOBLISTT_VBE, sizeof(struct vbe_handoff),
+ 0, (void **)&handoff);
+ if (ret)
+ return log_msg_ret("ro", ret);
+
+ if (USE_BOOTMETH) {
+ struct udevice *meth, *bdev;
+ struct abrec_priv *priv;
+ struct bootflow bflow;
+
+ vbe_find_first_device(&meth);
+ if (!meth)
+ return log_msg_ret("vd", -ENODEV);
+ log_debug("vbe dev %s\n", meth->name);
+ ret = device_probe(meth);
+ if (ret)
+ return log_msg_ret("probe", ret);
+
+ priv = dev_get_priv(meth);
+ log_debug("abrec %s\n", priv->storage);
+ ret = bootdev_find_by_label(priv->storage, &bdev, NULL);
+ if (ret)
+ return log_msg_ret("bd", ret);
+ log_debug("bootdev %s\n", bdev->name);
+
+ bootflow_init(&bflow, bdev, meth);
+ ret = bootmeth_read_bootflow(meth, &bflow);
+ log_debug("\nfw ret=%d\n", ret);
+ if (ret)
+ return log_msg_ret("rd", ret);
+
+ /* jump to the image */
+ image->flags = SPL_SANDBOXF_ARG_IS_BUF;
+ image->arg = bflow.buf;
+ image->size = bflow.size;
+ log_debug("Image: %s at %p size %x\n", bflow.name, bflow.buf,
+ bflow.size);
+
+ /* this is not used from now on, so free it */
+ bootflow_free(&bflow);
+ } else {
+ struct udevice *media;
+ struct udevice *blk;
+
+ ret = uclass_get_device_by_seq(UCLASS_MMC, 1, &media);
+ if (ret)
+ return log_msg_ret("vdv", ret);
+ ret = blk_get_from_parent(media, &blk);
+ if (ret)
+ return log_msg_ret("med", ret);
+
+ if (xpl_phase() == PHASE_TPL) {
+ ulong offset, size;
+
+ offset = binman_sym(ulong, vpl, image_pos);
+ size = binman_sym(ulong, vpl, size);
+ log_debug("VPL at offset %lx size %lx\n", offset, size);
+ ret = vbe_read_fit(blk, offset, size, image, NULL,
+ NULL, NULL);
+ if (ret)
+ return log_msg_ret("vbe", ret);
+ } else if (xpl_phase() == PHASE_VPL) {
+ ret = abrec_run_vpl(blk, image, handoff);
+ } else {
+ ret = abrec_run_spl(blk, image, handoff);
+ }
+ }
+
+ /* Record that VBE was used in this phase */
+ handoff->phases |= 1 << xpl_phase();
+
+ return 0;
+}
+SPL_LOAD_IMAGE_METHOD("vbe_abrec", 5, BOOT_DEVICE_VBE,
+ abrec_load_from_image);
diff --git a/boot/vbe_common.c b/boot/vbe_common.c
index 0d51fe762c3..a86986d86e9 100644
--- a/boot/vbe_common.c
+++ b/boot/vbe_common.c
@@ -202,29 +202,30 @@ int vbe_read_fit(struct udevice *blk, ulong area_offset, ulong area_size,
phase = IS_ENABLED(CONFIG_TPL_BUILD) ? IH_PHASE_NONE :
IS_ENABLED(CONFIG_VPL_BUILD) ? IH_PHASE_SPL : IH_PHASE_U_BOOT;
- /*
- * Load the image from the FIT. We ignore any load-address information
- * so in practice this simply locates the image in the external-data
- * region and returns its address and size. Since we only loaded the FIT
- * itself, only a part of the image will be present, at best.
- */
- fit_uname = NULL;
- fit_uname_config = NULL;
log_debug("loading FIT\n");
if (xpl_phase() == PHASE_SPL && !IS_ENABLED(CONFIG_SANDBOX)) {
struct spl_load_info info;
spl_load_init(&info, h_vbe_load_read, desc, desc->blksz);
+ xpl_set_fdt_update(&info, false);
xpl_set_phase(&info, IH_PHASE_U_BOOT);
log_debug("doing SPL from %s blksz %lx log2blksz %x area_offset %lx + fdt_size %lx\n",
blk->name, desc->blksz, desc->log2blksz, area_offset, ALIGN(size, 4));
ret = spl_load_simple_fit(image, &info, area_offset, buf);
- log_debug("spl_load_abrec_fit() ret=%d\n", ret);
+ log_debug("spl_load_simple_fit() ret=%d\n", ret);
return ret;
}
+ /*
+ * Load the image from the FIT. We ignore any load-address information
+ * so in practice this simply locates the image in the external-data
+ * region and returns its address and size. Since we only loaded the FIT
+ * itself, only a part of the image will be present, at best.
+ */
+ fit_uname = NULL;
+ fit_uname_config = NULL;
ret = fit_image_load(&images, addr, &fit_uname, &fit_uname_config,
IH_ARCH_DEFAULT, image_ph(phase, IH_TYPE_FIRMWARE),
BOOTSTAGE_ID_FIT_SPL_START, FIT_LOAD_IGNORED,
@@ -373,3 +374,8 @@ int vbe_read_fit(struct udevice *blk, ulong area_offset, ulong area_size,
return 0;
}
+
+ofnode vbe_get_node(void)
+{
+ return ofnode_path("/bootstd/firmware0");
+}
diff --git a/boot/vbe_common.h b/boot/vbe_common.h
index 84117815a19..493cbdc3694 100644
--- a/boot/vbe_common.h
+++ b/boot/vbe_common.h
@@ -9,6 +9,8 @@
#ifndef __VBE_COMMON_H
#define __VBE_COMMON_H
+#include <dm/ofnode_decl.h>
+#include <linux/bitops.h>
#include <linux/types.h>
struct spl_image_info;
@@ -39,6 +41,40 @@ enum {
};
/**
+ * enum vbe_try_result - result of trying a firmware pick
+ *
+ * @VBETR_UNKNOWN: Unknown / invalid result
+ * @VBETR_TRYING: Firmware pick is being tried
+ * @VBETR_OK: Firmware pick is OK and can be used from now on
+ * @VBETR_BAD: Firmware pick is bad and should be removed
+ */
+enum vbe_try_result {
+ VBETR_UNKNOWN,
+ VBETR_TRYING,
+ VBETR_OK,
+ VBETR_BAD,
+};
+
+/**
+ * enum vbe_flags - flags controlling operation
+ *
+ * @VBEF_TRY_COUNT_MASK: mask for the 'try count' value
+ * @VBEF_TRY_B: Try the B slot
+ * @VBEF_RECOVERY: Use recovery slot
+ */
+enum vbe_flags {
+ VBEF_TRY_COUNT_MASK = 0x3,
+ VBEF_TRY_B = BIT(2),
+ VBEF_RECOVERY = BIT(3),
+
+ VBEF_RESULT_SHIFT = 4,
+ VBEF_RESULT_MASK = 3 << VBEF_RESULT_SHIFT,
+
+ VBEF_PICK_SHIFT = 6,
+ VBEF_PICK_MASK = 3 << VBEF_PICK_SHIFT,
+};
+
+/**
* struct vbe_nvdata - basic storage format for non-volatile data
*
* This is used for all VBE methods
@@ -134,4 +170,11 @@ int vbe_read_fit(struct udevice *blk, ulong area_offset, ulong area_size,
struct spl_image_info *image, ulong *load_addrp, ulong *lenp,
char **namep);
+/**
+ * vbe_get_node() - Get the node containing the VBE settings
+ *
+ * Return: VBE node (typically "/bootstd/firmware0")
+ */
+ofnode vbe_get_node(void);
+
#endif /* __VBE_ABREC_H */
diff --git a/common/hash.c b/common/hash.c
index 8dd9da85768..0c45992d5c7 100644
--- a/common/hash.c
+++ b/common/hash.c
@@ -143,7 +143,8 @@ static int __maybe_unused hash_finish_sha512(struct hash_algo *algo, void *ctx,
return 0;
}
-static int hash_init_crc16_ccitt(struct hash_algo *algo, void **ctxp)
+static int __maybe_unused hash_init_crc16_ccitt(struct hash_algo *algo,
+ void **ctxp)
{
uint16_t *ctx = malloc(sizeof(uint16_t));
*ctx = 0;
@@ -151,16 +152,18 @@ static int hash_init_crc16_ccitt(struct hash_algo *algo, void **ctxp)
return 0;
}
-static int hash_update_crc16_ccitt(struct hash_algo *algo, void *ctx,
- const void *buf, unsigned int size,
- int is_last)
+static int __maybe_unused hash_update_crc16_ccitt(struct hash_algo *algo,
+ void *ctx, const void *buf,
+ unsigned int size,
+ int is_last)
{
*((uint16_t *)ctx) = crc16_ccitt(*((uint16_t *)ctx), buf, size);
return 0;
}
-static int hash_finish_crc16_ccitt(struct hash_algo *algo, void *ctx,
- void *dest_buf, int size)
+static int __maybe_unused hash_finish_crc16_ccitt(struct hash_algo *algo,
+ void *ctx, void *dest_buf,
+ int size)
{
if (size < algo->digest_size)
return -1;
@@ -295,6 +298,7 @@ static struct hash_algo hash_algo[] = {
#endif
},
#endif
+#if CONFIG_IS_ENABLED(CRC16)
{
.name = "crc16-ccitt",
.digest_size = 2,
@@ -304,6 +308,7 @@ static struct hash_algo hash_algo[] = {
.hash_update = hash_update_crc16_ccitt,
.hash_finish = hash_finish_crc16_ccitt,
},
+#endif
#if CONFIG_IS_ENABLED(CRC8) && IS_ENABLED(CONFIG_HASH_CRC8)
{
.name = "crc8",
diff --git a/common/spl/Kconfig.vpl b/common/spl/Kconfig.vpl
index 97dfc630152..cf6b36c8e38 100644
--- a/common/spl/Kconfig.vpl
+++ b/common/spl/Kconfig.vpl
@@ -9,6 +9,19 @@ config VPL_BANNER_PRINT
info. Disabling this option could be useful to reduce VPL boot time
(e.g. approx. 6 ms faster, when output on i.MX6 with 115200 baud).
+config VPL_LDSCRIPT
+ string "Linker script for the VPL stage"
+ default "arch/arm/cpu/armv8/u-boot-spl.lds" if ARM64
+ default "arch/\$(ARCH)/cpu/u-boot-spl.lds"
+ help
+ The TPL stage will usually require a different linker-script
+ (as it runs from a different memory region) than the regular
+ U-Boot stage. Set this to the path of the linker-script to
+ be used for TPL.
+
+ May be left empty to trigger the Makefile infrastructure to
+ fall back to the linker-script used for the SPL stage.
+
config VPL_BOARD_INIT
bool "Call board-specific initialization in VPL"
help
diff --git a/common/spl/spl.c b/common/spl/spl.c
index 9af0a4954d4..76fd56dfe4b 100644
--- a/common/spl/spl.c
+++ b/common/spl/spl.c
@@ -50,8 +50,10 @@ u32 *boot_params_ptr = NULL;
#if CONFIG_IS_ENABLED(BINMAN_UBOOT_SYMBOLS)
/* See spl.h for information about this */
+#if defined(CONFIG_SPL_BUILD)
binman_sym_declare(ulong, u_boot_any, image_pos);
binman_sym_declare(ulong, u_boot_any, size);
+#endif
#ifdef CONFIG_TPL
binman_sym_declare(ulong, u_boot_spl_any, image_pos);
@@ -179,9 +181,15 @@ ulong spl_get_image_pos(void)
if (xpl_next_phase() == PHASE_VPL)
return binman_sym(ulong, u_boot_vpl_any, image_pos);
#endif
- return xpl_next_phase() == PHASE_SPL ?
- binman_sym(ulong, u_boot_spl_any, image_pos) :
- binman_sym(ulong, u_boot_any, image_pos);
+#if defined(CONFIG_TPL) && !defined(CONFIG_VPL)
+ if (xpl_next_phase() == PHASE_SPL)
+ return binman_sym(ulong, u_boot_spl_any, image_pos);
+#endif
+#if defined(CONFIG_SPL_BUILD)
+ return binman_sym(ulong, u_boot_any, image_pos);
+#endif
+
+ return BINMAN_SYM_MISSING;
}
ulong spl_get_image_size(void)
@@ -263,14 +271,20 @@ void spl_set_header_raw_uboot(struct spl_image_info *spl_image)
*/
if (u_boot_pos && u_boot_pos != BINMAN_SYM_MISSING) {
/* Binman does not support separated entry addresses */
- spl_image->entry_point = u_boot_pos;
- spl_image->load_addr = u_boot_pos;
+ spl_image->entry_point = spl_get_image_text_base();
+ spl_image->load_addr = spl_get_image_text_base();
+ spl_image->size = spl_get_image_size();
+ log_debug("Next load addr %lx\n", spl_image->load_addr);
} else {
spl_image->entry_point = CONFIG_SYS_UBOOT_START;
spl_image->load_addr = CONFIG_TEXT_BASE;
+ log_debug("Default load addr %x (u_boot_pos=%lx)\n",
+ CONFIG_TEXT_BASE, u_boot_pos);
}
spl_image->os = IH_OS_U_BOOT;
- spl_image->name = "U-Boot";
+ spl_image->name = xpl_name(xpl_next_phase());
+ log_debug("Next phase: %s at %lx size %lx\n", spl_image->name,
+ spl_image->load_addr, (ulong)spl_image->size);
}
__weak int spl_parse_board_header(struct spl_image_info *spl_image,
diff --git a/common/spl/spl_fit.c b/common/spl/spl_fit.c
index 64c4349b138..49b4df60560 100644
--- a/common/spl/spl_fit.c
+++ b/common/spl/spl_fit.c
@@ -199,7 +199,9 @@ static int get_aligned_image_size(struct spl_load_info *info, int data_size,
* the image gets loaded to the address pointed to by the
* load_addr member in this struct, if load_addr is not 0
*
- * Return: 0 on success or a negative error number.
+ * Return: 0 on success, -EPERM if this image is not the correct phase
+ * (for CONFIG_BOOTMETH_VBE_SIMPLE_FW), or another negative error number on
+ * other error.
*/
static int load_simple_fit(struct spl_load_info *info, ulong fit_offset,
const struct spl_fit_info *ctx, int node,
@@ -218,6 +220,25 @@ static int load_simple_fit(struct spl_load_info *info, ulong fit_offset,
const void *fit = ctx->fit;
bool external_data = false;
+ log_debug("starting\n");
+ if (CONFIG_IS_ENABLED(BOOTMETH_VBE) &&
+ xpl_get_phase(info) != IH_PHASE_NONE) {
+ enum image_phase_t phase;
+ int ret;
+
+ ret = fit_image_get_phase(fit, node, &phase);
+ /* if the image is for any phase, let's use it */
+ if (ret == -ENOENT || phase == xpl_get_phase(info)) {
+ log_debug("found\n");
+ } else if (ret < 0) {
+ log_debug("err=%d\n", ret);
+ return ret;
+ } else {
+ log_debug("- phase mismatch, skipping this image\n");
+ return -EPERM;
+ }
+ }
+
if (IS_ENABLED(CONFIG_SPL_FPGA) ||
(IS_ENABLED(CONFIG_SPL_OS_BOOT) && spl_decompression_enabled())) {
if (fit_image_get_type(fit, node, &type))
@@ -278,10 +299,7 @@ static int load_simple_fit(struct spl_load_info *info, ulong fit_offset,
log_debug("reading from offset %x / %lx size %lx to %p: ",
offset, read_offset, size, src_ptr);
- if (info->read(info,
- fit_offset +
- get_aligned_image_offset(info, offset), size,
- src_ptr) < length)
+ if (info->read(info, read_offset, size, src_ptr) < length)
return -EIO;
debug("External data: dst=%p, offset=%x, size=%lx\n",
@@ -456,7 +474,9 @@ static int spl_fit_append_fdt(struct spl_image_info *spl_image,
image_info.load_addr = (ulong)tmpbuffer;
ret = load_simple_fit(info, offset, ctx, node,
&image_info);
- if (ret < 0)
+ if (ret == -EPERM)
+ continue;
+ else if (ret < 0)
break;
/* Make room in FDT for changes from the overlay */
@@ -495,9 +515,6 @@ static int spl_fit_record_loadable(const struct spl_fit_info *ctx, int index,
const char *name;
int node;
- if (CONFIG_IS_ENABLED(FIT_IMAGE_TINY))
- return 0;
-
ret = spl_fit_get_image_name(ctx, "loadables", index, &name);
if (ret < 0)
return ret;
@@ -817,7 +834,7 @@ int spl_load_simple_fit(struct spl_image_info *spl_image,
image_info.load_addr = 0;
ret = load_simple_fit(info, offset, &ctx, node, &image_info);
- if (ret < 0) {
+ if (ret < 0 && ret != -EPERM) {
printf("%s: can't load image loadables index %d (ret = %d)\n",
__func__, index, ret);
return ret;
@@ -843,7 +860,8 @@ int spl_load_simple_fit(struct spl_image_info *spl_image,
spl_image->entry_point = image_info.entry_point;
/* Record our loadables into the FDT */
- if (spl_image->fdt_addr)
+ if (!CONFIG_IS_ENABLED(FIT_IMAGE_TINY) &&
+ xpl_get_fdt_update(info) && spl_image->fdt_addr)
spl_fit_record_loadable(&ctx, index,
spl_image->fdt_addr,
&image_info);
diff --git a/common/spl/spl_reloc.c b/common/spl/spl_reloc.c
index be8349b535b..324b98eaf98 100644
--- a/common/spl/spl_reloc.c
+++ b/common/spl/spl_reloc.c
@@ -154,7 +154,7 @@ int spl_reloc_jump(struct spl_image_info *image, spl_jump_to_image_t jump)
rcode_func loader;
int ret;
- log_debug("malloc usage %lx bytes (%ld KB of %d KB)\n", gd->malloc_ptr,
+ log_debug("malloc usage %x bytes (%d KB of %d KB)\n", gd->malloc_ptr,
gd->malloc_ptr / 1024, CONFIG_VAL(SYS_MALLOC_F_LEN) / 1024);
if (*image->stack_prot != STACK_PROT_VALUE) {
diff --git a/configs/sandbox_vpl_defconfig b/configs/sandbox_vpl_defconfig
index 46329395ba5..f0315f6ab33 100644
--- a/configs/sandbox_vpl_defconfig
+++ b/configs/sandbox_vpl_defconfig
@@ -252,6 +252,8 @@ CONFIG_FS_CBFS=y
CONFIG_FS_CRAMFS=y
# CONFIG_SPL_USE_TINY_PRINTF is not set
CONFIG_CMD_DHRYSTONE=y
+CONFIG_VPL_SHA1_LEGACY=y
+CONFIG_VPL_SHA256_LEGACY=y
CONFIG_RSA_VERIFY_WITH_PKEY=y
CONFIG_TPM=y
CONFIG_ZSTD=y
diff --git a/drivers/mmc/dw_mmc.c b/drivers/mmc/dw_mmc.c
index e1110cace89..a51494380ce 100644
--- a/drivers/mmc/dw_mmc.c
+++ b/drivers/mmc/dw_mmc.c
@@ -724,7 +724,7 @@ static int dwmci_init(struct mmc *mmc)
return 0;
}
-#ifdef CONFIG_DM_MMC
+#if CONFIG_IS_ENABLED(DM_MMC)
int dwmci_probe(struct udevice *dev)
{
struct mmc *mmc = mmc_get_mmc_dev(dev);
@@ -749,7 +749,7 @@ void dwmci_setup_cfg(struct mmc_config *cfg, struct dwmci_host *host,
u32 max_clk, u32 min_clk)
{
cfg->name = host->name;
-#ifndef CONFIG_DM_MMC
+#if !CONFIG_IS_ENABLED(DM_MMC)
cfg->ops = &dwmci_ops;
#endif
cfg->f_min = min_clk;
diff --git a/include/asm-generic/sections.h b/include/asm-generic/sections.h
index b6bca53db10..3fd5c772a1a 100644
--- a/include/asm-generic/sections.h
+++ b/include/asm-generic/sections.h
@@ -67,6 +67,9 @@ extern char __text_start[];
/* This marks the text region which must be relocated */
extern char __image_copy_start[], __image_copy_end[];
+/* This marks the rcode region used for SPL relocation */
+extern char _rcode_start[], _rcode_end[];
+
extern char __bss_end[];
extern char __rel_dyn_start[], __rel_dyn_end[];
extern char _image_binary_end[];
@@ -77,4 +80,17 @@ extern char _image_binary_end[];
*/
extern void _start(void);
+#ifndef USE_HOSTCC
+#if CONFIG_IS_ENABLED(RELOC_LOADER)
+#define __rcode __section(".text.rcode")
+#define __rdata __section(".text.rdata")
+#else
+#define __rcode
+#define __rdata
+#endif
+#else
+#define __rcode
+#define __rdata
+#endif
+
#endif /* _ASM_GENERIC_SECTIONS_H_ */
diff --git a/include/spl.h b/include/spl.h
index 7155e9c67aa..850c64d4b19 100644
--- a/include/spl.h
+++ b/include/spl.h
@@ -345,7 +345,7 @@ typedef ulong (*spl_load_reader)(struct spl_load_info *load, ulong sector,
* @priv: Private data for the device
* @bl_len: Block length for reading in bytes
* @phase: Image phase to load
- * @fit_loaded: true if the FIT has been loaded, except for external data
+ * @no_fdt_update: true to update the FDT with any loadables that are loaded
*/
struct spl_load_info {
spl_load_reader read;
@@ -355,7 +355,7 @@ struct spl_load_info {
#endif
#if CONFIG_IS_ENABLED(BOOTMETH_VBE)
u8 phase;
- u8 fit_loaded;
+ u8 fdt_update;
#endif
};
@@ -395,12 +395,20 @@ static inline enum image_phase_t xpl_get_phase(struct spl_load_info *info)
#endif
}
-static inline bool xpl_get_fit_loaded(struct spl_load_info *info)
+static inline void xpl_set_fdt_update(struct spl_load_info *info,
+ bool fdt_update)
{
#if CONFIG_IS_ENABLED(BOOTMETH_VBE)
- return info->fit_loaded;
+ info->fdt_update = fdt_update;
+#endif
+}
+
+static inline enum image_phase_t xpl_get_fdt_update(struct spl_load_info *info)
+{
+#if CONFIG_IS_ENABLED(BOOTMETH_VBE)
+ return info->fdt_update;
#else
- return false;
+ return true;
#endif
}
@@ -415,6 +423,7 @@ static inline void spl_load_init(struct spl_load_info *load,
load->priv = priv;
spl_set_bl_len(load, bl_len);
xpl_set_phase(load, IH_PHASE_NONE);
+ xpl_set_fdt_update(load, true);
}
/*
diff --git a/include/spl_load.h b/include/spl_load.h
index 935f7d336f2..525e0c9e86c 100644
--- a/include/spl_load.h
+++ b/include/spl_load.h
@@ -20,13 +20,15 @@ static inline int _spl_load(struct spl_image_info *spl_image,
ulong base_offset, image_offset, overhead;
int read, ret;
+ log_debug("\nloading hdr from %lx to %p\n", (ulong)offset, header);
read = info->read(info, offset, ALIGN(sizeof(*header),
spl_get_bl_len(info)), header);
if (read < (int)sizeof(*header))
return -EIO;
if (image_get_magic(header) == FDT_MAGIC) {
- if (IS_ENABLED(CONFIG_SPL_LOAD_FIT_FULL)) {
+ log_debug("Found FIT\n");
+ if (CONFIG_IS_ENABLED(LOAD_FIT_FULL)) {
void *buf;
/*
@@ -48,9 +50,12 @@ static inline int _spl_load(struct spl_image_info *spl_image,
return spl_parse_image_header(spl_image, bootdev, buf);
}
- if (IS_ENABLED(CONFIG_SPL_LOAD_FIT))
+ if (CONFIG_IS_ENABLED(LOAD_FIT)) {
+ log_debug("Simple loading\n");
return spl_load_simple_fit(spl_image, info, offset,
header);
+ }
+ log_debug("No FIT support\n");
}
if (IS_ENABLED(CONFIG_SPL_LOAD_IMX_CONTAINER) &&
diff --git a/include/vbe.h b/include/vbe.h
index 56bff63362f..61bfa0e557d 100644
--- a/include/vbe.h
+++ b/include/vbe.h
@@ -10,6 +10,8 @@
#ifndef __VBE_H
#define __VBE_H
+#include <linux/types.h>
+
/**
* enum vbe_phase_t - current phase of VBE
*
@@ -26,12 +28,31 @@ enum vbe_phase_t {
};
/**
+ * enum vbe_pick_t - indicates which firmware is picked
+ *
+ * @VBEFT_A: Firmware A
+ * @VBEFT_B: Firmware B
+ * @VBEFT_RECOVERY: Recovery firmware
+ */
+enum vbe_pick_t {
+ VBEP_A,
+ VBEP_B,
+ VBEP_RECOVERY,
+};
+
+/**
* struct vbe_handoff - information about VBE progress
*
+ * @offset: Offset of the FIT to use for SPL onwards
+ * @size: Size of the area containing the FIT
* @phases: Indicates which phases used the VBE bootmeth (1 << PHASE_...)
+ * @pick: Indicates which firmware pick was used (enum vbe_pick_t)
*/
struct vbe_handoff {
+ ulong offset;
+ ulong size;
u8 phases;
+ u8 pick;
};
/**
diff --git a/lib/Kconfig b/lib/Kconfig
index b27965fc480..1a683dea670 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -758,6 +758,16 @@ config VPL_CRC8
checksum with feedback to produce an 8-bit result. The code is small
and it does not require a lookup table (unlike CRC32).
+config CRC16
+ bool "Support CRC16"
+ default y
+ help
+ Enables CRC16 support. This is normally required. Two algorithms are
+ provided:
+
+ - CCITT, with a polynomical x^16 + x^12 + x^5 + 1
+ - standard, with polynomial x^16 + x^15 + x^2 + 1 (0x8005)
+
config SPL_CRC16
bool "Support CRC16 in SPL"
depends on SPL
diff --git a/lib/Makefile b/lib/Makefile
index fc6e68c901a..a7bc2f3134a 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -35,8 +35,6 @@ obj-$(CONFIG_CIRCBUF) += circbuf.o
endif
obj-y += crc8.o
-obj-y += crc16.o
-obj-y += crc16-ccitt.o
obj-$(CONFIG_ERRNO_STR) += errno_str.o
obj-$(CONFIG_FIT) += fdtdec_common.o
obj-$(CONFIG_TEST_FDTDEC) += fdtdec_test.o
@@ -71,6 +69,7 @@ endif
obj-$(CONFIG_$(PHASE_)CRC8) += crc8.o
obj-$(CONFIG_$(PHASE_)CRC16) += crc16.o
+obj-$(CONFIG_$(PHASE_)CRC16) += crc16-ccitt.o
obj-y += crypto/
@@ -80,11 +79,11 @@ obj-$(CONFIG_$(XPL_)RSA) += rsa/
obj-$(CONFIG_HASH) += hash-checksum.o
obj-$(CONFIG_BLAKE2) += blake2/blake2b.o
-obj-$(CONFIG_$(XPL_)MD5_LEGACY) += md5.o
-obj-$(CONFIG_$(XPL_)SHA1_LEGACY) += sha1.o
-obj-$(CONFIG_$(XPL_)SHA256) += sha256_common.o
-obj-$(CONFIG_$(XPL_)SHA256_LEGACY) += sha256.o
-obj-$(CONFIG_$(XPL_)SHA512_LEGACY) += sha512.o
+obj-$(CONFIG_$(PHASE_)MD5_LEGACY) += md5.o
+obj-$(CONFIG_$(PHASE_)SHA1_LEGACY) += sha1.o
+obj-$(CONFIG_$(PHASE_)SHA256) += sha256_common.o
+obj-$(CONFIG_$(PHASE_)SHA256_LEGACY) += sha256.o
+obj-$(CONFIG_$(PHASE_)SHA512_LEGACY) += sha512.o
obj-$(CONFIG_CRYPT_PW) += crypt/
obj-$(CONFIG_$(XPL_)ASN1_DECODER_LEGACY) += asn1_decoder.o
diff --git a/lib/crc8.c b/lib/crc8.c
index 811e19917b4..bbb229c3892 100644
--- a/lib/crc8.c
+++ b/lib/crc8.c
@@ -6,11 +6,12 @@
#ifdef USE_HOSTCC
#include <arpa/inet.h>
#endif
+#include <asm/sections.h>
#include <u-boot/crc.h>
#define POLY (0x1070U << 3)
-static unsigned char _crc8(unsigned short data)
+__rcode static unsigned char _crc8(unsigned short data)
{
int i;
@@ -23,7 +24,7 @@ static unsigned char _crc8(unsigned short data)
return (unsigned char)(data >> 8);
}
-unsigned int crc8(unsigned int crc, const unsigned char *vptr, int len)
+__rcode unsigned int crc8(unsigned int crc, const unsigned char *vptr, int len)
{
int i;
diff --git a/lib/gunzip.c b/lib/gunzip.c
index e71d8d00ccb..52007715bda 100644
--- a/lib/gunzip.c
+++ b/lib/gunzip.c
@@ -15,6 +15,7 @@
#include <u-boot/crc.h>
#include <watchdog.h>
#include <u-boot/zlib.h>
+#include <asm/sections.h>
#define HEADER0 '\x1f'
#define HEADER1 '\x8b'
@@ -43,7 +44,7 @@ void gzfree(void *x, void *addr, unsigned nb)
free (addr);
}
-int gzip_parse_header(const unsigned char *src, unsigned long len)
+__rcode int gzip_parse_header(const unsigned char *src, unsigned long len)
{
int i, flags;
@@ -71,7 +72,7 @@ int gzip_parse_header(const unsigned char *src, unsigned long len)
return i;
}
-int gunzip(void *dst, int dstlen, unsigned char *src, unsigned long *lenp)
+__rcode int gunzip(void *dst, int dstlen, unsigned char *src, unsigned long *lenp)
{
int offset = gzip_parse_header(src, *lenp);
@@ -274,8 +275,8 @@ out:
/*
* Uncompress blocks compressed with zlib without headers
*/
-int zunzip(void *dst, int dstlen, unsigned char *src, unsigned long *lenp,
- int stoponerr, int offset)
+__rcode int zunzip(void *dst, int dstlen, unsigned char *src,
+ unsigned long *lenp, int stoponerr, int offset)
{
z_stream s;
int err = 0;
diff --git a/lib/lz4.c b/lib/lz4.c
index 63955a0b178..c718659c590 100644
--- a/lib/lz4.c
+++ b/lib/lz4.c
@@ -33,15 +33,16 @@
#include <linux/bug.h>
#include <asm/unaligned.h>
#include <u-boot/lz4.h>
+#include <asm/sections.h>
#define FORCE_INLINE inline __attribute__((always_inline))
-static FORCE_INLINE u16 LZ4_readLE16(const void *src)
+__rcode static FORCE_INLINE u16 LZ4_readLE16(const void *src)
{
return get_unaligned_le16(src);
}
-static FORCE_INLINE void LZ4_copy8(void *dst, const void *src)
+__rcode static FORCE_INLINE void LZ4_copy8(void *dst, const void *src)
{
put_unaligned(get_unaligned((const u64 *)src), (u64 *)dst);
}
@@ -53,7 +54,7 @@ typedef int32_t S32;
typedef uint64_t U64;
typedef uintptr_t uptrval;
-static FORCE_INLINE void LZ4_write32(void *memPtr, U32 value)
+__rcode static FORCE_INLINE void LZ4_write32(void *memPtr, U32 value)
{
put_unaligned(value, (U32 *)memPtr);
}
@@ -63,7 +64,7 @@ static FORCE_INLINE void LZ4_write32(void *memPtr, U32 value)
**************************************/
/* customized version of memcpy, which may overwrite up to 7 bytes beyond dstEnd */
-static void LZ4_wildCopy(void* dstPtr, const void* srcPtr, void* dstEnd)
+__rcode static void LZ4_wildCopy(void *dstPtr, const void *srcPtr, void *dstEnd)
{
BYTE* d = (BYTE*)dstPtr;
const BYTE* s = (const BYTE*)srcPtr;
@@ -112,13 +113,24 @@ typedef enum { decode_full_block = 0, partial_decode = 1 } earlyEnd_directive;
#endif
/*
+ * spl_reloc needs all necessary data to be set up within its code, since the
+ * code is relocated at runtime. Unfortunately this increase code-size slightly
+ * so only do it if spl_reloc is enabled
+ */
+#if CONFIG_IS_ENABLED(RELOC_LOADER)
+#define STATIC
+#else
+#define STATIC static
+#endif
+
+/*
* LZ4_decompress_generic() :
* This generic decompression function covers all use cases.
* It shall be instantiated several times, using different sets of directives.
* Note that it is important for performance that this function really get inlined,
* in order to remove useless branches during compilation optimization.
*/
-static FORCE_INLINE int LZ4_decompress_generic(
+__rcode static FORCE_INLINE int LZ4_decompress_generic(
const char * const src,
char * const dst,
int srcSize,
@@ -141,6 +153,8 @@ static FORCE_INLINE int LZ4_decompress_generic(
const size_t dictSize
)
{
+ STATIC const unsigned int inc32table[8] = {0, 1, 2, 1, 0, 4, 4, 4};
+ STATIC const int dec64table[8] = {0, 0, 0, -1, -4, 1, 2, 3};
const BYTE *ip = (const BYTE *) src;
const BYTE * const iend = ip + srcSize;
@@ -149,8 +163,6 @@ static FORCE_INLINE int LZ4_decompress_generic(
BYTE *cpy;
const BYTE * const dictEnd = (const BYTE *)dictStart + dictSize;
- static const unsigned int inc32table[8] = {0, 1, 2, 1, 0, 4, 4, 4};
- static const int dec64table[8] = {0, 0, 0, -1, -4, 1, 2, 3};
const int safeDecode = (endOnInput == endOnInputSize);
const int checkOffset = ((safeDecode) && (dictSize < (int)(64 * KB)));
@@ -514,8 +526,9 @@ _output_error:
return (int) (-(((const char *)ip) - src)) - 1;
}
-int LZ4_decompress_safe(const char *source, char *dest,
- int compressedSize, int maxDecompressedSize)
+#ifndef CONFIG_SPL_BUILD
+__rcode int LZ4_decompress_safe(const char *source, char *dest,
+ int compressedSize, int maxDecompressedSize)
{
return LZ4_decompress_generic(source, dest,
compressedSize, maxDecompressedSize,
@@ -523,11 +536,13 @@ int LZ4_decompress_safe(const char *source, char *dest,
noDict, (BYTE *)dest, NULL, 0);
}
-int LZ4_decompress_safe_partial(const char *src, char *dst,
- int compressedSize, int targetOutputSize, int dstCapacity)
+__rcode int LZ4_decompress_safe_partial(const char *src, char *dst,
+ int compressedSize,
+ int targetOutputSize, int dstCapacity)
{
dstCapacity = min(targetOutputSize, dstCapacity);
return LZ4_decompress_generic(src, dst, compressedSize, dstCapacity,
endOnInputSize, partial_decode,
noDict, (BYTE *)dst, NULL, 0);
}
+#endif
diff --git a/lib/lz4_wrapper.c b/lib/lz4_wrapper.c
index 4d48e7b0e8b..b1204511170 100644
--- a/lib/lz4_wrapper.c
+++ b/lib/lz4_wrapper.c
@@ -15,7 +15,7 @@
#define LZ4F_BLOCKUNCOMPRESSED_FLAG 0x80000000U
-int ulz4fn(const void *src, size_t srcn, void *dst, size_t *dstn)
+__rcode int ulz4fn(const void *src, size_t srcn, void *dst, size_t *dstn)
{
const void *end = dst + *dstn;
const void *in = src;
diff --git a/lib/mbedtls/Kconfig b/lib/mbedtls/Kconfig
index aa82336ef14..35d8c507a89 100644
--- a/lib/mbedtls/Kconfig
+++ b/lib/mbedtls/Kconfig
@@ -112,6 +112,46 @@ config SPL_MD5_LEGACY
endif # SPL
+if VPL
+
+config VPL_SHA1_LEGACY
+ bool "Enable SHA1 support in VPL with legacy crypto library"
+ depends on LEGACY_CRYPTO_BASIC && VPL_SHA1
+ help
+ This option enables support of hashing using SHA1 algorithm
+ with legacy crypto library.
+
+config VPL_SHA256_LEGACY
+ bool "Enable SHA256 support in VPL with legacy crypto library"
+ depends on LEGACY_CRYPTO_BASIC && VPL_SHA256
+ help
+ This option enables support of hashing using SHA256 algorithm
+ with legacy crypto library.
+
+config VPL_SHA512_LEGACY
+ bool "Enable SHA512 support in VPL with legacy crypto library"
+ depends on LEGACY_CRYPTO_BASIC && VPL_SHA512
+ help
+ This option enables support of hashing using SHA512 algorithm
+ with legacy crypto library.
+
+config VPL_SHA384_LEGACY
+ bool "Enable SHA384 support in VPL with legacy crypto library"
+ depends on LEGACY_CRYPTO_BASIC && VPL_SHA384
+ select VPL_SHA512_LEGACY
+ help
+ This option enables support of hashing using SHA384 algorithm
+ with legacy crypto library.
+
+config VPL_MD5_LEGACY
+ bool "Enable MD5 support in VPL with legacy crypto library"
+ depends on LEGACY_CRYPTO_BASIC && VPL_MD5
+ help
+ This option enables support of hashing using MD5 algorithm
+ with legacy crypto library.
+
+endif # VPL
+
endif # LEGACY_CRYPTO_BASIC
config LEGACY_CRYPTO_CERT
diff --git a/lib/string.c b/lib/string.c
index feae9519f2f..0e0900de8bf 100644
--- a/lib/string.c
+++ b/lib/string.c
@@ -21,6 +21,7 @@
#include <linux/string.h>
#include <linux/ctype.h>
#include <malloc.h>
+#include <asm/sections.h>
/**
* strncasecmp - Case insensitive, length-limited string comparison
@@ -559,7 +560,7 @@ __used void * memset(void * s,int c,size_t count)
* You should not use this function to access IO space, use memcpy_toio()
* or memcpy_fromio() instead.
*/
-__used void * memcpy(void *dest, const void *src, size_t count)
+__rcode __used void *memcpy(void *dest, const void *src, size_t count)
{
unsigned long *dl = (unsigned long *)dest, *sl = (unsigned long *)src;
char *d8, *s8;
@@ -593,7 +594,7 @@ __used void * memcpy(void *dest, const void *src, size_t count)
*
* Unlike memcpy(), memmove() copes with overlapping areas.
*/
-__used void * memmove(void * dest,const void *src,size_t count)
+__rcode __used void *memmove(void *dest, const void *src, size_t count)
{
char *tmp, *s;
diff --git a/lib/zlib/inflate.c b/lib/zlib/inflate.c
index f7e81fc8b2a..b4c72cc2c5c 100644
--- a/lib/zlib/inflate.c
+++ b/lib/zlib/inflate.c
@@ -2,10 +2,12 @@
* Copyright (C) 1995-2005 Mark Adler
* For conditions of distribution and use, see copyright notice in zlib.h
*/
+#include <asm/sections.h>
+
local void fixedtables OF((struct inflate_state FAR *state));
local int updatewindow OF((z_streamp strm, unsigned out));
-int ZEXPORT inflateReset(z_streamp strm)
+__rcode int ZEXPORT inflateReset(z_streamp strm)
{
struct inflate_state FAR *state;
@@ -30,8 +32,8 @@ int ZEXPORT inflateReset(z_streamp strm)
return Z_OK;
}
-int ZEXPORT inflateInit2_(z_streamp strm, int windowBits,
- int stream_size)
+__rcode int ZEXPORT inflateInit2_(z_streamp strm, int windowBits,
+ int stream_size)
{
struct inflate_state FAR *state;
@@ -67,12 +69,12 @@ int ZEXPORT inflateInit2_(z_streamp strm, int windowBits,
return inflateReset(strm);
}
-int ZEXPORT inflateInit_(z_streamp strm, int stream_size)
+__rcode int ZEXPORT inflateInit_(z_streamp strm, int stream_size)
{
return inflateInit2_(strm, DEF_WBITS, stream_size);
}
-local void fixedtables(struct inflate_state FAR *state)
+__rcode local void fixedtables(struct inflate_state FAR *state)
{
state->lencode = lenfix;
state->lenbits = 9;
@@ -94,7 +96,7 @@ local void fixedtables(struct inflate_state FAR *state)
output will fall in the output data, making match copies simpler and faster.
The advantage may be dependent on the size of the processor's data caches.
*/
-local int updatewindow(z_streamp strm, unsigned out)
+__rcode local int updatewindow(z_streamp strm, unsigned int out)
{
struct inflate_state FAR *state;
unsigned copy, dist;
@@ -322,7 +324,7 @@ local int updatewindow(z_streamp strm, unsigned out)
when flush is set to Z_FINISH, inflate() cannot return Z_OK. Instead it
will return Z_BUF_ERROR if it has not reached the end of the stream.
*/
-int ZEXPORT inflate(z_streamp strm, int flush)
+__rcode int ZEXPORT inflate(z_streamp strm, int flush)
{
struct inflate_state FAR *state;
unsigned char FAR *next; /* next input */
@@ -924,7 +926,7 @@ int ZEXPORT inflate(z_streamp strm, int flush)
return ret;
}
-int ZEXPORT inflateEnd(z_streamp strm)
+__rcode int ZEXPORT inflateEnd(z_streamp strm)
{
struct inflate_state FAR *state;
if (strm == Z_NULL || strm->state == Z_NULL || strm->zfree == (free_func)0)
diff --git a/tools/Kconfig b/tools/Kconfig
index 5c75af48fe3..01ff0fcf748 100644
--- a/tools/Kconfig
+++ b/tools/Kconfig
@@ -9,6 +9,11 @@ config MKIMAGE_DTC_PATH
some cases the system dtc may not support all required features
and the path to a different version should be given here.
+config TOOLS_CRC16
+ def_bool y
+ help
+ Enable CRC32 support in the tools builds
+
config TOOLS_CRC32
def_bool y
help