fit: prefer the default configuration on best-match ties

With CONFIG_FIT_BEST_MATCH, fit_conf_find_compat() selects the
configuration matching the most specific U-Boot compatible string; on
equal matches the first listed configuration wins and the configurations
node 'default' property is never consulted.

A FIT whose configurations all share the same base devicetree compatible
(e.g. one manifest carrying a base tree plus overlay combinations for a
single board) therefore always boots the first configuration, silently
ignoring the default chosen by the manifest author.

Break score ties in favour of the default configuration. A strictly
better compatible match still wins over it, and FITs without a default
keep the current first-listed behaviour.

Reviewed-by: Simon Glass <sjg@chromium.org>
Reviewed-by: Tom Rini <trini@konsulko.com>
Signed-off-by: Carlo Caione <ccaione@baylibre.com>
This commit is contained in:
Carlo Caione
2026-07-24 10:46:16 -06:00
committed by Tom Rini
parent 6380cb867e
commit 574b1adad7
5 changed files with 98 additions and 2 deletions
+68
View File
@@ -8,8 +8,76 @@
#include <image.h>
#include <test/ut.h>
#include <linux/libfdt.h>
#include "bootstd_common.h"
/* Test that the default configuration breaks best-match ties */
static int test_fit_conf_find_compat(struct unit_test_state *uts)
{
char fdt[256], fit[1024];
int confs, images, node;
int ret;
/* control devicetree with a two-entry compatible list */
ut_assertok(fdt_create_empty_tree(fdt, sizeof(fdt)));
ut_assertok(fdt_appendprop_string(fdt, 0, "compatible",
"test,board-a"));
ut_assertok(fdt_appendprop_string(fdt, 0, "compatible",
"test,fallback"));
/* FIT with two configurations matching the same compatible */
ut_assertok(fdt_create_empty_tree(fit, sizeof(fit)));
images = fdt_add_subnode(fit, 0, "images");
ut_assert(images >= 0);
confs = fdt_add_subnode(fit, 0, "configurations");
ut_assert(confs >= 0);
ut_assertok(fdt_setprop_string(fit, confs, FIT_DEFAULT_PROP, "conf-2"));
/*
* fdt_add_subnode() inserts before existing subnodes: create conf-2
* first so that conf-1 ends up listed first, like an .its compiled
* with the configurations in that order
*/
node = fdt_add_subnode(fit, confs, "conf-2");
ut_assert(node >= 0);
ut_assertok(fdt_setprop_string(fit, node, "compatible",
"test,board-a"));
node = fdt_add_subnode(fit, confs, "conf-1");
ut_assert(node >= 0);
ut_assertok(fdt_setprop_string(fit, node, "compatible",
"test,board-a"));
confs = fdt_path_offset(fit, "/configurations");
node = fdt_first_subnode(fit, confs);
ut_asserteq_str("conf-1", fdt_get_name(fit, node, NULL));
/* on a tie, the default configuration wins */
ret = fit_conf_find_compat(fit, fdt);
ut_assert(ret > 0);
ut_asserteq_str("conf-2", fdt_get_name(fit, ret, NULL));
/* without a default, the first listed configuration wins */
confs = fdt_path_offset(fit, "/configurations");
ut_assertok(fdt_delprop(fit, confs, FIT_DEFAULT_PROP));
confs = fdt_path_offset(fit, "/configurations");
ut_assertnull((void *)fdt_getprop(fit, confs, FIT_DEFAULT_PROP, NULL));
ret = fit_conf_find_compat(fit, fdt);
ut_assert(ret > 0);
ut_asserteq_str("conf-1", fdt_get_name(fit, ret, NULL));
/* a strictly better match still beats the default */
confs = fdt_path_offset(fit, "/configurations");
ut_assertok(fdt_setprop_string(fit, confs, FIT_DEFAULT_PROP, "conf-2"));
confs = fdt_path_offset(fit, "/configurations");
node = fdt_subnode_offset(fit, confs, "conf-2");
ut_assertok(fdt_setprop_string(fit, node, "compatible",
"test,fallback"));
ret = fit_conf_find_compat(fit, fdt);
ut_assert(ret > 0);
ut_asserteq_str("conf-1", fdt_get_name(fit, ret, NULL));
return 0;
}
BOOTSTD_TEST(test_fit_conf_find_compat, 0);
/* Test of image phase */
static int test_image_phase(struct unit_test_state *uts)
{