Some disk layouts store a U-Boot script image directly in a named partition, without a filesystem. Add a script_raw bootmeth to find these images without a board-specific bootcmd.
Read the image size from the first block and bound it by the partition size and configured limit. Support legacy scripts and FIT scripts with embedded data, using the shared script parser for validation and the shared execution handler for booting. Keep raw-partition scanning independently selectable from filesystem script lookup. Document the configuration and self-contained FIT policy. Signed-off-by: He Yong <[email protected]> --- Changes in v3: - Move shared FIT checks, handler export and sandbox tests to separate patches. MAINTAINERS | 1 + boot/Kconfig | 26 +++++ boot/Makefile | 1 + boot/bootmeth_script_raw.c | 152 ++++++++++++++++++++++++++ doc/develop/bootstd/index.rst | 1 + doc/develop/bootstd/script_raw.rst | 51 +++++++++ doc/device-tree-bindings/bootmeth.txt | 1 + 7 files changed, 233 insertions(+) create mode 100644 boot/bootmeth_script_raw.c create mode 100644 doc/develop/bootstd/script_raw.rst diff --git a/MAINTAINERS b/MAINTAINERS index d1f51d9197d..6870298ee0f 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -846,6 +846,7 @@ F: include/bootflow.h F: include/bootmeth.h F: include/bootstd.h F: test/boot/ +F: test/py/img/script_raw.py BOOTMETH_ANDROID M: Mattijs Korpershoek <[email protected]> diff --git a/boot/Kconfig b/boot/Kconfig index 8fcdc36c931..990c8bc0110 100644 --- a/boot/Kconfig +++ b/boot/Kconfig @@ -1009,6 +1009,32 @@ config BOOTMETH_SCRIPT This provides a way to try out standard boot on an existing boot flow. It is not enabled by default to save space. +config BOOTMETH_SCRIPT_RAW + bool "Boot from a script in a raw partition" + depends on BOOTMETH_SCRIPT && BLK && PARTITIONS + depends on LEGACY_IMAGE_FORMAT || FIT + help + Locate a named partition and read a U-Boot script image directly from + its first block, without a filesystem. This adds the script_raw boot + method. Legacy script images and FIT scripts with embedded data are + supported. + +config BOOTMETH_SCRIPT_RAW_PARTITION + string "Raw script partition name" + depends on BOOTMETH_SCRIPT_RAW + default "uboot_scr" + help + Partition label to match when scanning for a raw script image. + +config BOOTMETH_SCRIPT_RAW_MAX_SIZE + hex "Maximum raw script image size" + depends on BOOTMETH_SCRIPT_RAW + default 0x100000 + range 0x200 0x1000000 + help + Maximum script image size in bytes, including its image header. + The image must also fit within the selected partition. + config UPL bool "upl - Universal Payload Specification" imply CMD_UPL diff --git a/boot/Makefile b/boot/Makefile index f2cbda176a0..12649286601 100644 --- a/boot/Makefile +++ b/boot/Makefile @@ -38,6 +38,7 @@ obj-$(CONFIG_$(PHASE_)BOOTMETH_QFW) += bootmeth_qfw.o obj-$(CONFIG_$(PHASE_)BOOTMETH_RAUC) += bootmeth_rauc.o obj-$(CONFIG_$(PHASE_)BOOTMETH_SANDBOX) += bootmeth_sandbox.o obj-$(CONFIG_$(PHASE_)BOOTMETH_SCRIPT) += bootmeth_script.o +obj-$(CONFIG_$(PHASE_)BOOTMETH_SCRIPT_RAW) += bootmeth_script_raw.o obj-$(CONFIG_$(PHASE_)CEDIT) += cedit.o obj-$(CONFIG_$(PHASE_)BOOTMETH_EFI_BOOTMGR) += bootmeth_efi_mgr.o diff --git a/boot/bootmeth_script_raw.c b/boot/bootmeth_script_raw.c new file mode 100644 index 00000000000..53913f20e98 --- /dev/null +++ b/boot/bootmeth_script_raw.c @@ -0,0 +1,152 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Bootmethod for scripts stored in a raw partition + * + * Copyright 2026 He Yong <[email protected]> + */ + +#define LOG_CATEGORY UCLASS_BOOTSTD + +#include <blk.h> +#include <bootflow.h> +#include <bootmeth.h> +#include <dm.h> +#include <image.h> +#include <malloc.h> +#include <mapmem.h> +#include <part.h> +#include <asm/cache.h> + +static int script_raw_check(struct udevice *dev, struct bootflow_iter *iter) +{ + return bootflow_iter_check_blk(iter); +} + +static int script_raw_read_bootflow(struct udevice *dev, struct bootflow *bflow) +{ + struct legacy_img_hdr *hdr; + struct disk_partition info; + struct blk_desc *desc; + lbaint_t count; + uint size, len; + char *data; + void *buf; + int ret; + + if (!bflow->blk || !bflow->part) + return log_msg_ret("part", -ENOENT); + desc = dev_get_uclass_plat(bflow->blk); + ret = part_get_info(desc, bflow->part, &info); + if (ret) + return log_msg_ret("part", ret); + if (strcmp(info.name, CONFIG_BOOTMETH_SCRIPT_RAW_PARTITION)) + return log_msg_ret("name", -ENOENT); + bflow->state = BOOTFLOWST_PART; + + if (!info.size || desc->blksz < sizeof(*hdr) || + desc->blksz > CONFIG_BOOTMETH_SCRIPT_RAW_MAX_SIZE) + return log_msg_ret("block", -EINVAL); + buf = memalign(ARCH_DMA_MINALIGN, desc->blksz); + if (!buf) + return log_msg_ret("buf", -ENOMEM); + if (blk_dread(desc, info.start, 1, buf) != 1) { + ret = log_msg_ret("header-read", -EIO); + goto out; + } + + hdr = buf; + if (IS_ENABLED(CONFIG_LEGACY_IMAGE_FORMAT) && + genimg_get_format(buf) == IMAGE_FORMAT_LEGACY) { + if (!image_check_hcrc(hdr)) { + ret = log_msg_ret("header", -EINVAL); + goto out; + } + size = image_get_data_size(hdr); + if (size > CONFIG_BOOTMETH_SCRIPT_RAW_MAX_SIZE - sizeof(*hdr)) { + ret = log_msg_ret("legacy-size", -E2BIG); + goto out; + } + size += sizeof(*hdr); + } else if (IS_ENABLED(CONFIG_FIT) && !fdt_check_header(buf)) { + size = fdt_totalsize(buf); + if (size < sizeof(struct fdt_header)) { + ret = log_msg_ret("fit-size", -EINVAL); + goto out; + } + } else { + ret = log_msg_ret("format", -ENOEXEC); + goto out; + } + if (size > CONFIG_BOOTMETH_SCRIPT_RAW_MAX_SIZE) { + ret = log_msg_ret("size", -E2BIG); + goto out; + } + count = DIV_ROUND_UP(size, desc->blksz); + if (count > info.size) { + ret = log_msg_ret("partition-size", -E2BIG); + goto out; + } + free(buf); + buf = memalign(ARCH_DMA_MINALIGN, count * desc->blksz + 1); + if (!buf) + return log_msg_ret("buf", -ENOMEM); + if (blk_dread(desc, info.start, count, buf) != count) { + ret = log_msg_ret("image-read", -EIO); + goto out; + } + ((char *)buf)[size] = '\0'; + ret = image_locate_script(buf, size, NULL, NULL, &data, &len); + if (ret) { + ret = log_msg_ret("script", -EINVAL); + goto out; + } + + bflow->fname = strdup(CONFIG_BOOTMETH_SCRIPT_RAW_PARTITION); + bflow->subdir = strdup(""); + if (!bflow->fname || !bflow->subdir) { + ret = log_msg_ret("name-alloc", -ENOMEM); + goto out; + } + if (!bootflow_img_add(bflow, bflow->fname, (enum bootflow_img_t)IH_TYPE_SCRIPT, + map_to_sysmem(buf), size)) { + ret = log_msg_ret("image-alloc", -ENOMEM); + goto out; + } + bflow->buf = buf; + bflow->size = size; + bflow->state = BOOTFLOWST_READY; + + return 0; +out: + free(buf); + return ret; +} + +static int script_raw_bootmeth_bind(struct udevice *dev) +{ + struct bootmeth_uc_plat *plat = dev_get_uclass_plat(dev); + + plat->desc = "Script boot from a raw partition"; + plat->flags = BOOTMETHF_ANY_PART; + + return 0; +} + +static struct bootmeth_ops script_raw_bootmeth_ops = { + .check = script_raw_check, + .read_bootflow = script_raw_read_bootflow, + .boot = bootmeth_script_boot, +}; + +static const struct udevice_id script_raw_bootmeth_ids[] = { + { .compatible = "u-boot,script-raw" }, + { } +}; + +U_BOOT_DRIVER(bootmeth_2script_raw) = { + .name = "bootmeth_script_raw", + .id = UCLASS_BOOTMETH, + .of_match = script_raw_bootmeth_ids, + .ops = &script_raw_bootmeth_ops, + .bind = script_raw_bootmeth_bind, +}; diff --git a/doc/develop/bootstd/index.rst b/doc/develop/bootstd/index.rst index 9271b5eef14..0a2452a44c2 100644 --- a/doc/develop/bootstd/index.rst +++ b/doc/develop/bootstd/index.rst @@ -15,4 +15,5 @@ Standard Boot cros rauc script + script_raw sandbox diff --git a/doc/develop/bootstd/script_raw.rst b/doc/develop/bootstd/script_raw.rst new file mode 100644 index 00000000000..29a63c0ceb7 --- /dev/null +++ b/doc/develop/bootstd/script_raw.rst @@ -0,0 +1,51 @@ +.. SPDX-License-Identifier: GPL-2.0+ + +Raw Script Bootmeth +=================== + +The ``script_raw`` bootmeth reads a script image from the start of a named +partition on a block device, without a filesystem. Enable +``CONFIG_BOOTMETH_SCRIPT`` and ``CONFIG_BOOTMETH_SCRIPT_RAW`` to build it. +The partition name is selected by ``CONFIG_BOOTMETH_SCRIPT_RAW_PARTITION`` +and defaults to ``uboot_scr``. The partition need not be marked bootable. + +The method reads the first block to determine the image size, then reads the +complete image. The image must fit within the partition and the limit set by +``CONFIG_BOOTMETH_SCRIPT_RAW_MAX_SIZE`` (1 MiB by default). It supports legacy +U-Boot script images and FIT scripts with embedded data. FIT external data is +not supported: script FITs are small and must be self-contained so that all +metadata and script data can be validated within the loaded partition image. + +Plain text scripts must first be wrapped with ``mkimage``, for example:: + + mkimage -A arm64 -T script -C none -n 'Boot script' -d boot.cmd boot.scr + +Write ``boot.scr`` directly at the start of the ``uboot_scr`` partition when +creating the disk image. There is no filename lookup on the target partition. +Image validation is performed before the bootflow is marked ready, using the +same verification policy as ``source`` (including the ``verify`` environment +variable). + +To scan only this bootmeth on MMC device 0:: + + bootmeth order script_raw + bootflow scan -lb mmc0 + +To use the configured bootmeth order for normal automatic boot, set +``CONFIG_BOOTCOMMAND="bootflow scan -lb"``. Existing saved environments may +override this default; check ``printenv bootcmd bootmeths boot_targets``. +Restore the default bootmeth order with ``bootmeth order`` if necessary. + +The script is executed from the bootflow's allocated buffer, so ``scriptaddr`` +is not required. Before execution, the method sets ``devtype``, ``devnum`` and +``distro_bootpart`` as described in :doc:`script`, with an empty ``prefix``. +The script itself is responsible for selecting and booting an A/B slot. + +A separate bootmeth keeps raw-partition scanning independent of the existing +filesystem script lookup and allows either method to be selected in the bootmeth +order. Both methods share the script execution handler and verification policy. + +The compatible string is ``u-boot,script-raw``. On boards which explicitly +declare bootmeth devices in their device tree, add a child node with this +compatible under the ``bootstd`` node. Otherwise standard boot automatically +binds the enabled bootmeth drivers. diff --git a/doc/device-tree-bindings/bootmeth.txt b/doc/device-tree-bindings/bootmeth.txt index 127b09cd1b2..6886842b8f3 100644 --- a/doc/device-tree-bindings/bootmeth.txt +++ b/doc/device-tree-bindings/bootmeth.txt @@ -11,6 +11,7 @@ compatible: "u-boot,extlinux-pxe" - distro boot from a network device "u-boot,distro-efi" - EFI boot from an .efi file "u-boot,efi-bootmgr" - EFI boot using boot manager (bootmgr) + "u-boot,script-raw" - script boot from a named raw partition Example: -- 2.43.0
