boot: Run global bootmeths after all bootdevs are exhausted

When there are no more bootdevs we should still go through the global
bootmeths, since some may not have yet been used, if their priority has
not yet come up.

Add a final check for this at the end of the iterator.

Update the documentation to match the new behaviour of global bootmeths.

Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
Simon Glass
2025-10-15 16:44:13 +01:00
committed by Tom Rini
parent eff1dca963
commit 060ce66b83
2 changed files with 57 additions and 6 deletions

View File

@@ -354,6 +354,18 @@ static int iter_incr(struct bootflow_iter *iter)
return 0;
}
/* if this was the final global bootmeth check, we are done */
if (iter->cur_prio == BOOTDEVP_COUNT) {
log_debug("-> done global bootmeths\n");
/* print the same message as bootflow_iter_set_dev() */
if ((iter->flags & (BOOTFLOWIF_SHOW |
BOOTFLOWIF_SINGLE_DEV)) ==
BOOTFLOWIF_SHOW)
printf("No more bootdevs\n");
return BF_NO_MORE_DEVICES;
}
/*
* Don't move to the next dev as we haven't tried this
* one yet!
@@ -459,6 +471,17 @@ static int iter_incr(struct bootflow_iter *iter)
ret = prepare_bootdev(iter, dev, method_flags, true);
}
if (IS_ENABLED(CONFIG_BOOTMETH_GLOBAL) && ret) {
log_debug("no more bootdevs, trying global\n");
/* allow global bootmeths with any priority */
iter->cur_prio = BOOTDEVP_COUNT;
if (!next_glob_bootmeth(iter)) {
log_debug("-> next method '%s'\n", iter->method->name);
return 0;
}
}
/* if there are no more bootdevs, give up */
if (ret)
return log_msg_ret("incr", BF_NO_MORE_DEVICES);

View File

@@ -133,7 +133,8 @@ which scans for available bootflows, optionally listing each find it finds (-l)
and trying to boot it (-b).
When global bootmeths are available, these are typically checked before the
above bootdev scanning.
above bootdev scanning, but it is possible provide a priority to make them
run later, by setting the glob_prio field in the driver's bind() method.
Controlling ordering
@@ -612,9 +613,9 @@ simply copied into the iterator. Either way, the `method_order` array it set up,
along with `num_methods`.
Note that global bootmeths are always put at the end of the ordering. If any are
present, `cur_method` is set to the first one, so that global bootmeths are done
first. Once all have been used, these bootmeths are dropped from the iteration.
When there are no global bootmeths, `cur_method` is set to 0.
present, `cur_method` is set to the first one, so that global bootmeths are
processed first, so long as their priority allows it. Bootstd keeps track of
which global bootmeths have been used, to make sure they are only used once.
At this point the iterator is ready to use, with the first bootmeth selected.
Most of the other fields are 0. This means that the current partition
@@ -714,8 +715,35 @@ to the next partition, or bootdev, for example. The special values
`BF_NO_MORE_PARTS` and `BF_NO_MORE_DEVICES` handle this. When `iter_incr` sees
`BF_NO_MORE_PARTS` it knows that it should immediately move to the next bootdev.
When it sees `BF_NO_MORE_DEVICES` it knows that there is nothing more it can do
so it should immediately return. The caller of `iter_incr()` is responsible for
updating the `err` field, based on the return value it sees.
so it should immediately run any unused global bootmeths and then return. The
caller of `iter_incr()` is responsible for updating the `err` field, based on
the return value it sees.
Global bootmeths can have a non-zero priority, which indicates where in the
iteration sequence they should run. Each time a new bootdev is produced by a
hunter, all of the global bootmeths are first checked to see if they should run
before this new bootdev. For example, if the bootdev was produced by a hunter
with priority BOOTDEVP_6_NET_BASE, then a quick check is made for global
bootmeths with that priority or less. If there are any, they run before the new
bootdev is processed.
Assuming they are enabled and the iteration sequence runs right to the end, all
global bootmeths will be used. This is handled by a special case at the end of
iter_incr(), where it processes amy so-far-unused global bootmeths.
It is important to note the special nature of global bootmeths, with respect to
priority. If there are two normal bootmeths and a global one, the normal ones
are run for each bootdev, but the global one is independent of bootdevs. The
order might be:
bootdev priority 3: normal-1, normal-3
global-2, prio 4
bootdev priority 5: normal-1, normal-3
Of course if a specific bootmeth ordering is provided, then this overrides the
default ordering. Global bootmeths must be listed at the end, reflecting their
hybrid nature (they are bootmeths but operate on the system as a whole, not on
a particular bootdev).
The above describes the iteration process at a high level. It is basically a
very simple increment function with a checker called `bootflow_check()` that