bootstd: doc: Add documentation
Add documentation for this feature, including the commands and full devicetree bindings. Signed-off-by: Simon Glass <sjg@chromium.org>
This commit is contained in:
parent
a91492b6e9
commit
e7b2ce191e
@ -702,6 +702,10 @@ F: boot/bootmeth*.c
|
||||
F: boot/bootstd.c
|
||||
F: cmd/bootdev.c
|
||||
F: cmd/bootflow.c
|
||||
F: doc/develop/bootstd.rst
|
||||
F: doc/usage/bootdev.rst
|
||||
F: doc/usage/bootflow.rst
|
||||
F: doc/usage/bootmeth.rst
|
||||
F: drivers/mmc/mmc_bootdev.c
|
||||
F: include/bootdev.h
|
||||
F: include/bootflow.h
|
||||
|
638
doc/develop/bootstd.rst
Normal file
638
doc/develop/bootstd.rst
Normal file
@ -0,0 +1,638 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0+:
|
||||
|
||||
U-Boot Standard Boot
|
||||
====================
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
Standard boot provides a built-in way for U-Boot to automatically boot
|
||||
an Operating System without custom scripting and other customisation. It
|
||||
introduces the following concepts:
|
||||
|
||||
- bootdev - a device which can hold or access a distro (e.g. MMC, Ethernet)
|
||||
- bootmeth - a method to scan a bootdev to find bootflows (e.g. distro boot)
|
||||
- bootflow - a description of how to boot (provided by the distro)
|
||||
|
||||
For Linux, the distro (Linux distribution, e.g. Debian, Fedora) is responsible
|
||||
for creating a bootflow for each kernel combination that it wants to offer.
|
||||
These bootflows are stored on media so they can be discovered by U-Boot. This
|
||||
feature is typically called `distro boot` (see :doc:`distro`) because it is
|
||||
a way for distributions to boot on any hardware.
|
||||
|
||||
Traditionally U-Boot has relied on scripts to implement this feature. See
|
||||
disto_boodcmd_ for details. This is done because U-Boot has no native support
|
||||
for scanning devices. While the scripts work remarkably well, they can be hard
|
||||
to understand and extend, and the feature does not include tests. They are also
|
||||
making it difficult to move away from ad-hoc CONFIGs, since they are implemented
|
||||
using the environment and a lot of #defines.
|
||||
|
||||
Standard boot is a generalisation of distro boot. It provides a more built-in
|
||||
way to boot with U-Boot. The feature is extensible to different Operating
|
||||
Systems (such as Chromium OS) and devices (beyond just block and network
|
||||
devices). It supports EFI boot and EFI bootmgr too.
|
||||
|
||||
|
||||
Bootflow
|
||||
--------
|
||||
|
||||
A bootflow is a file that describes how to boot a distro. Conceptually there can
|
||||
be different formats for that file but at present U-Boot only supports the
|
||||
BootLoaderSpec_ format. which looks something like this::
|
||||
|
||||
menu autoboot Welcome to Fedora-Workstation-armhfp-31-1.9. Automatic boot in # second{,s}. Press a key for options.
|
||||
menu title Fedora-Workstation-armhfp-31-1.9 Boot Options.
|
||||
menu hidden
|
||||
|
||||
label Fedora-Workstation-armhfp-31-1.9 (5.3.7-301.fc31.armv7hl)
|
||||
kernel /vmlinuz-5.3.7-301.fc31.armv7hl
|
||||
append ro root=UUID=9732b35b-4cd5-458b-9b91-80f7047e0b8a rhgb quiet LANG=en_US.UTF-8 cma=192MB cma=256MB
|
||||
fdtdir /dtb-5.3.7-301.fc31.armv7hl/
|
||||
initrd /initramfs-5.3.7-301.fc31.armv7hl.img
|
||||
|
||||
As you can see it specifies a kernel, a ramdisk (initrd) and a directory from
|
||||
which to load devicetree files. The details are described in disto_boodcmd_.
|
||||
|
||||
The bootflow is provided by the distro. It is not part of U-Boot. U-Boot's job
|
||||
is simply to interpret the file and carry out the instructions. This allows
|
||||
distros to boot on essentially any device supported by U-Boot.
|
||||
|
||||
Typically the first available bootflow is selected and booted. If that fails,
|
||||
then the next one is tried.
|
||||
|
||||
|
||||
Bootdev
|
||||
-------
|
||||
|
||||
Where does U-Boot find the media that holds the operating systems? That is the
|
||||
job of bootdev. A bootdev is simply a layer on top of a media device (such as
|
||||
MMC, NVMe). The bootdev accesses the device, including partitions and
|
||||
filesystems that might contain things related to an operating system.
|
||||
|
||||
For example, an MMC bootdev provides access to the individual partitions on the
|
||||
MMC device. It scans through these to find filesystems, then provides a list of
|
||||
these for consideration.
|
||||
|
||||
|
||||
Bootmeth
|
||||
--------
|
||||
|
||||
Once the list of filesystems is provided, how does U-Boot find the bootflow
|
||||
files in these filesystems. That is the job of bootmeth. Each boot method has
|
||||
its own way of doing this.
|
||||
|
||||
For example, the distro bootmeth simply looks through the provided filesystem
|
||||
for a file called `extlinux/extlinux.conf`. This files constitutes a bootflow.
|
||||
If the distro bootmeth is used on multiple partitions it may produce multiple
|
||||
bootflows.
|
||||
|
||||
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.
|
||||
|
||||
|
||||
Boot process
|
||||
------------
|
||||
|
||||
U-Boot tries to use the 'lazy init' approach whereever possible and distro boot
|
||||
is no exception. The algorithm is::
|
||||
|
||||
while (get next bootdev)
|
||||
while (get next bootmeth)
|
||||
while (get next bootflow)
|
||||
try to boot it
|
||||
|
||||
So U-Boot works its way through the bootdevs, trying each bootmeth in turn to
|
||||
obtain bootflows, until it either boots or exhausts the available options.
|
||||
|
||||
Instead of 500 lines of #defines and a 4KB boot script, all that is needed is
|
||||
the following command::
|
||||
|
||||
bootflow scan -lb
|
||||
|
||||
which scans for available bootflows, optionally listing each find it finds (-l)
|
||||
and trying to boot it (-b).
|
||||
|
||||
|
||||
Controlling ordering
|
||||
--------------------
|
||||
|
||||
Several options are available to control the ordering of boot scanning:
|
||||
|
||||
|
||||
boot_targets
|
||||
~~~~~~~~~~~~
|
||||
|
||||
This environment variable can be used to control the list of bootdevs searched
|
||||
and their ordering, for example::
|
||||
|
||||
setenv boot_targets "mmc0 mmc1 usb pxe"
|
||||
|
||||
Entries may be removed or re-ordered in this list to affect the boot order. If
|
||||
the variable is empty, the default ordering is used, based on the priority of
|
||||
bootdevs and their sequence numbers.
|
||||
|
||||
|
||||
bootmeths
|
||||
~~~~~~~~~
|
||||
|
||||
This environment variable can be used to control the list of bootmeths used and
|
||||
their ordering for example::
|
||||
|
||||
setenv bootmeths "syslinux efi"
|
||||
|
||||
Entries may be removed or re-ordered in this list to affect the order the
|
||||
bootmeths are tried on each bootdev. If the variable is empty, the default
|
||||
ordering is used, based on the bootmeth sequence numbers, which can be
|
||||
controlled by aliases.
|
||||
|
||||
The :ref:`usage/cmd/bootmeth:bootmeth command` (`bootmeth order`) operates in
|
||||
the same way as setting this variable.
|
||||
|
||||
|
||||
Bootdev uclass
|
||||
--------------
|
||||
|
||||
The bootdev uclass provides an simple API call to obtain a bootflows from a
|
||||
device::
|
||||
|
||||
int bootdev_get_bootflow(struct udevice *dev, struct bootflow_iter *iter,
|
||||
struct bootflow *bflow);
|
||||
|
||||
This takes a iterator which indicates the bootdev, partition and bootmeth to
|
||||
use. It returns a bootflow. This is the core of the bootdev implementation. The
|
||||
bootdev drivers that implement this differ depending on the media they are
|
||||
reading from, but each is responsible for returning a valid bootflow if
|
||||
available.
|
||||
|
||||
A helper called `bootdev_find_in_blk()` makes it fairly easy to implement this
|
||||
function for each media device uclass, in a few lines of code.
|
||||
|
||||
|
||||
Bootdev drivers
|
||||
---------------
|
||||
|
||||
A bootdev driver is typically fairly simple. Here is one for mmc::
|
||||
|
||||
static int mmc_get_bootflow(struct udevice *dev, struct bootflow_iter *iter,
|
||||
struct bootflow *bflow)
|
||||
{
|
||||
struct udevice *mmc_dev = dev_get_parent(dev);
|
||||
struct udevice *blk;
|
||||
int ret;
|
||||
|
||||
ret = mmc_get_blk(mmc_dev, &blk);
|
||||
/*
|
||||
* If there is no media, indicate that no more partitions should be
|
||||
* checked
|
||||
*/
|
||||
if (ret == -EOPNOTSUPP)
|
||||
ret = -ESHUTDOWN;
|
||||
if (ret)
|
||||
return log_msg_ret("blk", ret);
|
||||
assert(blk);
|
||||
ret = bootdev_find_in_blk(dev, blk, iter, bflow);
|
||||
if (ret)
|
||||
return log_msg_ret("find", ret);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mmc_bootdev_bind(struct udevice *dev)
|
||||
{
|
||||
struct bootdev_uc_plat *ucp = dev_get_uclass_plat(dev);
|
||||
|
||||
ucp->prio = BOOTDEVP_0_INTERNAL_FAST;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct bootdev_ops mmc_bootdev_ops = {
|
||||
.get_bootflow = mmc_get_bootflow,
|
||||
};
|
||||
|
||||
static const struct udevice_id mmc_bootdev_ids[] = {
|
||||
{ .compatible = "u-boot,bootdev-mmc" },
|
||||
{ }
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(mmc_bootdev) = {
|
||||
.name = "mmc_bootdev",
|
||||
.id = UCLASS_BOOTDEV,
|
||||
.ops = &mmc_bootdev_ops,
|
||||
.bind = mmc_bootdev_bind,
|
||||
.of_match = mmc_bootdev_ids,
|
||||
};
|
||||
|
||||
The implementation of the `get_bootflow()` method is simply to obtain the
|
||||
block device and call a bootdev helper function to do the rest. The
|
||||
implementation of `bootdev_find_in_blk()` checks the partition table, and
|
||||
attempts to read a file from a filesystem on the partition number given by the
|
||||
`@iter->part` parameter.
|
||||
|
||||
Each bootdev has a priority, which indicates the order in which it is used.
|
||||
Faster bootdevs are used first, since they are more likely to be able to boot
|
||||
the device quickly.
|
||||
|
||||
|
||||
Device hierarchy
|
||||
----------------
|
||||
|
||||
A bootdev device is a child of the media device. In this example, you can see
|
||||
that the bootdev is a sibling of the block device and both are children of
|
||||
media device::
|
||||
|
||||
mmc 0 [ + ] bcm2835-sdhost | |-- mmc@7e202000
|
||||
blk 0 [ + ] mmc_blk | | |-- mmc@7e202000.blk
|
||||
bootdev 0 [ ] mmc_bootdev | | `-- mmc@7e202000.bootdev
|
||||
mmc 1 [ + ] sdhci-bcm2835 | |-- sdhci@7e300000
|
||||
blk 1 [ ] mmc_blk | | |-- sdhci@7e300000.blk
|
||||
bootdev 1 [ ] mmc_bootdev | | `-- sdhci@7e300000.bootdev
|
||||
|
||||
The bootdev device is typically created automatically in the media uclass'
|
||||
`post_bind()` method by calling `bootdev_setup_for_dev()`. The code typically
|
||||
something like this::
|
||||
|
||||
ret = bootdev_setup_for_dev(dev, "eth_bootdev");
|
||||
if (ret)
|
||||
return log_msg_ret("bootdev", ret);
|
||||
|
||||
Here, `eth_bootdev` is the name of the Ethernet bootdev driver and `dev`
|
||||
is the ethernet device. This function is safe to call even if standard boot is
|
||||
not enabled, since it does nothing in that case. It can be added to all uclasses
|
||||
which implement suitable media.
|
||||
|
||||
|
||||
The bootstd device
|
||||
------------------
|
||||
|
||||
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
|
||||
`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.
|
||||
|
||||
|
||||
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
|
||||
-----------------
|
||||
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
|
||||
Using devicetree
|
||||
----------------
|
||||
|
||||
If a bootdev is complicated or needs configuration information, it can be
|
||||
added to the devicetree as a child of the media device. For example, imagine a
|
||||
bootdev which reads a bootflow from SPI flash. The devicetree fragment might
|
||||
look like this::
|
||||
|
||||
spi@0 {
|
||||
flash@0 {
|
||||
reg = <0>;
|
||||
compatible = "spansion,m25p16", "jedec,spi-nor";
|
||||
spi-max-frequency = <40000000>;
|
||||
|
||||
bootdev {
|
||||
compatible = "u-boot,sf-bootdev";
|
||||
offset = <0x2000>;
|
||||
size = <0x1000>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
The `sf-bootdev` driver can implement a way to read from the SPI flash, using
|
||||
the offset and size provided, and return that bootflow file back to the caller.
|
||||
When distro boot wants to read the kernel it calls disto_getfile() which must
|
||||
provide a way to read from the SPI flash. See `distro_boot()` at distro_boot_
|
||||
for more details.
|
||||
|
||||
Of course this is all internal to U-Boot. All the distro sees is another way
|
||||
to boot.
|
||||
|
||||
|
||||
Configuration
|
||||
-------------
|
||||
|
||||
Standard boot is enabled with `CONFIG_BOOTSTD`. Each bootmeth has its own CONFIG
|
||||
option also. For example, `CONFIG_BOOTMETH_DISTRO` enables support for distro
|
||||
boot from a disk.
|
||||
|
||||
|
||||
Available bootmeth drivers
|
||||
--------------------------
|
||||
|
||||
Bootmeth drivers are provided for:
|
||||
|
||||
- distro boot from a disk (syslinux)
|
||||
- distro boot from a network (PXE)
|
||||
- EFI boot using bootefi
|
||||
- EFI boot using boot manager
|
||||
|
||||
|
||||
Command interface
|
||||
-----------------
|
||||
|
||||
Three commands are available:
|
||||
|
||||
`bootdev`
|
||||
Allows listing of available bootdevs, selecting a particular one and
|
||||
getting information about it. See :doc:`../usage/cmd/bootdev`
|
||||
|
||||
`bootflow`
|
||||
Allows scanning one or more bootdevs for bootflows, listing available
|
||||
bootflows, selecting one, obtaining information about it and booting it.
|
||||
See :doc:`../usage/cmd/bootflow`
|
||||
|
||||
`bootmeth`
|
||||
Allow listing of available bootmethds and setting the order in which they
|
||||
are tried. See :doc:`../usage/cmd/bootmeth`
|
||||
|
||||
.. _BootflowStates:
|
||||
|
||||
Bootflow states
|
||||
---------------
|
||||
|
||||
Here is a list of states that a bootflow can be in:
|
||||
|
||||
======= =======================================================================
|
||||
State Meaning
|
||||
======= =======================================================================
|
||||
base Starting-out state, indicates that no media/partition was found. For an
|
||||
SD card socket it may indicate that the card is not inserted.
|
||||
media Media was found (e.g. SD card is inserted) but no partition information
|
||||
was found. It might lack a partition table or have a read error.
|
||||
part Partition was found but a filesystem could not be read. This could be
|
||||
because the partition does not hold a filesystem or the filesystem is
|
||||
very corrupted.
|
||||
fs Filesystem was found but the file could not be read. It could be
|
||||
missing or in the wrong subdirectory.
|
||||
file File was found and its size detected, but it could not be read. This
|
||||
could indicate filesystem corruption.
|
||||
ready File was loaded and is ready for use. In this state the bootflow is
|
||||
ready to be booted.
|
||||
======= =======================================================================
|
||||
|
||||
|
||||
Theory of operation
|
||||
-------------------
|
||||
|
||||
This describes how standard boot progresses through to booting an operating
|
||||
system.
|
||||
|
||||
To start. all the necessary devices must be bound, including bootstd, which
|
||||
provides the top-level `struct bootstd_priv` containing optional configuration
|
||||
information. The bootstd device is also holds the various lists used while
|
||||
scanning. This step is normally handled automatically by driver model, as
|
||||
described in `Automatic Devices`_.
|
||||
|
||||
Bootdevs are also required, to provide access to the media to use. These are not
|
||||
useful by themselves: bootmeths are needed to provide the means of scanning
|
||||
those bootdevs. So, all up, we need a single bootstd device, one or more bootdev
|
||||
devices and one or more bootmeth devices.
|
||||
|
||||
Once these are ready, typically a `bootflow scan` command is issued. This kicks
|
||||
of the iteration process, which involves looking through the bootdevs and their
|
||||
partitions one by one to find bootflows.
|
||||
|
||||
Iteration is kicked off using `bootflow_scan_first()`, which calls
|
||||
`bootflow_scan_bootdev()`.
|
||||
|
||||
The iterator is set up with `bootflow_iter_init()`. This simply creates an
|
||||
empty one with the given flags. Flags are used to control whether each
|
||||
iteration is displayed, whether to return iterations even if they did not result
|
||||
in a valid bootflow, whether to iterate through just a single bootdev, etc.
|
||||
|
||||
Then the ordering of bootdevs is determined, by `bootdev_setup_iter_order()`. By
|
||||
default, the bootdevs are used in the order specified by the `boot_targets`
|
||||
environment variable (e.g. "mmc2 mmc0 usb"). If that is missing then their
|
||||
sequence order is used, as determined by the `/aliases` node, or failing that
|
||||
their order in the devicetree. For BOOTSTD_FULL, if there is a `bootdev-order`
|
||||
property in the bootstd node, then this is used as a final fallback. In any
|
||||
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
|
||||
`cur_dev` starting at 0.
|
||||
|
||||
Next, the ordering of bootdevs 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.
|
||||
|
||||
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
|
||||
about is 0, meaning that, as far as we know, there is no partition table on this
|
||||
bootdev.
|
||||
|
||||
With the iterator ready, `bootflow_scan_bootdev()` checks whether the current
|
||||
settings produce a valid bootflow. This is handled by `bootflow_check()`, which
|
||||
either returns 0 (if it got something) or an error if not (more on that later).
|
||||
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
|
||||
iteration.
|
||||
|
||||
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.
|
||||
|
||||
The actual 'moving on' part is implemented in `iter_incr()`. This is a very
|
||||
simple function. It increments the first counter. If that hits its maximum, it
|
||||
sets it to zero and increments the second counter. You can think of all the
|
||||
counters together as a number with three digits which increment in order, with
|
||||
the least-sigificant digit on the right, counting like this:
|
||||
|
||||
======== ======= =======
|
||||
bootdev part method
|
||||
======== ======= =======
|
||||
0 0 0
|
||||
0 0 1
|
||||
0 0 2
|
||||
0 1 0
|
||||
0 1 1
|
||||
0 1 1
|
||||
1 0 0
|
||||
1 0 1
|
||||
======== ======= =======
|
||||
|
||||
The maximum value for `method` is `num_methods - 1` so when it exceeds that, it
|
||||
goes back to 0 and the next `part` is considered. The maximum value for that is
|
||||
`max_part`, which is initially zero for all bootdevs. If we find a partition
|
||||
table on that bootdev, `max_part` can be updated during the iteration to a
|
||||
higher value - see `bootdev_find_in_blk()` for that, described later. If that
|
||||
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
|
||||
called.
|
||||
|
||||
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
|
||||
completes.
|
||||
|
||||
Also note that the iterator hold the **current** combination being considered.
|
||||
So when `iter_incr()` is called, it increments to the next one and returns it,
|
||||
the new **current** combination.
|
||||
|
||||
Note also the `err` field in `struct bootflow_iter`. This is normally 0 and has
|
||||
thus has no effect on `iter_inc()`. But if it is non-zero, signalling an error,
|
||||
it indicates to the iterator what it should do when called. It can force moving
|
||||
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.
|
||||
|
||||
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
|
||||
checks the result of each iteration generated, to determine whether it can
|
||||
produce a bootflow.
|
||||
|
||||
So what happens inside of `bootflow_check()`? It simply calls the uclass
|
||||
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
|
||||
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.
|
||||
|
||||
Based on what the bootdev 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.
|
||||
|
||||
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
|
||||
`bootdev_get_bootflow()` ends up in `mmc_get_bootflow()`. It locates the parent
|
||||
device of the bootdev, i.e. the `UCLASS_MMC` device itself, then finds the block
|
||||
device associated with it. It then calls the helper function
|
||||
`bootdev_find_in_blk()` to do all the work. This is common with just about any
|
||||
bootdev that is based on a media device.
|
||||
|
||||
The `bootdev_find_in_blk()` helper is implemented in the bootdev uclass. It
|
||||
names the bootflow and copies the partition number in from the iterator. Then it
|
||||
calls the bootmeth device to check if it can support this device. This is
|
||||
important since some bootmeths only work with network devices, for example. If
|
||||
that check fails, it stops.
|
||||
|
||||
Assuming the bootmeth is happy, or at least indicates that it is willing to try
|
||||
(by returning 0 from its `check()` method), the next step is to try the
|
||||
partition. If that works it tries to detect a file system. If that works then it
|
||||
calls the bootmeth device once more, this time to read the bootflow.
|
||||
|
||||
Note: At present a filesystem is needed for the bootmeth to be called on block
|
||||
devices, simply because we don't have any examples where this is not the case.
|
||||
This feature can be added as needed.
|
||||
|
||||
If we take the example of the `bootmeth_distro` driver, this call ends up at
|
||||
`distro_read_bootflow()`. It has the filesystem ready, so tries various
|
||||
filenames to try to find the `extlinux.conf` file, reading it if possible. If
|
||||
all goes well the bootflow ends up in the `BOOTFLOWST_READY` state.
|
||||
|
||||
At this point, we fall back from the bootmeth driver, to
|
||||
`bootdev_find_in_blk()`, then back to `mmc_get_bootflow()`, then to
|
||||
`bootdev_get_bootflow()`, then to `bootflow_check()` and finally to its caller,
|
||||
either `bootflow_scan_bootdev()` or `bootflow_scan_next()`. In either case,
|
||||
the bootflow is returned as the result of this iteration, assuming it made it to
|
||||
the `BOOTFLOWST_READY` state.
|
||||
|
||||
That is the basic operation of scanning for bootflows. The process of booting a
|
||||
bootflow is handled by the bootmeth driver for that bootflow. In the case of
|
||||
distro boot, this parses and processes the `extlinux.conf` file that was read.
|
||||
See `distro_boot()` for how that works. The processing may involve reading
|
||||
additional files, which is handled by the `read_file()` method, which is
|
||||
`distro_read_file()` in this case. All bootmethds should support reading files,
|
||||
since the bootflow is typically only the basic instructions and does not include
|
||||
the operating system itself, ramdisk, device tree, etc.
|
||||
|
||||
The vast majority of the bootstd code is concerned with iterating through
|
||||
partitions on bootdevs and using bootmethds to find bootflows.
|
||||
|
||||
How about bootdevs which are not block devices? They are handled by the same
|
||||
methods as above, but with a different implementation. For example, the bootmeth
|
||||
for PXE boot (over a network) uses `tftp` to read files rather than `fs_read()`.
|
||||
But other than that it is very similar.
|
||||
|
||||
|
||||
Tests
|
||||
-----
|
||||
|
||||
Tests are located in `test/boot` and cover the core functionality as well as
|
||||
the commands. All tests use sandbox so can be run on a standard Linux computer
|
||||
and in U-Boot's CI.
|
||||
|
||||
For testing, a DOS-formatted disk image is used with a single FAT partition on
|
||||
it. This is created in `setup_bootflow_image()`, with a canned one from the
|
||||
source tree used if it cannot be created (e.g. in CI).
|
||||
|
||||
|
||||
Bootflow internals
|
||||
------------------
|
||||
|
||||
The bootstd device holds a linked list of scanned bootflows as well as the
|
||||
currently selected bootdev and bootflow (for use by commands). This is in
|
||||
`struct bootstd_priv`.
|
||||
|
||||
Each bootdev device has its own `struct bootdev_uc_plat` which holds a
|
||||
list of scanned bootflows just for that device.
|
||||
|
||||
The bootflow itself is documented in bootflow_h_. It includes various bits of
|
||||
information about the bootflow and a buffer to hold the file.
|
||||
|
||||
|
||||
Future
|
||||
------
|
||||
|
||||
Apart from the to-do items below, different types of bootflow files may be
|
||||
implemented in future, e.g. Chromium OS support which is currently only
|
||||
available as a script in chromebook_coral.
|
||||
|
||||
|
||||
To do
|
||||
-----
|
||||
|
||||
Some things that need to be done to completely replace the distro-boot scripts:
|
||||
|
||||
- add bootdev drivers for dhcp, sata, scsi, ide, virtio
|
||||
- PXE boot for EFI
|
||||
- support for loading U-Boot scripts
|
||||
|
||||
Other ideas:
|
||||
|
||||
- `bootflow prep` to load everything preparing for boot, so that `bootflow boot`
|
||||
can just do the boot.
|
||||
- automatically load kernel, FDT, etc. to suitable addresses so the board does
|
||||
not need to specify things like `pxefile_addr_r`
|
||||
|
||||
|
||||
.. _disto_boodcmd: https://github.com/u-boot/u-boot/blob/master/include/config_distro_bootcmd.h
|
||||
.. _BootLoaderSpec: http://www.freedesktop.org/wiki/Specifications/BootLoaderSpec/
|
||||
.. _distro_boot: https://github.com/u-boot/u-boot/blob/master/boot/distro.c
|
||||
.. _bootflow_h: https://github.com/u-boot/u-boot/blob/master/include/bootflow.h
|
@ -157,6 +157,9 @@ a line with "CONFIG_DISTRO_DEFAULTS=y". If you want to enable this
|
||||
from Kconfig itself, for e.g. all boards using a specific SoC then
|
||||
add a "imply DISTRO_DEFAULTS" to your SoC CONFIG option.
|
||||
|
||||
|
||||
TO BE UPDATED:
|
||||
|
||||
In your board configuration file, include the following::
|
||||
|
||||
#ifndef CONFIG_SPL_BUILD
|
||||
|
@ -10,6 +10,7 @@ Implementation
|
||||
:maxdepth: 1
|
||||
|
||||
bloblist
|
||||
bootstd
|
||||
ci_testing
|
||||
commands
|
||||
config_binding
|
||||
|
@ -6,3 +6,21 @@ child of the media device (UCLASS_MMC, UCLASS_SPI_FLASH, etc.)
|
||||
|
||||
The bootdev driver is provided by the media devices. The bindings for each
|
||||
are described in this file (to come).
|
||||
|
||||
Required properties:
|
||||
|
||||
compatible:
|
||||
"u-boot,bootdev-eth" - Ethernet bootdev
|
||||
"u-boot,bootdev-mmc" - MMC bootdev
|
||||
"u-boot,bootdev-usb" - USB bootdev
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
mmc1 {
|
||||
compatible = "sandbox,mmc";
|
||||
|
||||
mmc-bootdev {
|
||||
compatible = "u-boot,bootdev-eth";
|
||||
};
|
||||
};
|
||||
|
31
doc/device-tree-bindings/bootmeth.txt
Normal file
31
doc/device-tree-bindings/bootmeth.txt
Normal file
@ -0,0 +1,31 @@
|
||||
U-Boot standard boot methods (bootmeth)
|
||||
======================================
|
||||
|
||||
This provides methods (called bootmeths) for locating bootflows on a boot
|
||||
device (bootdev). These are normally created as children of the bootstd device.
|
||||
|
||||
Required properties:
|
||||
|
||||
compatible:
|
||||
"u-boot,distro-syslinux" - distro boot from a block device
|
||||
"u-boot,distro-pxe" - distro boot from a network device
|
||||
"u-boot,distro-efi" - EFI boot from an .efi file
|
||||
"u-boot,efi-bootmgr" - EFI boot using boot manager (bootmgr)
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
bootstd {
|
||||
compatible = "u-boot,boot-std";
|
||||
|
||||
filename-prefixes = "/", "/boot/";
|
||||
bootdev-order = "mmc2", "mmc1";
|
||||
|
||||
syslinux {
|
||||
compatible = "u-boot,distro-syslinux";
|
||||
};
|
||||
|
||||
efi {
|
||||
compatible = "u-boot,distro-efi";
|
||||
};
|
||||
};
|
@ -25,4 +25,12 @@ Example:
|
||||
|
||||
filename-prefixes = "/", "/boot/";
|
||||
bootdev-order = "mmc2", "mmc1";
|
||||
|
||||
syslinux {
|
||||
compatible = "u-boot,distro-syslinux";
|
||||
};
|
||||
|
||||
efi {
|
||||
compatible = "u-boot,distro-efi";
|
||||
};
|
||||
};
|
||||
|
135
doc/usage/cmd/bootdev.rst
Normal file
135
doc/usage/cmd/bootdev.rst
Normal file
@ -0,0 +1,135 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0+:
|
||||
|
||||
bootdev command
|
||||
===============
|
||||
|
||||
Synopis
|
||||
-------
|
||||
|
||||
::
|
||||
|
||||
bootdev list [-p] - list all available bootdevs (-p to probe)\n"
|
||||
bootdev select <bm> - select a bootdev by name\n"
|
||||
bootdev info [-p] - show information about a bootdev";
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
The `bootdev` command is used to manage bootdevs. It can list available
|
||||
bootdevs, select one and obtain information about it.
|
||||
|
||||
See :doc:`../../develop/bootstd` for more information about bootdevs in general.
|
||||
|
||||
|
||||
bootdev list
|
||||
~~~~~~~~~~~~
|
||||
|
||||
This lists available bootdevs
|
||||
|
||||
Scanning with `-p` causes the bootdevs to be probed. This happens automatically
|
||||
when they are used.
|
||||
|
||||
The list looks something like this:
|
||||
|
||||
=== ====== ====== ======== =========================
|
||||
Seq Probed Status Uclass Name
|
||||
=== ====== ====== ======== =========================
|
||||
0 [ + ] OK mmc mmc@7e202000.bootdev
|
||||
1 [ ] OK mmc sdhci@7e300000.bootdev
|
||||
2 [ ] OK ethernet smsc95xx_eth.bootdev
|
||||
=== ====== ====== ======== =========================
|
||||
|
||||
|
||||
The fields are as follows:
|
||||
|
||||
Seq:
|
||||
Sequence number in the scan, used to reference the bootflow later
|
||||
|
||||
Probed:
|
||||
Shows a plus (+) if the device is probed, empty if not.
|
||||
|
||||
Status:
|
||||
Shows the status of the device. Typically this is `OK` meaning that there is
|
||||
no error. If you use -p and an error occurs when probing, then this shows
|
||||
the error number. You can look up Linux error codes to find the meaning of
|
||||
the number.
|
||||
|
||||
Uclass:
|
||||
Name of the media device's Uclass. This indicates the type of the parent
|
||||
device (e.g. MMC, Ethernet).
|
||||
|
||||
Name:
|
||||
Name of the bootdev. This is generated from the media device appended
|
||||
with `.bootdev`
|
||||
|
||||
|
||||
bootdev select
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
Use this to select a particular bootdev. You can select it by the sequence
|
||||
number or name, as shown in `bootdev list`.
|
||||
|
||||
Once a bootdev is selected, you can use `bootdev info` to look at it or
|
||||
`bootflow scan` to scan it.
|
||||
|
||||
If no bootdev name or number is provided, then any existing bootdev is
|
||||
unselected.
|
||||
|
||||
|
||||
bootdev info
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
This shows information on the current bootdev, with the format looking like
|
||||
this:
|
||||
|
||||
========= =======================
|
||||
Name mmc@7e202000.bootdev
|
||||
Sequence 0
|
||||
Status Probed
|
||||
Uclass mmc
|
||||
Bootflows 1 (1 valid)
|
||||
========= =======================
|
||||
|
||||
Most of the information is the same as `bootdev list` above. The new fields
|
||||
are:
|
||||
|
||||
Device
|
||||
Name of the bootdev
|
||||
|
||||
Status
|
||||
Shows `Probed` if the device is probed, `OK` if not. If `-p` is used and the
|
||||
device fails to probe, an error code is shown.
|
||||
|
||||
Bootflows
|
||||
Indicates the number of bootflows attached to the bootdev. This is 0
|
||||
unless you have used 'bootflow scan' on the bootflow, or on all bootflows.
|
||||
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
This example shows listing available bootdev and getting information about
|
||||
one of them::
|
||||
|
||||
U-Boot> bootdev list
|
||||
Seq Probed Status Uclass Name
|
||||
--- ------ ------ -------- ------------------
|
||||
0 [ + ] OK mmc mmc@7e202000.bootdev
|
||||
1 [ ] OK mmc sdhci@7e300000.bootdev
|
||||
2 [ ] OK ethernet smsc95xx_eth.bootdev
|
||||
--- ------ ------ -------- ------------------
|
||||
(3 devices)
|
||||
U-Boot> bootdev sel 0
|
||||
U-Boot> bootflow scan
|
||||
U-Boot> bootdev info
|
||||
Name: mmc@7e202000.bootdev
|
||||
Sequence: 0
|
||||
Status: Probed
|
||||
Uclass: mmc
|
||||
Bootflows: 1 (1 valid)
|
||||
|
||||
|
||||
Return value
|
||||
------------
|
||||
|
||||
The return value $? is always 0 (true).
|
427
doc/usage/cmd/bootflow.rst
Normal file
427
doc/usage/cmd/bootflow.rst
Normal file
@ -0,0 +1,427 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0+:
|
||||
|
||||
bootflow command
|
||||
================
|
||||
|
||||
Synopis
|
||||
-------
|
||||
|
||||
::
|
||||
|
||||
bootflow scan [-abel] [bootdev]
|
||||
bootflow list [-e]
|
||||
bootflow select [<num|name>]
|
||||
bootflow info [-d]
|
||||
bootflow boot
|
||||
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
The `bootflow` command is used to manage bootflows. It can scan bootdevs to
|
||||
locate bootflows, list them and boot them.
|
||||
|
||||
See :doc:`../../develop/bootstd` for more information.
|
||||
|
||||
|
||||
bootflow scan
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
Scans for available bootflows, optionally booting the first valid one it finds.
|
||||
This operates in two modes:
|
||||
|
||||
- If no bootdev is selected (see `bootdev select`) it scans bootflows one
|
||||
by one, extracting all the bootdevs from each
|
||||
- If a bootdev is selected, it just scans that one bootflow
|
||||
|
||||
Flags are:
|
||||
|
||||
-a
|
||||
Collect all bootflows, even those that cannot be loaded. Normally if a file
|
||||
is not where it is expected, then the bootflow fails and so is dropped
|
||||
during the scan. With this option you can see why each bootflow would be
|
||||
dropped.
|
||||
|
||||
-b
|
||||
Boot each valid bootflow as it is scanned. Typically only the first bootflow
|
||||
matters, since by then the system boots in the OS and U-Boot is no-longer
|
||||
running. `bootflow scan -b` is a quick way to boot the first available OS.
|
||||
A valid bootflow is one that made it all the way to the `loaded` state.
|
||||
|
||||
-e
|
||||
Used with -l to also show errors for each bootflow. The shows detailed error
|
||||
information for each bootflow that failed to make it to the `loaded` state.
|
||||
|
||||
-l
|
||||
List bootflows while scanning. This is helpful when you want to see what
|
||||
is happening during scanning. Use it with the `-b` flag to see which
|
||||
bootdev and bootflows are being tried.
|
||||
|
||||
The optional argument specifies a particular bootdev to scan. This can either be
|
||||
the name of a bootdev or its sequence number (both shown with `bootdev list`).
|
||||
Alternatively a convenience label can be used, like `mmc0`, which is the type of
|
||||
device and an optional sequence number. Specifically, the label is the uclass of
|
||||
the bootdev's parent followed by the sequence number of that parent. Sequence
|
||||
numbers are typically set by aliases, so if you have 'mmc0' in your devicetree
|
||||
alias section, then `mmc0` refers to the bootdev attached to that device.
|
||||
|
||||
|
||||
bootflow list
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
Lists the previously scanned bootflows. You must use `bootflow scan` before this
|
||||
to see anything.
|
||||
|
||||
If you scanned with -a and have bootflows with errors, -e can be used to show
|
||||
those errors.
|
||||
|
||||
The list looks something like this:
|
||||
|
||||
=== ====== ====== ======== ==== =============================== ================
|
||||
Seq Method State Uclass Part Name Filename
|
||||
=== ====== ====== ======== ==== =============================== ================
|
||||
0 distro ready mmc 2 mmc\@7e202000.bootdev.part_2 /boot/extlinux/extlinux.conf
|
||||
1 pxe ready ethernet 0 smsc95xx_eth.bootdev.0 rpi.pxe/extlinux/extlinux.conf
|
||||
=== ====== ====== ======== ==== =============================== ================
|
||||
|
||||
The fields are as follows:
|
||||
|
||||
Seq:
|
||||
Sequence number in the scan, used to reference the bootflow later
|
||||
|
||||
Method:
|
||||
The boot method (bootmeth) used to find the bootflow. Several methods are
|
||||
included in U-Boot.
|
||||
|
||||
State:
|
||||
Current state of the bootflow, indicating how far the bootdev got in
|
||||
obtaining a valid one. See :ref:`BootflowStates` for a list of states.
|
||||
|
||||
Uclass:
|
||||
Name of the media device's Uclass. This indicates the type of the parent
|
||||
device (e.g. MMC, Ethernet).
|
||||
|
||||
Part:
|
||||
Partition number being accesseed, numbered from 1. Normally a device will
|
||||
have a partition table with a small number of partitions. For devices
|
||||
without partition tables (e.g. network) this field is 0.
|
||||
|
||||
Name:
|
||||
Name of the bootflow. This is generated from the bootdev appended with
|
||||
the partition information
|
||||
|
||||
Filename:
|
||||
Name of the bootflow file. This indicates where the file is on the
|
||||
filesystem or network device.
|
||||
|
||||
|
||||
bootflow select
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
Use this to select a particular bootflow. You can select it by the sequence
|
||||
number or name, as shown in `bootflow list`.
|
||||
|
||||
Once a bootflow is selected, you can use `bootflow info` and `bootflow boot`.
|
||||
|
||||
If no bootflow name or number is provided, then any existing bootflow is
|
||||
unselected.
|
||||
|
||||
|
||||
bootflow info
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
This shows information on the current bootflow, with the format looking like
|
||||
this:
|
||||
|
||||
========= ===============================
|
||||
Name mmc\@7e202000.bootdev.part_2
|
||||
Device mmc\@7e202000.bootdev
|
||||
Block dev mmc\@7e202000.blk
|
||||
Type distro
|
||||
Method: syslinux
|
||||
State ready
|
||||
Partition 2
|
||||
Subdir (none)
|
||||
Filename /extlinux/extlinux.conf
|
||||
Buffer 3db7ad48
|
||||
Size 232 (562 bytes)
|
||||
Error 0
|
||||
========= ===============================
|
||||
|
||||
Most of the information is the same as `bootflow list` above. The new fields
|
||||
are:
|
||||
|
||||
Device
|
||||
Name of the bootdev
|
||||
|
||||
Block dev
|
||||
Name of the block device, if any. Network devices don't have a block device.
|
||||
|
||||
Subdir
|
||||
Subdirectory used for retrieving files. For network bootdevs this is the
|
||||
directory of the 'bootfile' parameter passed from DHCP. All file retrievals
|
||||
when booting are relative to this.
|
||||
|
||||
Buffer
|
||||
Buffer containing the bootflow file. You can use the :doc:`md` to look at
|
||||
it, or dump it with `bootflow info -d`.
|
||||
|
||||
Size
|
||||
Size of the bootflow file
|
||||
|
||||
Error
|
||||
Error number returned from scanning for the bootflow. This is 0 if the
|
||||
bootflow is in the 'loaded' state, or a negative error value on error. You
|
||||
can look up Linux error codes to find the meaning of the number.
|
||||
|
||||
Use the `-d` flag to dump out the contents of the bootfile file.
|
||||
|
||||
|
||||
bootflow boot
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
This boots the current bootflow.
|
||||
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
Here is an example of scanning for bootflows, then listing them::
|
||||
|
||||
U-Boot> bootflow scan -l
|
||||
Scanning for bootflows in all bootdevs
|
||||
Seq Type State Uclass Part Name Filename
|
||||
--- ----------- ------ -------- ---- ------------------------ ----------------
|
||||
Scanning bootdev 'mmc@7e202000.bootdev':
|
||||
0 distro ready mmc 2 mmc@7e202000.bootdev.p /extlinux/extlinux.conf
|
||||
Scanning bootdev 'sdhci@7e300000.bootdev':
|
||||
Card did not respond to voltage select! : -110
|
||||
Scanning bootdev 'smsc95xx_eth.bootdev':
|
||||
Waiting for Ethernet connection... done.
|
||||
BOOTP broadcast 1
|
||||
DHCP client bound to address 192.168.4.30 (4 ms)
|
||||
Using smsc95xx_eth device
|
||||
TFTP from server 192.168.4.1; our IP address is 192.168.4.30
|
||||
Filename 'rpi.pxe/'.
|
||||
Load address: 0x200000
|
||||
Loading: *
|
||||
TFTP error: 'Is a directory' (0)
|
||||
Starting again
|
||||
|
||||
missing environment variable: pxeuuid
|
||||
Retrieving file: rpi.pxe/pxelinux.cfg/01-b8-27-eb-a6-61-e1
|
||||
Waiting for Ethernet connection... done.
|
||||
Using smsc95xx_eth device
|
||||
TFTP from server 192.168.4.1; our IP address is 192.168.4.30
|
||||
Filename 'rpi.pxe/pxelinux.cfg/01-b8-27-eb-a6-61-e1'.
|
||||
Load address: 0x2500000
|
||||
Loading: ################################################## 566 Bytes
|
||||
45.9 KiB/s
|
||||
done
|
||||
Bytes transferred = 566 (236 hex)
|
||||
1 distro ready ethernet 0 smsc95xx_eth.bootdev.0 rpi.pxe/extlinux/extlinux.conf
|
||||
No more bootdevs
|
||||
--- ----------- ------ -------- ---- ------------------------ ----------------
|
||||
(2 bootflows, 2 valid)
|
||||
U-Boot> bootflow l
|
||||
Showing all bootflows
|
||||
Seq Type State Uclass Part Name Filename
|
||||
--- ----------- ------ -------- ---- ------------------------ ----------------
|
||||
0 distro ready mmc 2 mmc@7e202000.bootdev.p /extlinux/extlinux.conf
|
||||
1 pxe ready ethernet 0 smsc95xx_eth.bootdev.0 rpi.pxe/extlinux/extlinux.conf
|
||||
--- ----------- ------ -------- ---- ------------------------ ----------------
|
||||
(2 bootflows, 2 valid)
|
||||
|
||||
|
||||
The second one is then selected by name (we could instead use `bootflow sel 0`),
|
||||
displayed and booted::
|
||||
|
||||
U-Boot> bootflow info
|
||||
No bootflow selected
|
||||
U-Boot> bootflow sel mmc@7e202000.bootdev.part_2
|
||||
U-Boot> bootflow info
|
||||
Name: mmc@7e202000.bootdev.part_2
|
||||
Device: mmc@7e202000.bootdev
|
||||
Block dev: mmc@7e202000.blk
|
||||
Sequence: 1
|
||||
Method: distro
|
||||
State: ready
|
||||
Partition: 2
|
||||
Subdir: (none)
|
||||
Filename: extlinux/extlinux.conf
|
||||
Buffer: 3db7ae88
|
||||
Size: 232 (562 bytes)
|
||||
Error: 0
|
||||
U-Boot> bootflow boot
|
||||
** Booting bootflow 'smsc95xx_eth.bootdev.0'
|
||||
Ignoring unknown command: ui
|
||||
Ignoring malformed menu command: autoboot
|
||||
Ignoring malformed menu command: hidden
|
||||
Ignoring unknown command: totaltimeout
|
||||
1: Fedora-Workstation-armhfp-31-1.9 (5.3.7-301.fc31.armv7hl)
|
||||
Retrieving file: rpi.pxe/initramfs-5.3.7-301.fc31.armv7hl.img
|
||||
get 2700000 rpi.pxe/initramfs-5.3.7-301.fc31.armv7hl.img
|
||||
Waiting for Ethernet connection... done.
|
||||
Using smsc95xx_eth device
|
||||
TFTP from server 192.168.4.1; our IP address is 192.168.4.30
|
||||
Filename 'rpi.pxe/initramfs-5.3.7-301.fc31.armv7hl.img'.
|
||||
Load address: 0x2700000
|
||||
Loading: ###################################T ############### 57.7 MiB
|
||||
1.9 MiB/s
|
||||
done
|
||||
Bytes transferred = 60498594 (39b22a2 hex)
|
||||
Retrieving file: rpi.pxe//vmlinuz-5.3.7-301.fc31.armv7hl
|
||||
get 80000 rpi.pxe//vmlinuz-5.3.7-301.fc31.armv7hl
|
||||
Waiting for Ethernet connection... done.
|
||||
Using smsc95xx_eth device
|
||||
TFTP from server 192.168.4.1; our IP address is 192.168.4.30
|
||||
Filename 'rpi.pxe//vmlinuz-5.3.7-301.fc31.armv7hl'.
|
||||
Load address: 0x80000
|
||||
Loading: ################################################## 7.2 MiB
|
||||
2.3 MiB/s
|
||||
done
|
||||
Bytes transferred = 7508480 (729200 hex)
|
||||
append: ro root=UUID=9732b35b-4cd5-458b-9b91-80f7047e0b8a rhgb quiet LANG=en_US.UTF-8 cma=192MB cma=256MB
|
||||
Retrieving file: rpi.pxe//dtb-5.3.7-301.fc31.armv7hl/bcm2837-rpi-3-b.dtb
|
||||
get 2600000 rpi.pxe//dtb-5.3.7-301.fc31.armv7hl/bcm2837-rpi-3-b.dtb
|
||||
Waiting for Ethernet connection... done.
|
||||
Using smsc95xx_eth device
|
||||
TFTP from server 192.168.4.1; our IP address is 192.168.4.30
|
||||
Filename 'rpi.pxe//dtb-5.3.7-301.fc31.armv7hl/bcm2837-rpi-3-b.dtb'.
|
||||
Load address: 0x2600000
|
||||
Loading: ################################################## 13.8 KiB
|
||||
764.6 KiB/s
|
||||
done
|
||||
Bytes transferred = 14102 (3716 hex)
|
||||
Kernel image @ 0x080000 [ 0x000000 - 0x729200 ]
|
||||
## Flattened Device Tree blob at 02600000
|
||||
Booting using the fdt blob at 0x2600000
|
||||
Using Device Tree in place at 02600000, end 02606715
|
||||
|
||||
Starting kernel ...
|
||||
|
||||
[ OK ] Started Show Plymouth Boot Screen.
|
||||
[ OK ] Started Forward Password R…s to Plymouth Directory Watch.
|
||||
[ OK ] Reached target Local Encrypted Volumes.
|
||||
[ OK ] Reached target Paths.
|
||||
....
|
||||
|
||||
|
||||
Here we scan for bootflows and boot the first one found::
|
||||
|
||||
U-Boot> bootflow scan -bl
|
||||
Scanning for bootflows in all bootdevs
|
||||
Seq Method State Uclass Part Name Filename
|
||||
--- ----------- ------ -------- ---- ---------------------- ----------------
|
||||
Scanning bootdev 'mmc@7e202000.bootdev':
|
||||
0 distro ready mmc 2 mmc@7e202000.bootdev.p /extlinux/extlinux.conf
|
||||
** Booting bootflow 'mmc@7e202000.bootdev.part_2'
|
||||
Ignoring unknown command: ui
|
||||
Ignoring malformed menu command: autoboot
|
||||
Ignoring malformed menu command: hidden
|
||||
Ignoring unknown command: totaltimeout
|
||||
1: Fedora-KDE-armhfp-31-1.9 (5.3.7-301.fc31.armv7hl)
|
||||
Retrieving file: /initramfs-5.3.7-301.fc31.armv7hl.img
|
||||
getfile 2700000 /initramfs-5.3.7-301.fc31.armv7hl.img
|
||||
Retrieving file: /vmlinuz-5.3.7-301.fc31.armv7hl
|
||||
getfile 80000 /vmlinuz-5.3.7-301.fc31.armv7hl
|
||||
append: ro root=UUID=b8781f09-e2dd-4cb8-979b-7df5eeaaabea rhgb LANG=en_US.UTF-8 cma=192MB console=tty0 console=ttyS1,115200
|
||||
Retrieving file: /dtb-5.3.7-301.fc31.armv7hl/bcm2837-rpi-3-b.dtb
|
||||
getfile 2600000 /dtb-5.3.7-301.fc31.armv7hl/bcm2837-rpi-3-b.dtb
|
||||
Kernel image @ 0x080000 [ 0x000000 - 0x729200 ]
|
||||
## Flattened Device Tree blob at 02600000
|
||||
Booting using the fdt blob at 0x2600000
|
||||
Using Device Tree in place at 02600000, end 02606715
|
||||
|
||||
Starting kernel ...
|
||||
|
||||
[ 0.000000] Booting Linux on physical CPU 0x0
|
||||
|
||||
|
||||
Here is am example using the -e flag to see all errors::
|
||||
|
||||
U-Boot> bootflow scan -a
|
||||
Card did not respond to voltage select! : -110
|
||||
Waiting for Ethernet connection... done.
|
||||
BOOTP broadcast 1
|
||||
DHCP client bound to address 192.168.4.30 (4 ms)
|
||||
Using smsc95xx_eth device
|
||||
TFTP from server 192.168.4.1; our IP address is 192.168.4.30
|
||||
Filename 'rpi.pxe/'.
|
||||
Load address: 0x200000
|
||||
Loading: *
|
||||
TFTP error: 'Is a directory' (0)
|
||||
Starting again
|
||||
|
||||
missing environment variable: pxeuuid
|
||||
Retrieving file: rpi.pxe/pxelinux.cfg/01-b8-27-eb-a6-61-e1
|
||||
Waiting for Ethernet connection... done.
|
||||
Using smsc95xx_eth device
|
||||
TFTP from server 192.168.4.1; our IP address is 192.168.4.30
|
||||
Filename 'rpi.pxe/pxelinux.cfg/01-b8-27-eb-a6-61-e1'.
|
||||
Load address: 0x2500000
|
||||
Loading: ################################################## 566 Bytes
|
||||
49.8 KiB/s
|
||||
done
|
||||
Bytes transferred = 566 (236 hex)
|
||||
U-Boot> bootflow l -e
|
||||
Showing all bootflows
|
||||
Seq Type State Uclass Part Name Filename
|
||||
--- ----------- ------ -------- ---- --------------------- ----------------
|
||||
0 distro fs mmc 1 mmc@7e202000.bootdev.p /extlinux/extlinux.conf
|
||||
** File not found, err=-2
|
||||
1 distro ready mmc 2 mmc@7e202000.bootdev.p /extlinux/extlinux.conf
|
||||
2 distro fs mmc 3 mmc@7e202000.bootdev.p /extlinux/extlinux.conf
|
||||
** File not found, err=-1
|
||||
3 distro media mmc 0 mmc@7e202000.bootdev.p <NULL>
|
||||
** No partition found, err=-2
|
||||
4 distro media mmc 0 mmc@7e202000.bootdev.p <NULL>
|
||||
** No partition found, err=-2
|
||||
5 distro media mmc 0 mmc@7e202000.bootdev.p <NULL>
|
||||
** No partition found, err=-2
|
||||
6 distro media mmc 0 mmc@7e202000.bootdev.p <NULL>
|
||||
** No partition found, err=-2
|
||||
7 distro media mmc 0 mmc@7e202000.bootdev.p <NULL>
|
||||
** No partition found, err=-2
|
||||
8 distro media mmc 0 mmc@7e202000.bootdev.p <NULL>
|
||||
** No partition found, err=-2
|
||||
9 distro media mmc 0 mmc@7e202000.bootdev.p <NULL>
|
||||
** No partition found, err=-2
|
||||
a distro media mmc 0 mmc@7e202000.bootdev.p <NULL>
|
||||
** No partition found, err=-2
|
||||
b distro media mmc 0 mmc@7e202000.bootdev.p <NULL>
|
||||
** No partition found, err=-2
|
||||
c distro media mmc 0 mmc@7e202000.bootdev.p <NULL>
|
||||
** No partition found, err=-2
|
||||
d distro media mmc 0 mmc@7e202000.bootdev.p <NULL>
|
||||
** No partition found, err=-2
|
||||
e distro media mmc 0 mmc@7e202000.bootdev.p <NULL>
|
||||
** No partition found, err=-2
|
||||
f distro media mmc 0 mmc@7e202000.bootdev.p <NULL>
|
||||
** No partition found, err=-2
|
||||
10 distro media mmc 0 mmc@7e202000.bootdev.p <NULL>
|
||||
** No partition found, err=-2
|
||||
11 distro media mmc 0 mmc@7e202000.bootdev.p <NULL>
|
||||
** No partition found, err=-2
|
||||
12 distro media mmc 0 mmc@7e202000.bootdev.p <NULL>
|
||||
** No partition found, err=-2
|
||||
13 distro media mmc 0 mmc@7e202000.bootdev.p <NULL>
|
||||
** No partition found, err=-2
|
||||
14 distro ready ethernet 0 smsc95xx_eth.bootdev.0 rpi.pxe/extlinux/extlinux.conf
|
||||
--- ----------- ------ -------- ---- --------------------- ----------------
|
||||
(21 bootflows, 2 valid)
|
||||
U-Boot>
|
||||
|
||||
|
||||
Return value
|
||||
------------
|
||||
|
||||
On success `bootflow boot` normally boots into the Operating System and does not
|
||||
return to U-Boot. If something about the U-Boot processing fails, then the
|
||||
return value $? is 1. If the boot succeeds but for some reason the Operating
|
||||
System returns, then $? is 0, indicating success.
|
||||
|
||||
For other subcommands, the return value $? is always 0 (true).
|
||||
|
||||
|
||||
.. BootflowStates_:
|
108
doc/usage/cmd/bootmeth.rst
Normal file
108
doc/usage/cmd/bootmeth.rst
Normal file
@ -0,0 +1,108 @@
|
||||
.. SPDX-License-Identifier: GPL-2.0+:
|
||||
|
||||
bootmeth command
|
||||
================
|
||||
|
||||
Synopis
|
||||
-------
|
||||
|
||||
::
|
||||
|
||||
bootmeth list [-a] - list selected bootmeths (-a for all)
|
||||
bootmeth order "[<bm> ...]" - select the order of bootmeths\n"
|
||||
|
||||
|
||||
Description
|
||||
-----------
|
||||
|
||||
The `bootmeth` command is used to manage bootmeths. It can list them and change
|
||||
the order in which they are used.
|
||||
|
||||
See :doc:`../../develop/bootstd` for more information.
|
||||
|
||||
|
||||
.. _bootmeth_order:
|
||||
|
||||
bootmeth order
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
Selects which bootmeths to use and the order in which they are invoked. When
|
||||
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
|
||||
boomeths.
|
||||
|
||||
The argument is a quoted list of bootmeths to use, by name.
|
||||
|
||||
|
||||
bootmeth list
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
This lists the selected bootmeths, or all of them, if the `-a` flag is used.
|
||||
The format looks like this:
|
||||
|
||||
===== === ================== =================================
|
||||
Order Seq Name Description
|
||||
===== === ================== =================================
|
||||
0 0 distro Syslinux boot from a block device
|
||||
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
|
||||
===== === ================== =================================
|
||||
|
||||
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.
|
||||
|
||||
Seq:
|
||||
The sequence number of the bootmeth, i.e. the normal ordering if none is set
|
||||
|
||||
Name:
|
||||
Name of the bootmeth
|
||||
|
||||
Description:
|
||||
A friendly description for the bootmeth
|
||||
|
||||
|
||||
Example
|
||||
-------
|
||||
|
||||
This shows listing bootmeths. All are present and in the normal order::
|
||||
|
||||
=> bootmeth list
|
||||
Order Seq Name Description
|
||||
----- --- ------------------ ------------------
|
||||
0 0 distro Syslinux boot from a block device
|
||||
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
|
||||
----- --- ------------------ ------------------
|
||||
(5 bootmeths)
|
||||
|
||||
Now the order is changed, to include only two of them::
|
||||
|
||||
=> bootmeth order "sandbox distro"
|
||||
=> bootmeth list
|
||||
Order Seq Name Description
|
||||
----- --- ------------------ ------------------
|
||||
0 3 sandbox Sandbox boot for testing
|
||||
1 0 distro Syslinux boot from a block device
|
||||
----- --- ------------------ ------------------
|
||||
(2 bootmeths)
|
||||
|
||||
The -a flag shows all bootmeths so you can clearly see which ones are used and
|
||||
which are not::
|
||||
|
||||
=> bootmeth list -a
|
||||
Order Seq Name Description
|
||||
----- --- ------------------ ------------------
|
||||
1 0 distro Syslinux boot from a block device
|
||||
- 1 efi EFI boot from an .efi file
|
||||
- 2 pxe PXE boot from a network device
|
||||
0 3 sandbox Sandbox boot for testing
|
||||
- 4 efi_mgr EFI bootmgr flow
|
||||
----- --- ------------------ ------------------
|
||||
(5 bootmeths)
|
@ -23,9 +23,12 @@ Shell commands
|
||||
cmd/addrmap
|
||||
cmd/askenv
|
||||
cmd/base
|
||||
cmd/bootdev
|
||||
cmd/bootefi
|
||||
cmd/bootflow
|
||||
cmd/booti
|
||||
cmd/bootmenu
|
||||
cmd/bootmeth
|
||||
cmd/button
|
||||
cmd/cbsysinfo
|
||||
cmd/conitrace
|
||||
|
Loading…
Reference in New Issue
Block a user