mail archive of the barebox mailing list
 help / color / mirror / Atom feed
From: Ahmad Fatoum <a.fatoum@pengutronix.de>
To: barebox@lists.infradead.org
Cc: Ahmad Fatoum <a.fatoum@pengutronix.de>
Subject: [PATCH 6/7] ARM: add support for chainloading barebox inside FIP images
Date: Wed,  9 Apr 2025 16:01:34 +0200	[thread overview]
Message-ID: <20250409140134.2079552-7-a.fatoum@pengutronix.de> (raw)
In-Reply-To: <20250409140134.2079552-1-a.fatoum@pengutronix.de>

For use on the STM32MP1, add a bootm handler for chainloading FIP
images. This removes the last remaining use case for SSBL .stm32 images,
after TF-A had dropped support late 2022.

Signed-off-by: Ahmad Fatoum <a.fatoum@pengutronix.de>
---
 arch/arm/Kconfig             |  11 ++
 arch/arm/cpu/Makefile        |   1 +
 arch/arm/cpu/bootm-fip.c     | 276 +++++++++++++++++++++++++++++++++++
 arch/arm/mach-stm32mp/init.c |  10 ++
 include/fiptool.h            |  13 ++
 5 files changed, 311 insertions(+)
 create mode 100644 arch/arm/cpu/bootm-fip.c

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index ab7ff5369b20..84b1660d1ed9 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -473,6 +473,17 @@ config ARM_BOOTM_ELF
 	help
 	  Add support to load elf file with bootm.
 
+config ARM_BOOTM_FIP
+	bool
+	depends on BOOTM
+	select FIP
+	prompt "FIP loading support"
+	default ARCH_STM32MP
+	help
+	  Add support to load FIP file with bootm.
+	  This allows barebox to chainload barebox on platforms where it
+	  is located inside a FIP. This can be useful during development.
+
 config ARM_ATF
 	bool
 
diff --git a/arch/arm/cpu/Makefile b/arch/arm/cpu/Makefile
index d59aae1ee55c..39e59c2a2f73 100644
--- a/arch/arm/cpu/Makefile
+++ b/arch/arm/cpu/Makefile
@@ -32,6 +32,7 @@ obj-$(CONFIG_CMD_ARM_CPUINFO) += cpuinfo.o
 obj-$(CONFIG_MMUINFO) += mmuinfo.o mmuinfo_$(S64_32).o
 obj-$(CONFIG_OFDEVICE) += dtb.o
 obj-$(CONFIG_ARM_BOOTM_ELF)	+= bootm-elf.o
+obj-$(CONFIG_ARM_BOOTM_FIP)	+= bootm-fip.o
 
 ifeq ($(CONFIG_MMU),)
 obj-$(CONFIG_CPU_32v7) += no-mmu.o
diff --git a/arch/arm/cpu/bootm-fip.c b/arch/arm/cpu/bootm-fip.c
new file mode 100644
index 000000000000..89201ade5f12
--- /dev/null
+++ b/arch/arm/cpu/bootm-fip.c
@@ -0,0 +1,276 @@
+// SPDX-License-Identifier: GPL-2.0-only
+
+#define pr_fmt(fmt) "bootm-fip: " fmt
+
+#include <bootm.h>
+#include <common.h>
+#include <init.h>
+#include <memory.h>
+#include <linux/sizes.h>
+#include <asm/boot.h>
+#include <fip.h>
+#include <libfile.h>
+#include <bootm.h>
+#include <fiptool.h>
+
+const struct fip_binding *fip_bindings;
+
+#define for_each_fip_binding(bindings, binding) \
+	for (binding = bindings; !uuid_is_null(&binding->uuid); binding++)
+
+static inline struct resource *desc_get_res(struct fip_image_desc *desc)
+{
+	return desc->private_data;
+}
+
+static inline void desc_set_res(struct fip_image_desc *desc,
+				struct resource *res)
+{
+	desc->private_data = res;
+}
+
+static int desc_to_sdram(struct fip_image_desc *loadable, ulong load_address)
+{
+	struct resource *res;
+
+	if (desc_get_res(loadable))
+		return 0;
+
+	res = request_sdram_region("fip", load_address,
+				   loadable->image->toc_e.size);
+	if (!res)
+		return -EBUSY;
+
+	memcpy((void *)res->start,
+	       loadable->image->buffer, loadable->image->toc_e.size);
+
+	desc_set_res(loadable, res);
+
+	return 0;
+}
+
+static void desc_release_sdram(struct fip_image_desc *loadable)
+{
+	struct resource *res = loadable ? desc_get_res(loadable) : NULL;
+	if (res)
+		release_sdram_region(res);
+}
+
+enum { IMAGE_BL33, IMAGE_HW_CONFIG, IMAGE_COUNT };
+
+static int parse_dtb_registry(struct fip_image_desc *fw_config_desc,
+			      struct fip_image_desc *loadables[],
+			      int verbose)
+{
+	struct fip_toc_entry *toc_entry = &fw_config_desc->image->toc_e;
+	struct device_node *fw_config, *fconf = NULL, *image, *tmp;
+	const struct fip_binding *binding;
+	void *buf;
+	int ret = 0;
+
+	if (!fip_bindings) {
+		if (verbose)
+			printf("Platform registered no FIP bindings. Skipping firmware config\n");
+		return 0;
+	}
+
+	/* We have no alignment guarantees for the buffer, so we need to copy it */
+	buf = xmemdup(fw_config_desc->image->buffer, toc_entry->size);
+
+	fw_config = of_unflatten_dtb(buf, toc_entry->size);
+	if (!IS_ERR(fw_config))
+		fconf = of_find_compatible_node(fw_config, NULL,
+						"fconf,dyn_cfg-dtb_registry");
+	if (!fconf) {
+		pr_warn("error parsing fw_config devicetree\n");
+		goto out;
+	}
+
+	for_each_fip_binding(fip_bindings, binding) {
+		for_each_child_of_node_safe(fconf, tmp, image) {
+			u64 load_addr;
+			u32 id;
+			int ret;
+
+			ret = of_property_read_u32(image, "id", &id);
+			if (ret)
+				continue;
+
+			ret = of_property_read_u64(image, "load-address", &load_addr);
+			if (ret || load_addr > ULONG_MAX)
+				continue;
+
+			if (id != binding->id)
+				continue;
+
+			for (int i = 0; i < IMAGE_COUNT; i++) {
+				struct fip_image_desc *loadable = loadables[i];
+
+				if (!loadable)
+					continue;
+
+				if (!uuid_equal(&binding->uuid,
+						&loadable->image->toc_e.uuid))
+					continue;
+
+				ret = desc_to_sdram(loadable, load_addr);
+				if (ret) {
+					pr_warn("load address 0x%08llx for image ID %u"
+						" conflicts with reservation\n",
+						load_addr, binding->id);
+					goto out;
+				}
+
+				if (verbose > 1)
+					printf("loaded image ID %u to address 0x%08llx\n",
+						binding->id, load_addr);
+				break;
+			}
+
+			/* No need to iterate over this node again, so drop it */
+			of_delete_node(image);
+		}
+	}
+
+out:
+	if (!IS_ERR(fw_config))
+		of_delete_node(fw_config);
+	free(buf);
+	return ret;
+}
+
+static int fip_load(struct image_data *data,
+		    struct fip_image_desc *fw_config_desc,
+		    struct fip_image_desc *loadables[])
+{
+	resource_size_t start, end;
+	int ret;
+
+	if (UIMAGE_IS_ADDRESS_VALID(data->os_address)) {
+		ret = desc_to_sdram(loadables[IMAGE_BL33], data->os_address);
+		if (ret)
+			return ret;
+	}
+
+	if (fw_config_desc) {
+		ret = parse_dtb_registry(fw_config_desc, loadables, data->verbose);
+		if (ret)
+			return ret;
+	}
+
+	ret = memory_bank_first_find_space(&start, &end);
+	if (ret)
+		return ret;
+
+	for (int i = 0; i < IMAGE_COUNT; i++) {
+		struct fip_image_desc *loadable = loadables[i];
+
+		if (!loadable || desc_get_res(loadable))
+			continue;
+
+		start = ALIGN(start, SZ_4K);
+
+		ret = desc_to_sdram(loadable, start);
+		if (ret)
+			return ret;
+
+		/* Leave a stack's worth of space after each artifact;
+		 * The STM32MP1 barebox entry point depends on it.
+		 */
+		start += resource_size(desc_get_res(loadable));
+		start += CONFIG_STACK_SIZE;
+		start = ALIGN(start, 16);
+	}
+
+	return 0;
+}
+
+static const uuid_t uuid_bl33 = UUID_NON_TRUSTED_FIRMWARE_BL33;
+static const uuid_t uuid_hwconfig = UUID_HW_CONFIG;
+static const uuid_t uuid_fwconfig = UUID_FW_CONFIG;
+
+static int do_bootm_fip(struct image_data *data)
+{
+	struct fip_image_desc *fwconfig = NULL;
+	struct fip_image_desc *loadables[IMAGE_COUNT] = {};
+	struct fip_image_desc *desc;
+	struct fip_state *fip;
+	int ret;
+
+	if (!data->os_file)
+		return -EINVAL;
+
+	fip = fip_new();
+	ret = fip_parse(fip, data->os_file, NULL);
+	if (ret)
+		goto out;
+
+	fip_for_each_desc(fip, desc) {
+		struct fip_toc_entry *toc_entry = &desc->image->toc_e;
+
+		if (uuid_equal(&toc_entry->uuid, &uuid_bl33))
+			loadables[IMAGE_BL33] = desc;
+		else if (uuid_equal(&toc_entry->uuid, &uuid_hwconfig))
+			loadables[IMAGE_HW_CONFIG] = desc;
+		else if (uuid_equal(&toc_entry->uuid, &uuid_fwconfig))
+			fwconfig = desc;
+	}
+
+	if (!loadables[IMAGE_BL33]) {
+		pr_err("FIP is missing BL33 image to chainload\n");
+		ret = -ENOENT;
+		goto out;
+	}
+
+	ret = fip_load(data, fwconfig, loadables);
+	if (ret)
+		goto out;
+
+	if (data->verbose) {
+		printf("Loaded non-trusted firmware to 0x%08lx",
+		       (ulong)desc_get_res(loadables[IMAGE_BL33])->start);
+		if (loadables[IMAGE_HW_CONFIG])
+			printf(", hardware config to 0x%08lx",
+			       (ulong)desc_get_res(loadables[IMAGE_HW_CONFIG])->start);
+		printf("\n");
+	}
+
+	if (data->dryrun) {
+		ret = 0;
+		goto out;
+	}
+
+	shutdown_barebox();
+
+	/* We don't actually expect NT FW to be a Linux image, but
+	 * we want to use the Linux boot calling convention
+	 */
+	jump_to_linux((void *)desc_get_res(loadables[IMAGE_BL33])->start,
+		      desc_get_res(loadables[IMAGE_HW_CONFIG])->start);
+
+	ret = -EIO;
+out:
+	for (int i = 0; i < IMAGE_COUNT; i++)
+		desc_release_sdram(loadables[i]);
+
+	if (fip)
+		fip_free(fip);
+	return ret;
+}
+
+void plat_set_fip_bindings(const struct fip_binding *bindings)
+{
+	fip_bindings = bindings;
+}
+
+struct image_handler fip_image_handler = {
+	.name = "FIP",
+	.bootm = do_bootm_fip,
+	.filetype = filetype_fip,
+};
+
+static int stm32mp_register_fip_bootm_handler(void)
+{
+	return register_image_handler(&fip_image_handler);
+}
+late_initcall(stm32mp_register_fip_bootm_handler);
diff --git a/arch/arm/mach-stm32mp/init.c b/arch/arm/mach-stm32mp/init.c
index 1c7f62dbb033..422218e18e5a 100644
--- a/arch/arm/mach-stm32mp/init.c
+++ b/arch/arm/mach-stm32mp/init.c
@@ -13,6 +13,7 @@
 #include <mach/stm32mp/revision.h>
 #include <mach/stm32mp/bootsource.h>
 #include <bootsource.h>
+#include <fiptool.h>
 #include <dt-bindings/pinctrl/stm32-pinfunc.h>
 
 /* Package = bit 27:29 of OTP16
@@ -236,6 +237,13 @@ unsigned stm32mp_soc_code(void)
 	return __st32mp_soc;
 }
 
+static const struct fip_binding stm32mp_fip_handler[] = {
+	{  1, UUID_FW_CONFIG },
+	{  2, UUID_HW_CONFIG },
+	{  5, UUID_NON_TRUSTED_FIRMWARE_BL33 },
+	{ /* sentinel */ }
+};
+
 static int stm32mp_init(void)
 {
 	u32 boot_ctx;
@@ -264,6 +272,8 @@ static int stm32mp_init(void)
 
 	setup_boot_mode(boot_ctx);
 
+	plat_set_fip_bindings(stm32mp_fip_handler);
+
 	return 0;
 }
 postcore_initcall(stm32mp_init);
diff --git a/include/fiptool.h b/include/fiptool.h
index 1a0dbe0e6975..8cb1f7d3959d 100644
--- a/include/fiptool.h
+++ b/include/fiptool.h
@@ -104,4 +104,17 @@ struct fip_state *fip_image_open(const char *filename, size_t offset);
 
 int fip_sha256(struct fip_state *fip, char *hash);
 
+struct fip_binding {
+	unsigned id;
+	uuid_t uuid;
+};
+
+#ifdef CONFIG_ARM_BOOTM_FIP
+void plat_set_fip_bindings(const struct fip_binding *bindings);
+#else
+static inline void plat_set_fip_bindings(const struct fip_binding *bindings)
+{
+}
+#endif
+
 #endif /* FIPTOOL_H */
-- 
2.39.5




  parent reply	other threads:[~2025-04-09 14:40 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-04-09 14:01 [PATCH 0/7] " Ahmad Fatoum
2025-04-09 14:01 ` [PATCH 1/7] fip: add struct fip_image_desc::private_data Ahmad Fatoum
2025-04-09 14:01 ` [PATCH 2/7] fip: mark predefined toc_entries array const Ahmad Fatoum
2025-04-09 14:01 ` [PATCH 3/7] bootm: implement UIMAGE_IS_ADDRESS_VALID helper Ahmad Fatoum
2025-04-09 14:01 ` [PATCH 4/7] ARM: legacy: make architecture number unsigned Ahmad Fatoum
2025-04-09 14:01 ` [PATCH 5/7] ARM: introduce jump_to_linux helper Ahmad Fatoum
2025-04-09 14:01 ` Ahmad Fatoum [this message]
2025-04-09 14:01 ` [PATCH 7/7] ARM: stm32mp: retire non-FIP stm32mp_bbu_mmc_register_handler Ahmad Fatoum

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20250409140134.2079552-7-a.fatoum@pengutronix.de \
    --to=a.fatoum@pengutronix.de \
    --cc=barebox@lists.infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox