From: Frieder Schrempf <[email protected]> The RAUC bootmeth uses any MMC device on which the boot partition of a slot holds a filesystem and the root partition exists. This also matches devices with a different layout, for example a single-system image or a standard distro installed to eMMC. The bootmeth then claims such a device and creates and saves its BOOT_ORDER and BOOT_x_LEFT variables in the environment, which makes it difficult to run BOOTMETH_RAUC alongside other bootmeths.
Allow to give the boot and root partitions in CONFIG_BOOTMETH_RAUC_PARTITIONS by their GPT names instead of their numbers, for example "boot_a,root_a boot_b,root_b". The bootmeth looks up the names on each device and only uses a device which has the partitions of all slots, so that it never boots a slot whose partitions are missing. As only GPT has partition names, this also rejects MBR devices. A value consisting only of digits is still taken as a partition number, which keeps the current behaviour. The bootmeth keeps the partitions in its platform data, which is set from the option when the bootmeth is bound. This allows tests to check other layouts at runtime. Also report a slot without a boot or root partition in the option, instead of passing NULL to simple_strtoul(). Assisted-by: LLM Signed-off-by: Frieder Schrempf <[email protected]> --- Changes in v2: - Give the partition names in CONFIG_BOOTMETH_RAUC_PARTITIONS instead of the new option CONFIG_BOOTMETH_RAUC_PART_NAMES (Bastien) - Only use a device which has the partitions of all slots (Simon) - Keep the partitions in the platform data of the bootmeth, so that tests can change them at runtime (Simon) - Report a slot without a boot or root partition in the option - Rename from "bootstd: rauc: Optionally check the partition names" --- MAINTAINERS | 1 + boot/Kconfig | 7 +++ boot/bootmeth_rauc.c | 108 +++++++++++++++++++++++++++++++++++++++---- doc/develop/bootstd/rauc.rst | 7 +++ include/bootmeth_rauc.h | 22 +++++++++ 5 files changed, 136 insertions(+), 9 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index af3ca0f1bf2..63bed54e8bf 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -846,6 +846,7 @@ F: drivers/mmc/mmc_bootdev.c F: include/bootdev.h F: include/bootflow.h F: include/bootmeth.h +F: include/bootmeth_rauc.h F: include/bootstd.h F: test/boot/ diff --git a/boot/Kconfig b/boot/Kconfig index d4d2a77f15a..072108db64a 100644 --- a/boot/Kconfig +++ b/boot/Kconfig @@ -969,6 +969,13 @@ config BOOTMETH_RAUC_PARTITIONS The first value in pair is for the boot partition and second for the root partition. + Instead of an index, a value can also be the name of a GPT partition, + for example "boot_a,root_a boot_b,root_b". A device is then only used + if it has partitions with these names for all slots, so the bootmeth + does not claim devices with a different layout. As only GPT has + partition names, this also rejects MBR devices. A value consisting + only of digits is always taken as an index. + config BOOTMETH_RAUC_DEFAULT_TRIES int "RAUC slot default tries" default 3 diff --git a/boot/bootmeth_rauc.c b/boot/bootmeth_rauc.c index a32f19303a5..acf9413591b 100644 --- a/boot/bootmeth_rauc.c +++ b/boot/bootmeth_rauc.c @@ -11,6 +11,7 @@ #include <blk.h> #include <bootflow.h> #include <bootmeth.h> +#include <bootmeth_rauc.h> #include <bootstd.h> #include <dm.h> #include <env.h> @@ -38,11 +39,17 @@ static const char * const script_names[] = { "boot.scr", "boot.scr.uimg", NULL } * @name The slot name * @boot_part The boot partition number on disk * @root_part The root partition number on disk + * @boot_part_name The name of the boot partition, or NULL if it is given by + * its number + * @root_part_name The name of the root partition, or NULL if it is given by + * its number */ struct distro_rauc_slot { char *name; int boot_part; int root_part; + char *boot_part_name; + char *root_part_name; }; /** @@ -55,14 +62,20 @@ struct distro_rauc_priv { struct distro_rauc_slot **slots; }; +static void distro_rauc_slot_free(struct distro_rauc_slot *slot) +{ + free(slot->name); + free(slot->boot_part_name); + free(slot->root_part_name); + free(slot); +} + static void distro_rauc_priv_free(struct distro_rauc_priv *priv) { int i; - for (i = 0; priv->slots[i]; i++) { - free(priv->slots[i]->name); - free(priv->slots[i]); - } + for (i = 0; priv->slots[i]; i++) + distro_rauc_slot_free(priv->slots[i]); free(priv->slots); free(priv); } @@ -89,6 +102,60 @@ static struct distro_rauc_slot *get_slot(struct distro_rauc_priv *priv, return NULL; } +/** + * distro_rauc_parse_part() - Parse a partition of a slot + * + * @str: Partition number, or name of a GPT partition + * @part: Returns the partition number, if @str is a number + * @name: Returns a copy of @str, if it is not a number + * Return: 0 if OK, -EINVAL if @str is empty, -ENOMEM if out of memory + */ +static int distro_rauc_parse_part(const char *str, int *part, char **name) +{ + if (!str || !*str) + return log_msg_ret("part", -EINVAL); + + if (strspn(str, "0123456789") == strlen(str)) { + *part = simple_strtoul(str, NULL, 10); + return 0; + } + + *name = strdup(str); + if (!*name) + return log_msg_ret("buf", -ENOMEM); + + return 0; +} + +/** + * distro_rauc_find_parts() - Find the partitions of a slot by their names + * + * @desc: Block device to search + * @slot: Slot to update, if its partitions are given by name + * Return: 0 if OK, -ENOENT if a partition was not found + */ +static int distro_rauc_find_parts(struct blk_desc *desc, + struct distro_rauc_slot *slot) +{ + struct disk_partition info; + int part; + + if (slot->boot_part_name) { + part = part_get_info_by_name(desc, slot->boot_part_name, &info); + if (part < 0) + return log_msg_ret("boot", -ENOENT); + slot->boot_part = part; + } + if (slot->root_part_name) { + part = part_get_info_by_name(desc, slot->root_part_name, &info); + if (part < 0) + return log_msg_ret("root", -ENOENT); + slot->root_part = part; + } + + return 0; +} + static int distro_rauc_check(struct udevice *dev, struct bootflow_iter *iter) { /* @@ -121,6 +188,15 @@ static int distro_rauc_scan_parts(struct bootflow *bflow) if (!priv || !priv->slots) return log_msg_ret("priv", -EINVAL); + /* With partition names, the partitions of all slots must exist */ + if (desc) { + for (i = 0; priv->slots[i]; i++) { + ret = distro_rauc_find_parts(desc, priv->slots[i]); + if (ret) + return ret; + } + } + /* BOOT_ORDER is only set once a device has been found */ boot_order = env_get("BOOT_ORDER"); if (!boot_order) @@ -198,6 +274,7 @@ static int distro_rauc_set_defaults(void) static int distro_rauc_read_bootflow(struct udevice *dev, struct bootflow *bflow) { + const struct distro_rauc_plat *rplat = dev_get_plat(dev); struct distro_rauc_priv *priv = NULL; int ret = 0; char *slot; @@ -226,7 +303,7 @@ static int distro_rauc_read_bootflow(struct udevice *dev, struct bootflow *bflow ret = log_msg_ret("buf", -ENOMEM); goto rauc_read_bootflow_err; } - partitions = strdup(CONFIG_BOOTMETH_RAUC_PARTITIONS); + partitions = strdup(rplat->partitions); if (!partitions) { ret = log_msg_ret("buf", -ENOMEM); goto rauc_read_bootflow_err; @@ -252,13 +329,23 @@ static int distro_rauc_read_bootflow(struct udevice *dev, struct bootflow *bflow ret = log_msg_ret("buf", -ENOMEM); goto rauc_read_bootflow_err; } - s->boot_part = simple_strtoul(strsep(&parts, ","), NULL, 10); - s->root_part = simple_strtoul(strsep(&parts, ","), NULL, 10); + ret = distro_rauc_parse_part(strsep(&parts, ","), &s->boot_part, + &s->boot_part_name); + if (!ret) + ret = distro_rauc_parse_part(strsep(&parts, ","), + &s->root_part, + &s->root_part_name); + if (ret) { + if (ret == -EINVAL) + log_err("ERROR: Invalid partitions for slot %s\n", + slot); + distro_rauc_slot_free(s); + goto rauc_read_bootflow_err; + } new_slots = realloc(priv->slots, (i + 1) * sizeof(struct distro_rauc_slot)); if (!new_slots) { - free(s->name); - free(s); + distro_rauc_slot_free(s); ret = log_msg_ret("buf", -ENOMEM); goto rauc_read_bootflow_err; } @@ -527,9 +614,11 @@ static int distro_rauc_boot(struct udevice *dev, struct bootflow *bflow) static int distro_rauc_bootmeth_bind(struct udevice *dev) { struct bootmeth_uc_plat *plat = dev_get_uclass_plat(dev); + struct distro_rauc_plat *rplat = dev_get_plat(dev); plat->desc = "RAUC distro boot from MMC"; plat->flags = BOOTMETHF_ANY_PART; + rplat->partitions = CONFIG_BOOTMETH_RAUC_PARTITIONS; return 0; } @@ -552,4 +641,5 @@ U_BOOT_DRIVER(bootmeth_rauc) = { .of_match = distro_rauc_bootmeth_ids, .ops = &distro_rauc_bootmeth_ops, .bind = distro_rauc_bootmeth_bind, + .plat_auto = sizeof(struct distro_rauc_plat), }; diff --git a/doc/develop/bootstd/rauc.rst b/doc/develop/bootstd/rauc.rst index 5afd705dcb1..eee8d103fb9 100644 --- a/doc/develop/bootstd/rauc.rst +++ b/doc/develop/bootstd/rauc.rst @@ -14,6 +14,13 @@ filesystem each. The partition numbers must be specified with the following syntax: ``1,2 3,4``, where 1 and 3 are the slots' boot partition and 2 and 4 the slots' root partition. +Instead of their numbers, the partitions can also be given by their GPT +partition names, for example ``boot_a,root_a boot_b,root_b``. The bootmeth then +only uses a device if it has partitions with these names for all slots. This +prevents it from claiming devices with a different layout which happen to have +a filesystem in the first partition. A value consisting only of digits is +always taken as a partition number. + Each pair of boot and rootfs partition form a "slot". The default order in which available slots are tried is set through ``CONFIG_BOOTMETH_RAUC_BOOT_ORDER``, with the left one tried first. diff --git a/include/bootmeth_rauc.h b/include/bootmeth_rauc.h new file mode 100644 index 00000000000..0faeab192d4 --- /dev/null +++ b/include/bootmeth_rauc.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Bootmethod for distro boot with RAUC + */ + +#ifndef __BOOTMETH_RAUC_H +#define __BOOTMETH_RAUC_H + +/** + * struct distro_rauc_plat - Platform data of the RAUC bootmeth + * + * This is set from Kconfig when the bootmeth is bound. Tests can change it + * afterwards to check other configurations. + * + * @partitions: Boot and root partitions of each slot, given by number or + * by name, see CONFIG_BOOTMETH_RAUC_PARTITIONS + */ +struct distro_rauc_plat { + const char *partitions; +}; + +#endif -- 2.56.0
