bootstd: Update documentation
Add some documentation updates, particularly about global bootmeths.
Signed-off-by: Simon Glass <sjg@chromium.org>
diff --git a/doc/develop/bootstd.rst b/doc/develop/bootstd.rst
index dadd347..b8773f8 100644
--- a/doc/develop/bootstd.rst
+++ b/doc/develop/bootstd.rst
@@ -90,6 +90,12 @@
Note: it is possible to have a bootmeth that uses a partition or a whole device
directly, but it is more common to use a filesystem.
+Note that some bootmeths are 'global', meaning that they select the bootdev
+themselves. Examples include VBE and EFI boot manager. In this case, they
+provide a `read_bootflow()` method which checks whatever bootdevs it likes, then
+returns the bootflow, if found. Some of these bootmeths may be very slow, if
+they scan a lot of devices.
+
Boot process
------------
@@ -113,6 +119,9 @@
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.
+
Controlling ordering
--------------------
@@ -270,19 +279,9 @@
work. This includes global information about the state of standard boot. See
`struct bootstd_priv` for this structure, accessed with `bootstd_get_priv()`.
-Within the devicetree, if you add bootmeth devices or a system bootdev, they
-should be children of the bootstd device. See `arch/sandbox/dts/test.dts` for
-an example of this.
-
+Within the devicetree, if you add bootmeth devices, they should be children of
+the bootstd device. See `arch/sandbox/dts/test.dts` for an example of this.
-The system bootdev
-------------------
-
-Some bootmeths don't operate on individual bootdevs, but on the whole system.
-For example, the EFI boot manager does its own device scanning and does not
-make use of the bootdev devices. Such bootmeths can make use of the system
-bootdev, typically considered last, after everything else has been tried.
-
.. _`Automatic Devices`:
@@ -292,12 +291,11 @@
It is possible to define all the required devices in the devicetree manually,
but it is not necessary. The bootstd uclass includes a `dm_scan_other()`
function which creates the bootstd device if not found. If no bootmeth devices
-are found at all, it creates one for each available bootmeth driver as well as a
-system bootdev.
+are found at all, it creates one for each available bootmeth driver.
If your devicetree has any bootmeth device it must have all of them that you
-want to use, as well as the system bootdev if needed, since no bootmeth devices
-will be created automatically in that case.
+want to use, since no bootmeth devices will be created automatically in that
+case.
Using devicetree
@@ -348,6 +346,7 @@
- distro boot from a disk (syslinux)
- distro boot from a network (PXE)
- EFI boot using bootefi
+ - VBE
- EFI boot using boot manager
@@ -434,18 +433,23 @@
are going to be used, with `num_devs` set to the number of bootdevs and
`cur_dev` starting at 0.
-Next, the ordering of bootdevs is determined, by `bootmeth_setup_iter_order()`.
+Next, the ordering of bootmeths is determined, by `bootmeth_setup_iter_order()`.
By default the ordering is again by sequence number, i.e. the `/aliases` node,
or failing that the order in the devicetree. But the `bootmeth order` command
or `bootmeths` environment variable can be used to set up an ordering. If that
has been done, the ordering is in `struct bootstd_priv`, so that ordering is
simply copied into the iterator. Either way, the `method_order` array it set up,
-along with `num_methods`. Then `cur_method` is set to 0.
+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.
At this point the iterator is ready to use, with the first bootdev and bootmeth
-selected. All the other fields are 0. This means that the current partition is
-0, which is taken to mean the whole device, since partition numbers start at 1.
-It also means that `max_part` is 0, i.e. the maximum partition number we know
+selected. Most of the other fields are 0. This means that the current partition
+is 0, which is taken to mean the whole device, since partition numbers start at
+1. It also means that `max_part` is 0, i.e. the maximum partition number we know
about is 0, meaning that, as far as we know, there is no partition table on this
bootdev.
@@ -456,6 +460,10 @@
incomplete bootflows, but normally an error results in moving onto the next
iteration.
+Note that `bootflow_check()` handles global bootmeths explicitly, but calling
+`bootmeth_get_bootflow()` on each one. The `doing_global` flag indicates when
+the iterator is in that state.
+
The `bootflow_scan_next()` function handles moving onto the next iteration and
checking it. In fact it sits in a loop doing that repeatedly until it finds
something it wants to return.
@@ -474,9 +482,10 @@
0 0 2
0 1 0
0 1 1
- 0 1 1
+ 0 1 2
1 0 0
1 0 1
+ ...
======== ======= =======
The maximum value for `method` is `num_methods - 1` so when it exceeds that, it
@@ -488,6 +497,31 @@
works its way through all possibilities, moving forward one each time it is
called.
+Note that global bootmeths introduce a subtlety into the above description.
+When `doing_global` is true, the iteration takes place only among the bootmeths,
+i.e. the last column above. The global bootmeths are at the end of the list.
+Assuming that they are entries 3 and 4 in the list, the iteration then looks
+like this:
+
+ ======== ======= ======= =======================================
+ bootdev part method notes
+ ======== ======= ======= =======================================
+ . . 3 doing_global = true, method_count = 5
+ . . 4
+ 0 0 0 doing_global = false, method_count = 3
+ 0 0 1
+ 0 0 2
+ 0 1 0
+ 0 1 1
+ 0 1 2
+ 1 0 0
+ 1 0 1
+ ...
+ ======== ======= ======= =======================================
+
+The changeover of the value of `doing_global` from true to false is handled in
+`iter_incr()` as well.
+
There is no expectation that iteration will actually finish. Quite often a
valid bootflow is found early on. With `bootflow scan -b`, that causes the
bootflow to be immediately booted. Assuming it is successful, the iteration never
@@ -517,17 +551,19 @@
passes the iterator to the bootdev method, so that function knows what we are
talking about. At first, the bootflow is set up in the state `BOOTFLOWST_BASE`,
with just the `method` and `dev` intiialised. But the bootdev may fill in more,
-e.g. updating the state, depending on what it finds.
+e.g. updating the state, depending on what it finds. For global bootmeths the
+`bootmeth_get_bootflow()` function is called instead of
+`bootdev_get_bootflow()`.
-Based on what the bootdev responds with, `bootflow_check()` either
+Based on what the bootdev or bootmeth responds with, `bootflow_check()` either
returns a valid bootflow, or a partial one with an error. A partial bootflow
is one that has some fields set up, but did not reach the `BOOTFLOWST_READY`
state. As noted before, if the `BOOTFLOWF_ALL` iterator flag is set, then all
bootflows are returned, even partial ones. This can help with debugging.
So at this point you can see that total control over whether a bootflow can
-be generated from a particular iteration, or not, rests with the bootdev.
-Each one can adopt its own approach.
+be generated from a particular iteration, or not, rests with the bootdev (or
+global bootmeth). Each one can adopt its own approach.
Going down a level, what does the bootdev do in its `get_bootflow()` method?
Let us consider the MMC bootdev. In that case the call to
diff --git a/doc/usage/cmd/bootmeth.rst b/doc/usage/cmd/bootmeth.rst
index 9fc7ebf..29d8215 100644
--- a/doc/usage/cmd/bootmeth.rst
+++ b/doc/usage/cmd/bootmeth.rst
@@ -31,7 +31,9 @@
bootflow. You can use this command to adjust the order or even to omit some
boomeths.
-The argument is a quoted list of bootmeths to use, by name.
+The argument is a quoted list of bootmeths to use, by name. If global bootmeths
+are included, they must be at the end, otherwise the scanning mechanism will not
+work correctly.
bootmeth list
@@ -47,14 +49,15 @@
1 1 efi EFI boot from an .efi file
2 2 pxe PXE boot from a network device
3 3 sandbox Sandbox boot for testing
- 4 4 efi_mgr EFI bootmgr flow
+ glob 4 efi_mgr EFI bootmgr flow
===== === ================== =================================
The fields are as follows:
Order:
The order in which these bootmeths are invoked for each bootdev. If this
- shows as a hyphen, then the bootmeth is not in the current ordering.
+ shows as a hyphen, then the bootmeth is not in the current ordering. If it
+ shows as 'glob', then this is a global bootmeth and should be at the end.
Seq:
The sequence number of the bootmeth, i.e. the normal ordering if none is set