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

Reply via email to