bootstd: Update documentation

Add some documentation updates, particularly about global bootmeths.

Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
Simon Glass 2022-07-30 15:52:35 -06:00 committed by Tom Rini
parent 0917f77393
commit 228fe57ad2
2 changed files with 68 additions and 29 deletions

View file

@ -90,6 +90,12 @@ bootflows.
Note: it is possible to have a bootmeth that uses a partition or a whole device 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. 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 Boot process
------------ ------------
@ -113,6 +119,9 @@ the following command::
which scans for available bootflows, optionally listing each find it finds (-l) which scans for available bootflows, optionally listing each find it finds (-l)
and trying to boot it (-b). and trying to boot it (-b).
When global bootmeths are available, these are typically checked before the
above bootdev scanning.
Controlling ordering Controlling ordering
-------------------- --------------------
@ -270,18 +279,8 @@ Standard boot requires a single instance of the bootstd device to make things
work. This includes global information about the state of standard boot. See work. This includes global information about the state of standard boot. See
`struct bootstd_priv` for this structure, accessed with `bootstd_get_priv()`. `struct bootstd_priv` for this structure, accessed with `bootstd_get_priv()`.
Within the devicetree, if you add bootmeth devices or a system bootdev, they Within the devicetree, if you add bootmeth devices, they should be children of
should be children of the bootstd device. See `arch/sandbox/dts/test.dts` for the bootstd device. See `arch/sandbox/dts/test.dts` for an example of this.
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`: .. _`Automatic Devices`:
@ -292,12 +291,11 @@ Automatic devices
It is possible to define all the required devices in the devicetree manually, 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()` 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 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 are found at all, it creates one for each available bootmeth driver.
system bootdev.
If your devicetree has any bootmeth device it must have all of them that you 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 want to use, since no bootmeth devices will be created automatically in that
will be created automatically in that case. case.
Using devicetree Using devicetree
@ -348,6 +346,7 @@ Bootmeth drivers are provided for:
- distro boot from a disk (syslinux) - distro boot from a disk (syslinux)
- distro boot from a network (PXE) - distro boot from a network (PXE)
- EFI boot using bootefi - EFI boot using bootefi
- VBE
- EFI boot using boot manager - EFI boot using boot manager
@ -434,18 +433,23 @@ case, the iterator ends up with a `dev_order` array containing the bootdevs that
are going to be used, with `num_devs` set to the number of bootdevs and are going to be used, with `num_devs` set to the number of bootdevs and
`cur_dev` starting at 0. `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, 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 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 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 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, 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 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 selected. Most of the other fields are 0. This means that the current partition
0, which is taken to mean the whole device, since partition numbers start at 1. is 0, which is taken to mean the whole device, since partition numbers start at
It also means that `max_part` is 0, i.e. the maximum partition number we know 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 about is 0, meaning that, as far as we know, there is no partition table on this
bootdev. bootdev.
@ -456,6 +460,10 @@ If the `BOOTFLOWF_ALL` iterator flag is set, even errors are returned as
incomplete bootflows, but normally an error results in moving onto the next incomplete bootflows, but normally an error results in moving onto the next
iteration. 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 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 checking it. In fact it sits in a loop doing that repeatedly until it finds
something it wants to return. something it wants to return.
@ -474,9 +482,10 @@ the least-sigificant digit on the right, counting like this:
0 0 2 0 0 2
0 1 0 0 1 0
0 1 1 0 1 1
0 1 1 0 1 2
1 0 0 1 0 0
1 0 1 1 0 1
...
======== ======= ======= ======== ======= =======
The maximum value for `method` is `num_methods - 1` so when it exceeds that, it The maximum value for `method` is `num_methods - 1` so when it exceeds that, it
@ -488,6 +497,31 @@ exceeds its maximum, then the next bootdev is used. In this way, iter_incr()
works its way through all possibilities, moving forward one each time it is works its way through all possibilities, moving forward one each time it is
called. 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 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 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 bootflow to be immediately booted. Assuming it is successful, the iteration never
@ -517,17 +551,19 @@ method `bootdev_get_bootflow()` to ask the bootdev to return a bootflow. It
passes the iterator to the bootdev method, so that function knows what we are 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`, 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, 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 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` 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 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. 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 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. be generated from a particular iteration, or not, rests with the bootdev (or
Each one can adopt its own approach. global bootmeth). Each one can adopt its own approach.
Going down a level, what does the bootdev do in its `get_bootflow()` method? 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 Let us consider the MMC bootdev. In that case the call to

View file

@ -31,7 +31,9 @@ scanning bootdevs, each bootmeth is tried in turn to see if it can find a valid
bootflow. You can use this command to adjust the order or even to omit some bootflow. You can use this command to adjust the order or even to omit some
boomeths. 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 bootmeth list
@ -47,14 +49,15 @@ Order Seq Name Description
1 1 efi EFI boot from an .efi file 1 1 efi EFI boot from an .efi file
2 2 pxe PXE boot from a network device 2 2 pxe PXE boot from a network device
3 3 sandbox Sandbox boot for testing 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: The fields are as follows:
Order: Order:
The order in which these bootmeths are invoked for each bootdev. If this 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: Seq:
The sequence number of the bootmeth, i.e. the normal ordering if none is set The sequence number of the bootmeth, i.e. the normal ordering if none is set