mail archive of the barebox mailing list
 help / color / mirror / Atom feed
From: Sascha Hauer <s.hauer@pengutronix.de>
To: Ahmad Fatoum <a.fatoum@barebox.org>
Cc: barebox@lists.infradead.org
Subject: Re: [PATCH 2/5] blspec: sort entries according to specification
Date: Mon, 23 Feb 2026 12:06:17 +0100	[thread overview]
Message-ID: <aZw0qQVz1mX1l8nV@pengutronix.de> (raw)
In-Reply-To: <20260209090911.3561875-3-a.fatoum@barebox.org>

On Mon, Feb 09, 2026 at 10:08:52AM +0100, Ahmad Fatoum wrote:
> Boot entries generated from bootloader spec are currently sorted by the
> order the files are read from the file system.
> 
> This is inadequate if we have multiple entries with different kernels
> and we want to sort the newer kernels higher.
> 
> The UAPI.1 Boot Loader Specification defines an algorithm[1] to order the
> entries that takes care of this, so implement it into barebox.
> 
> [1]: https://uapi-group.org/specifications/specs/boot_loader_specification/#sorting
> 
> Signed-off-by: Ahmad Fatoum <a.fatoum@barebox.org>
> ---
>  common/Kconfig            |  1 +
>  common/blspec.c           | 62 ++++++++++++++++++++++++++++++++++++++-
>  common/boot.c             |  7 +++++
>  include/asm-generic/bug.h |  7 +++++
>  include/boot.h            |  2 ++
>  5 files changed, 78 insertions(+), 1 deletion(-)
> 
> diff --git a/common/Kconfig b/common/Kconfig
> index 50c26695b2b5..cd002865f736 100644
> --- a/common/Kconfig
> +++ b/common/Kconfig
> @@ -715,6 +715,7 @@ config BLSPEC
>  	select BOOT
>  	select BOOTM
>  	select OFTREE
> +	select VERSION_CMP
>  	bool
>  	prompt "Support bootloader spec"
>  	help
> diff --git a/common/blspec.c b/common/blspec.c
> index 624e4c115272..f13e44f1de71 100644
> --- a/common/blspec.c
> +++ b/common/blspec.c
> @@ -28,6 +28,7 @@ struct blspec_entry {
>  	struct cdev *cdev;
>  	const char *rootpath;
>  	const char *configpath;
> +	char *sortkey;
>  };
>  
>  /*
> @@ -181,6 +182,7 @@ static void blspec_entry_free(struct bootentry *be)
>  	of_delete_node(entry->node);
>  	free_const(entry->configpath);
>  	free_const(entry->rootpath);
> +	free(entry->sortkey);
>  	free(entry);
>  }
>  
> @@ -268,6 +270,12 @@ static struct blspec_entry *blspec_entry_open(struct bootentries *bootentries,
>  			}
>  		}
>  
> +		/* This will be read often during comparison, so we cache it */
> +		if (!strcmp(name, "sort-key")) {
> +			entry->sortkey = xstrdup(val);
> +			continue;
> +		}
> +
>  		blspec_entry_var_set(entry, name, val);
>  	}
>  
> @@ -414,6 +422,58 @@ static const char *get_blspec_prefix_path(const char *configname)
>  	return get_mounted_path(configname);
>  }
>  
> +static int blspec_compare(struct list_head *list_a, struct list_head *list_b)
> +{
> +	struct bootentry *be_a = container_of(list_a, struct bootentry, list);
> +	struct bootentry *be_b = container_of(list_b, struct bootentry, list);
> +	struct blspec_entry *a, *b;
> +	const char *a_version, *b_version;
> +	int r;
> +
> +	/* The boot entry providers are called one by one and passed an empty
> +	 * list that's aggregated later, so we should only be encountering
> +	 * bootloader spec entries here.
> +	 */
> +	DEBUG_ASSERT(is_blspec_entry(be_a) && is_blspec_entry(be_b));
> +
> +	a = container_of(be_a, struct blspec_entry, entry);
> +	b = container_of(be_b, struct blspec_entry, entry);
> +
> +	a_version = a->configpath;
> +	b_version = b->configpath;
> +
> +	if (a->sortkey && b->sortkey) {
> +		const char *a_machine_id, *b_machine_id;
> +
> +		/* A-Z, increasing alphanumerical order */
> +		r = strcmp(a->sortkey, b->sortkey);
> +		if (r != 0)
> +			return r;
> +
> +		a_machine_id = blspec_entry_var_get(a, "machine-id");
> +		b_machine_id = blspec_entry_var_get(b, "machine-id");
> +
> +		/* A-Z, increasing alphanumerical order) */
> +		r = strcmp_ptr(a_machine_id, b_machine_id);
> +		if (r != 0)
> +			return r;
> +
> +		/* Will be compared in decreasing version order */
> +		a_version = blspec_entry_var_get(a, "version");
> +		b_version = blspec_entry_var_get(b, "version");
> +	} else if (a->sortkey != b->sortkey) {
> +		/* If sort-key is set on one entry, it sorts earlier. */
> +		return a->sortkey ? -1 : 1;
> +	}
> +
> +	/* At the end, if necessary, when sort-key is not set or
> +	 * those fields are not set or are all equal, the boot loader
> +	 * should sort using the file name of the entry (decreasing
> +	 * version sort), with the suffix removed.
> +	 */
> +	return -strverscmp(a_version, b_version);
> +}
> +
>  static int __blspec_scan_file(struct bootentries *bootentries, const char *root,
>  			      const char *configname)
>  {
> @@ -459,7 +519,7 @@ static int __blspec_scan_file(struct bootentries *bootentries, const char *root,
>  	entry->entry.me.type = MENU_ENTRY_NORMAL;
>  	entry->entry.release = blspec_entry_free;
>  
> -	bootentries_add_entry(bootentries, &entry->entry);
> +	bootentries_add_entry_sorted(bootentries, &entry->entry, blspec_compare);
>  	return 1;
>  }
>  
> diff --git a/common/boot.c b/common/boot.c
> index 8ccc269ac5bd..2e5294ffa2f0 100644
> --- a/common/boot.c
> +++ b/common/boot.c
> @@ -34,6 +34,13 @@ static inline void bootentries_merge(struct bootentries *dst, struct bootentries
>  	list_splice_tail_init(&src->entries, &dst->entries);
>  }
>  
> +void bootentries_add_entry_sorted(struct bootentries *entries, struct bootentry *entry,
> +				  int (*compare)(struct list_head *, struct list_head *))
> +
> +{
> +	list_add_sort(&entry->list, &entries->entries, compare);
> +}
> +
>  struct bootentries *bootentries_alloc(void)
>  {
>  	struct bootentries *bootentries;
> diff --git a/include/asm-generic/bug.h b/include/asm-generic/bug.h
> index 514801dab10e..1953c6e642c1 100644
> --- a/include/asm-generic/bug.h
> +++ b/include/asm-generic/bug.h
> @@ -78,4 +78,11 @@
>  		BUG_ON(!(expr));			\
>  } while (0)
>  
> +
> +#ifdef DEBUG
> +#define DEBUG_ASSERT(expr)	BUG_ON(!(expr))
> +#else
> +#define DEBUG_ASSERT(expr)	((void)(expr))
> +#endif

Is this change intentional here?

Sascha

> +
>  #endif
> diff --git a/include/boot.h b/include/boot.h
> index e6309b65a0c3..fdc108b7a21d 100644
> --- a/include/boot.h
> +++ b/include/boot.h
> @@ -24,6 +24,8 @@ struct bootentry {
>  };
>  
>  int bootentries_add_entry(struct bootentries *entries, struct bootentry *entry);
> +void bootentries_add_entry_sorted(struct bootentries *entries, struct bootentry *entry,
> +				  int (*compare)(struct list_head *, struct list_head *));
>  
>  struct bootentry_provider {
>  	const char *name;
> -- 
> 2.47.3
> 
> 
> 

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |



  reply	other threads:[~2026-02-23 11:06 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-02-09  9:08 [PATCH 0/5] " Ahmad Fatoum
2026-02-09  9:08 ` [PATCH 1/5] boot: aggregate bootentry provider entries one by one Ahmad Fatoum
2026-02-09  9:08 ` [PATCH 2/5] blspec: sort entries according to specification Ahmad Fatoum
2026-02-23 11:06   ` Sascha Hauer [this message]
2026-02-23 11:08     ` Ahmad Fatoum
2026-02-09  9:08 ` [PATCH 3/5] boot: give struct bootentry a path member Ahmad Fatoum
2026-02-09  9:08 ` [PATCH 4/5] commands: boot: support file path in boot -M for default entry Ahmad Fatoum
2026-02-09  9:08 ` [PATCH 5/5] test: self: add bootloader spec files test Ahmad Fatoum
2026-02-23 11:11 ` [PATCH 0/5] blspec: sort entries according to specification Sascha Hauer

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=aZw0qQVz1mX1l8nV@pengutronix.de \
    --to=s.hauer@pengutronix.de \
    --cc=a.fatoum@barebox.org \
    --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